main.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. //
  2. // Created by Mpho Mbotho on 2021-01-15.
  3. //
  4. #include <suil/base/env.hpp>
  5. #include <suil/http/server/pgsqlmw.hpp>
  6. #include <suil/http/server/endpoint.hpp>
  7. #include <suil/http/server/sysattrs.hpp>
  8. #include "app.scc.hpp"
  9. using suil::net::ServerConfig;
  10. using suil::net::TcpSocketConfig;
  11. using suil::http::server::PgSqlMiddleware;
  12. using suil::http::server::Endpoint;
  13. using suil::http::server::SystemAttrs;
  14. using suil::http::server::Request;
  15. using suil::http::server::Response;
  16. using suil::db::Orm;
  17. using suil::db::PgSqlConnection;
  18. using suil::bench::World;
  19. using WorldOrm = Orm<PgSqlConnection, suil::bench::World>;
  20. #define DEFAULT_POSTGRES_CONN "postgres://build:passwd@postgres:5432/dev"
  21. static inline int randnum()
  22. {
  23. // from https://stackoverflow.com/questions/1640258/need-a-fast-random-generator-for-c
  24. constexpr int MAX_VALUE = 10000;
  25. static int g_seed = 0;
  26. g_seed = (214013*g_seed+2531011);
  27. return 1 + ((g_seed>>16)&0x7FFF)%MAX_VALUE;
  28. }
  29. #if SUIL_BENCH_DEV==1
  30. void seedDatabase(PgSqlConnection& conn)
  31. {
  32. constexpr int MAX_RECORDS = 10000;
  33. WorldOrm orm("world", conn);
  34. if (orm.cifne(false)) {
  35. for (int i = 0; i < MAX_RECORDS; i++) {
  36. orm.insert(World{.id = i+1, .randomNumber = randnum()});
  37. }
  38. }
  39. }
  40. #endif
  41. int main(int argc, char *argv[])
  42. {
  43. suil::setup(opt(verbose, 1));
  44. auto config = ServerConfig{
  45. .socketConfig = TcpSocketConfig {
  46. .bindAddr = {.name = "0.0.0.0", .port = 8080}
  47. }
  48. };
  49. Endpoint<SystemAttrs, PgSqlMiddleware> ep{"/",
  50. opt(serverConfig, std::move(config)),
  51. opt(connectionTimeout, 60_sec)
  52. };
  53. ep.middleware<PgSqlMiddleware>().setup(
  54. suil::env("POSTGRES_CONN", DEFAULT_POSTGRES_CONN),
  55. opt(ASYNC, true), // connections are async
  56. opt(TIMEOUT, 10_sec), // timeout on db transactions
  57. opt(EXPIRES, 30_sec) // connections are cached for 30 seconds
  58. );
  59. #if SUIL_BENCH_DEV == 1
  60. {
  61. scoped(conn, ep.middleware<PgSqlMiddleware>().conn(false));
  62. seedDatabase(conn);
  63. }
  64. #endif
  65. Route(ep, "/plaintext")
  66. ("GET"_method)
  67. .attrs(opt(ReplyType, "text/plain"))
  68. ([]() {
  69. return suil::String{"Hello, World!"};
  70. });
  71. Route(ep, "/json")
  72. ("GET"_method)
  73. .attrs(opt(ReplyType, "application/json"))
  74. ([]() {
  75. return suil::bench::Object{.message = "Hello, World!"};
  76. });
  77. Route(ep, "/db")
  78. ("GET"_method)
  79. .attrs(opt(ReplyType, "application/json"))
  80. ([&ep]() {
  81. scoped(conn, ep.middleware<PgSqlMiddleware>().conn());
  82. WorldOrm orm("World", conn);
  83. suil::bench::World obj{};
  84. orm.find(opt(id, randnum()), obj);
  85. return obj;
  86. });
  87. Route(ep, "/query")
  88. ("GET"_method)
  89. .attrs(opt(ReplyType, "application/json"))
  90. ([&ep](const Request& req, Response& resp) {
  91. auto queries = req.query().get<int>("queries") or int(1);
  92. int count = std::max(1, std::min(*queries, 500));
  93. scoped(conn, ep.context<PgSqlMiddleware>(req).conn());
  94. std::vector<World> objects(count);
  95. WorldOrm orm("World", conn);
  96. for (auto& obj: objects) {
  97. orm.find(opt(id, randnum()), obj);
  98. }
  99. resp.append(objects);
  100. resp.end();
  101. });
  102. Route(ep, "/update")
  103. ("GET"_method)
  104. .attrs(opt(ReplyType, "application/json"))
  105. ([&ep](const Request& req, Response& resp) {
  106. auto queries = req.query().get<int>("queries") or int(1);
  107. int count = std::max(1, std::min(*queries, 500));
  108. scoped(conn, ep.context<PgSqlMiddleware>(req).conn());
  109. std::vector<World> objects(count);
  110. WorldOrm orm("World", conn);
  111. for (auto& obj: objects) {
  112. orm.find(opt(id, randnum()), obj);
  113. obj.randomNumber = randnum();
  114. }
  115. {
  116. suil::db::PgSqlTransaction txn(conn.get());
  117. txn.begin();
  118. // Sorting transactions to avoid postgres deadlock
  119. std::sort(objects.begin(), objects.end(),
  120. [](const World& a, const World& b) { return a.id < b.id; });
  121. for (auto& obj: objects) {
  122. orm.update(obj);
  123. }
  124. }
  125. resp.append(objects);
  126. resp.end();
  127. });
  128. return ep.start();
  129. }