123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- //
- // Created by Mpho Mbotho on 2021-01-15.
- //
- #include <suil/base/env.hpp>
- #include <suil/http/server/pgsqlmw.hpp>
- #include <suil/http/server/endpoint.hpp>
- #include <suil/http/server/sysattrs.hpp>
- #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<PgSqlConnection, suil::bench::World>;
- #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<SystemAttrs, PgSqlMiddleware> ep{"/",
- opt(serverConfig, std::move(config)),
- opt(connectionTimeout, 60_sec)
- };
- ep.middleware<PgSqlMiddleware>().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<PgSqlMiddleware>().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<PgSqlMiddleware>().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<int>("queries") or int(1);
- int count = std::max(1, std::min(*queries, 500));
- scoped(conn, ep.context<PgSqlMiddleware>(req).conn());
- std::vector<World> 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<int>("queries") or int(1);
- int count = std::max(1, std::min(*queries, 500));
- scoped(conn, ep.context<PgSqlMiddleware>(req).conn());
- std::vector<World> 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();
- }
|