mongodb.d 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. import vibe.core.core;
  2. import vibe.db.mongo.mongo;
  3. import vibe.http.router;
  4. import vibe.http.server;
  5. import vibe.web.web;
  6. import mir.random : unpredictableSeedOf;
  7. import mir.random.variable : UniformVariable;
  8. import mir.random.engine.xorshift : Xorshift;
  9. import std.conv : ConvException, to;
  10. import std.array;
  11. enum worldSize = 10000;
  12. void main()
  13. {
  14. runWorkerTaskDist(&runServer);
  15. runApplication();
  16. }
  17. void runServer()
  18. {
  19. auto router = new URLRouter;
  20. router.registerWebInterface(new WebInterface);
  21. router.rebuild();
  22. auto settings = new HTTPServerSettings;
  23. settings.options |= HTTPServerOption.reusePort;
  24. settings.port = 8080;
  25. listenHTTP(settings, router);
  26. }
  27. class WebInterface {
  28. private {
  29. MongoCollection _worldCollection;
  30. MongoCollection _fortuneCollection;
  31. UniformVariable!uint _uniformVariable;
  32. Xorshift _gen;
  33. }
  34. this()
  35. {
  36. import std.process : environment;
  37. auto db = connectMongoDB("tfb-database");
  38. _worldCollection = db.getCollection("hello_world.world");
  39. _fortuneCollection = db.getCollection("hello_world.fortune");
  40. _gen = Xorshift(unpredictableSeedOf!uint);
  41. _uniformVariable = UniformVariable!uint(1, worldSize);
  42. }
  43. // GET /
  44. void get()
  45. {
  46. render!"index.dt";
  47. }
  48. // GET /json
  49. void getJson(HTTPServerResponse res)
  50. {
  51. // NOTE: the status and content type parameters are optional, but we need
  52. // to specify them, because the default content type is "application/json; charset=UTF8"
  53. res.writeJsonBody(Message("Hello, World!"), HTTPStatus.ok, "application/json");
  54. }
  55. // GET /db
  56. void getDB(HTTPServerResponse res)
  57. {
  58. struct Q { int _id; }
  59. auto query = Q(_uniformVariable(_gen));
  60. auto w = WorldResponse(_worldCollection.findOne!World(query));
  61. res.writeJsonBody(w, HTTPStatus.ok, "application/json");
  62. }
  63. // GET /queries?queries=...
  64. void getQueries(HTTPServerResponse res, string queries)
  65. {
  66. import std.algorithm : min, max;
  67. // Convert the "queries" parameter to int and ignore any conversion errors
  68. // Note that you'd usually declare queries as int instead. However, the
  69. // test required to gracefully handle errors here.
  70. int count = 1;
  71. try count = min(max(queries.to!int, 1), 500);
  72. catch (ConvException) {}
  73. // assemble the response array
  74. scope data = new WorldResponse[count];
  75. foreach (ref w; data) {
  76. static struct Q { int _id; }
  77. auto query = Q(_uniformVariable(_gen));
  78. w = WorldResponse(_worldCollection.findOne!World(query));
  79. }
  80. // write response as JSON
  81. res.writeJsonBody(data, HTTPStatus.ok, "application/json");
  82. }
  83. // GET /fortunes
  84. void getFortunes()
  85. {
  86. import std.algorithm : map, sort;
  87. FortuneResponse[] data;
  88. data = _fortuneCollection.find!Fortune().map!(f => FortuneResponse(f)).array;
  89. data ~= FortuneResponse(Fortune(0, "Additional fortune added at request time."));
  90. data.sort!((a, b) => a.message < b.message);
  91. render!("fortunes.dt", data);
  92. }
  93. // GET /updates?queries=...
  94. void getUpdates(HTTPServerResponse res, string queries)
  95. {
  96. import std.algorithm : min, max;
  97. int count = 1;
  98. try count = min(max(queries.to!int, 1), 500);
  99. catch (ConvException e) {}
  100. scope data = new WorldResponse[count];
  101. foreach (ref w; data) {
  102. static struct Q { int _id; }
  103. auto query = Q(_uniformVariable(_gen));
  104. w = WorldResponse(_worldCollection.findOne!World(query));
  105. // update random number
  106. w.randomNumber = _uniformVariable(_gen);
  107. // persist to DB
  108. static struct US {
  109. double randomNumber;
  110. }
  111. static struct U {
  112. @name("$set") US set;
  113. }
  114. _worldCollection.update(query, U(US(w.randomNumber)));
  115. }
  116. // write response as JSON
  117. res.writeJsonBody(data, HTTPStatus.ok, "application/json");
  118. }
  119. // GET /plaintext
  120. void getPlaintext(HTTPServerResponse res)
  121. {
  122. res.writeBody("Hello, World!", HTTPStatus.ok, "text/plain");
  123. }
  124. }
  125. struct Message {
  126. string message;
  127. }
  128. struct World {
  129. double _id;
  130. double randomNumber;
  131. }
  132. struct Fortune {
  133. double _id;
  134. string message;
  135. }
  136. struct WorldResponse {
  137. this(World w) { this.id = cast(int)w._id; this.randomNumber = cast(int)w.randomNumber; }
  138. int id;
  139. int randomNumber;
  140. }
  141. struct FortuneResponse {
  142. this(Fortune f) { this.id = cast(int)f._id; this.message = f.message; }
  143. int id;
  144. string message;
  145. }