server.dart 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. import "dart:core";
  2. import "dart:io";
  3. import 'dart:async' show Future;
  4. import 'dart:math' show Random;
  5. import "package:redstone/server.dart" as app;
  6. import "package:redstone_mapper/mapper.dart";
  7. import "package:redstone_mapper/plugin.dart";
  8. import "package:redstone_mapper_mongo/manager.dart";
  9. import "package:redstone_mapper_pg/manager.dart";
  10. import "package:postgresql/postgresql.dart" as pg;
  11. import "package:di/di.dart";
  12. import "package:args/args.dart";
  13. import 'package:yaml/yaml.dart' as yaml;
  14. import 'package:mustache/mustache.dart' as mustache;
  15. const _WORLD_TABLE_SIZE = 10000;
  16. final _RANDOM = new Random();
  17. class Fortune implements Comparable<Fortune> {
  18. @Field()
  19. int id;
  20. @Field()
  21. String message;
  22. Fortune([this.id, this.message]);
  23. compareTo(Fortune other) => message.compareTo(other.message);
  24. }
  25. class World {
  26. @Field()
  27. int id;
  28. @Field(model: "randomnumber")
  29. int randomNumber;
  30. }
  31. class MongoFortune implements Comparable<Fortune> {
  32. @Field(model: "_id")
  33. int id;
  34. @Field()
  35. String message;
  36. MongoFortune([this.id, this.message]);
  37. compareTo(Fortune other) => message.compareTo(other.message);
  38. }
  39. class MongoWorld {
  40. @Field(model: "_id")
  41. int id;
  42. @Field()
  43. int randomNumber;
  44. }
  45. ///Handle PostgreSql connections
  46. @app.Interceptor(r'/pg/.+')
  47. pgSqlManager(PostgreSqlManager pgSql) {
  48. pgSql.getConnection().then((conn) {
  49. app.request.attributes["dbConn"] = conn;
  50. app.chain.next(() {
  51. pgSql.closeConnection(conn, error: app.chain.error);
  52. });
  53. });
  54. }
  55. ///Handle MongoDb connections
  56. @app.Interceptor(r'/mongo/.+')
  57. mongoDbManager(MongoDbManager mongoDb) {
  58. mongoDb.getConnection().then((conn) {
  59. app.request.attributes["dbConn"] = conn;
  60. app.chain.next(() {
  61. mongoDb.closeConnection(conn, error: app.chain.error);
  62. });
  63. });
  64. }
  65. ///JSON test
  66. @app.Route("/json")
  67. getJson() => {"message": "Hello, World!"};
  68. ///PlainText test
  69. @app.Route("/plaintext")
  70. getPlainText() => "Hello, World!";
  71. ///PostgreSql tests
  72. @app.Group("/pg")
  73. @Encode()
  74. class PgTests {
  75. static const worldQuery = 'SELECT id, randomnumber FROM world WHERE id = @id;';
  76. static const worldUpdt = 'UPDATE world SET randomnumber = @randomnumber WHERE id = @id;';
  77. static const fortuneQuery = 'SELECT id, message FROM fortune;';
  78. PostgreSql get pgSql => app.request.attributes["dbConn"];
  79. @app.Route("/db")
  80. Future<World> queryTest() {
  81. var params = { 'id': _RANDOM.nextInt(_WORLD_TABLE_SIZE) + 1 };
  82. return pgSql.query(worldQuery, World, params).then((list) => list[0]);
  83. }
  84. @app.Route("/queries")
  85. Future<List<World>> queriesTest() {
  86. var queries = _parseQueriesParam(app.request.queryParams.queries);
  87. return Future.wait(new List.generate(queries, (_) => queryTest()));
  88. }
  89. @app.Route("/updates")
  90. Future<List<World>> updateTest() {
  91. var queries = _parseQueriesParam(app.request.queryParams.queries);
  92. return Future.wait(new List.generate(queries, (_) => queryTest().then((world) {
  93. world.randomNumber = _RANDOM.nextInt(_WORLD_TABLE_SIZE) + 1;
  94. return pgSql.execute(worldUpdt, world).then((_) => world);
  95. })));
  96. }
  97. @app.Route("/fortunes", responseType: "text/html")
  98. Future<String> fortunesTest(@app.Inject() mustache.Template template) {
  99. return pgSql.query(fortuneQuery, Fortune).then((values) {
  100. values
  101. ..add(new Fortune(0, 'Additional fortune added at request time.'))
  102. ..sort();
  103. return template.renderString({
  104. "fortunes": encode(values)
  105. });
  106. });
  107. }
  108. }
  109. ///MongoDb tests
  110. @app.Group("/mongo")
  111. @Encode()
  112. class MongoTests {
  113. static const worldCollection = "World";
  114. static const fortuneCollection = "Fortune";
  115. MongoDb get mongoDb => app.request.attributes["dbConn"];
  116. @app.Route("/db")
  117. Future<MongoWorld> queryTest() {
  118. return mongoDb.findOne(worldCollection, MongoWorld, {
  119. "_id": _RANDOM.nextInt(_WORLD_TABLE_SIZE) + 1
  120. });
  121. }
  122. @app.Route("/queries")
  123. Future<List<MongoWorld>> queriesTest() {
  124. var queries = _parseQueriesParam(app.request.queryParams.queries);
  125. return Future.wait(new List.generate(queries, (_) => queryTest()));
  126. }
  127. @app.Route("/updates")
  128. Future<List<MongoWorld>> updateTest() {
  129. var queries = _parseQueriesParam(app.request.queryParams.queries);
  130. return Future.wait(new List.generate(queries, (_) => queryTest().then((world) {
  131. world.randomNumber = _RANDOM.nextInt(_WORLD_TABLE_SIZE) + 1;
  132. return mongoDb.update(worldCollection, { "_id": world.id }, world)
  133. .then((_) => world);
  134. })));
  135. }
  136. @app.Route("/fortunes", responseType: "text/html")
  137. Future<String> fortunesTest(@app.Inject() mustache.Template template) {
  138. return mongoDb.find(fortuneCollection, MongoFortune).then((values) {
  139. values
  140. ..add(new MongoFortune(0, 'Additional fortune added at request time.'))
  141. ..sort();
  142. return template.renderString({
  143. "fortunes": encode(values)
  144. });
  145. });
  146. }
  147. }
  148. main(List<String> args) {
  149. var parser = new ArgParser();
  150. parser.addOption('address', abbr: 'a', defaultsTo: '0.0.0.0');
  151. parser.addOption('port', abbr: 'p', defaultsTo: '8080');
  152. parser.addOption('dbconnections', abbr: 'd', defaultsTo: '256');
  153. var arguments = parser.parse(args);
  154. var dbConnections = int.parse(arguments["dbconnections"]);
  155. MongoDbManager mongoDbManager;
  156. PostgreSqlManager pgSqlManager;
  157. mustache.Template fortunesTemplate;
  158. Future.wait([
  159. //load PostgreSql configuration
  160. new File("postgresql.yaml").readAsString().then((config){
  161. pgSqlManager = new PostgreSqlManager(
  162. new pg.Settings.fromMap(yaml.loadYaml(config)).toUri(),
  163. min: dbConnections,
  164. max: dbConnections);
  165. }),
  166. //load MongoDb configuration
  167. new File("mongodb.yaml").readAsString().then((config) {
  168. var mongoConfig = yaml.loadYaml(config);
  169. mongoDbManager = new MongoDbManager(
  170. "mongodb://${mongoConfig["host"]}/${mongoConfig["database"]}",
  171. poolSize: dbConnections);
  172. }),
  173. //load fortunes mustache template
  174. new File('fortunes.mustache').readAsString().then((template) {
  175. fortunesTemplate = mustache.parse(template);
  176. })
  177. ]).then((_) {
  178. //app.setupConsoleLog();
  179. //install module for dependency injection
  180. app.addModule(new Module()
  181. ..bind(MongoDbManager, toValue: mongoDbManager)
  182. ..bind(PostgreSqlManager, toValue: pgSqlManager)
  183. ..bind(mustache.Template, toValue: fortunesTemplate));
  184. //initialize mapper plugin
  185. app.addPlugin(getMapperPlugin());
  186. //start the server
  187. app.start(address: arguments["address"], port: int.parse(arguments["port"]));
  188. });
  189. }
  190. _parseQueriesParam(param) {
  191. return param.isEmpty ? 1 : int.parse(param, radix: 10, onError: (_) => 1).clamp(1, 500);
  192. }