// // Created by Mpho Mbotho on 2021-01-15. // #include #include #include #include #include "app.scc.hpp" using suil::net::ServerConfig; using suil::net::TcpSocketConfig; using suil::http::server::PgSqlMiddleware; using suil::http::server::Endpoint; using suil::http::server::SystemAttrs; using suil::http::server::Request; using suil::http::server::Response; using suil::db::Orm; using suil::db::PgSqlConnection; using suil::bench::World; using WorldOrm = Orm; #define DEFAULT_POSTGRES_CONN "postgres://build:passwd@postgres:5432/dev" static inline int randnum() { // from https://stackoverflow.com/questions/1640258/need-a-fast-random-generator-for-c constexpr int MAX_VALUE = 10000; static int g_seed = 0; g_seed = (214013*g_seed+2531011); return 1 + ((g_seed>>16)&0x7FFF)%MAX_VALUE; } #if SUIL_BENCH_DEV==1 void seedDatabase(PgSqlConnection& conn) { constexpr int MAX_RECORDS = 10000; WorldOrm orm("world", conn); if (orm.cifne(false)) { for (int i = 0; i < MAX_RECORDS; i++) { orm.insert(World{.id = i+1, .randomNumber = randnum()}); } } } #endif int main(int argc, char *argv[]) { suil::setup(opt(verbose, 1)); auto config = ServerConfig{ .socketConfig = TcpSocketConfig { .bindAddr = {.name = "0.0.0.0", .port = 8080} } }; Endpoint ep{"/", opt(serverConfig, std::move(config)), opt(connectionTimeout, 60_sec) }; ep.middleware().setup( suil::env("POSTGRES_CONN", DEFAULT_POSTGRES_CONN), opt(ASYNC, true), // connections are async opt(TIMEOUT, 10_sec), // timeout on db transactions opt(EXPIRES, 30_sec) // connections are cached for 30 seconds ); #if SUIL_BENCH_DEV == 1 { scoped(conn, ep.middleware().conn(false)); seedDatabase(conn); } #endif Route(ep, "/plaintext") ("GET"_method) .attrs(opt(ReplyType, "text/plain")) ([]() { return suil::String{"Hello, World!"}; }); Route(ep, "/json") ("GET"_method) .attrs(opt(ReplyType, "application/json")) ([]() { return suil::bench::Object{.message = "Hello, World!"}; }); Route(ep, "/db") ("GET"_method) .attrs(opt(ReplyType, "application/json")) ([&ep]() { scoped(conn, ep.middleware().conn()); WorldOrm orm("World", conn); suil::bench::World obj{}; orm.find(opt(id, randnum()), obj); return obj; }); Route(ep, "/query") ("GET"_method) .attrs(opt(ReplyType, "application/json")) ([&ep](const Request& req, Response& resp) { auto queries = req.query().get("queries") or int(1); int count = std::max(1, std::min(*queries, 500)); scoped(conn, ep.context(req).conn()); std::vector objects(count); WorldOrm orm("World", conn); for (auto& obj: objects) { orm.find(opt(id, randnum()), obj); } resp.append(objects); resp.end(); }); Route(ep, "/update") ("GET"_method) .attrs(opt(ReplyType, "application/json")) ([&ep](const Request& req, Response& resp) { auto queries = req.query().get("queries") or int(1); int count = std::max(1, std::min(*queries, 500)); scoped(conn, ep.context(req).conn()); std::vector objects(count); WorldOrm orm("World", conn); for (auto& obj: objects) { orm.find(opt(id, randnum()), obj); obj.randomNumber = randnum(); } { suil::db::PgSqlTransaction txn(conn.get()); txn.begin(); // Sorting transactions to avoid postgres deadlock std::sort(objects.begin(), objects.end(), [](const World& a, const World& b) { return a.id < b.id; }); for (auto& obj: objects) { orm.update(obj); } } resp.append(objects); resp.end(); }); return ep.start(); }