server.js

  1. const url = require('url');
  2. const http = require('http');
  3. const body = require('body');
  4. const npmlog = require('npmlog');
  5. const dummy = require('dummy-object');
  6. /**
  7. * Takes HTTP requests
  8. *
  9. * Example (in the main script):
  10. * ```
  11. * const server = new Server(somebot, someotherbot);
  12. * server.listen(80, 'localhost');
  13. * ```
  14. */
  15. class Server {
  16. /**
  17. * @param {Function[]} [bots] Bots whose handle method will be called
  18. * on incoming requests
  19. * @param {object} [options]
  20. * @param {object} [options.log] npmlog-like logger; pass null to disable
  21. */
  22. constructor(bots = [], { log } = {}) {
  23. this.bots = bots;
  24. if (bots) {
  25. for (const bot of bots) {
  26. bot.setServer(this);
  27. }
  28. }
  29. if (log === null) {
  30. this.log = dummy;
  31. } else {
  32. this.log = log || npmlog;
  33. }
  34. // Creating HTTP server. Data is handled by this.request
  35. this.server = http.createServer((req, res) => this.request(req, res));
  36. }
  37. /**
  38. * Adds bots whose handle functions are called on HTTP requests
  39. *
  40. * @param {Bot} bot
  41. */
  42. addBot(bot) {
  43. this.bots.push(bot);
  44. bot.server = this;
  45. }
  46. /**
  47. * Executes the HTTP Server's listen method
  48. *
  49. * @param {number} port Port to listen on
  50. * @param {string} host Hostname for the server
  51. *
  52. * @see https://nodejs.org/api/http.html
  53. */
  54. listen(...args) {
  55. this.log.http('bot', `Server on app ${process.pid} started`);
  56. this.server.listen(...args);
  57. }
  58. /**
  59. * Receives HTTP requests from the API
  60. *
  61. * @param {IncomingMessage} req Request
  62. * @param {ServerResponse} res Response
  63. */
  64. request(req, res) {
  65. if (req.method === 'POST') {
  66. const parts = url.parse(req.url, true);
  67. const route = parts.pathname;
  68. const passedUrl = parts.query && parts.query.url ? parts.query.url : '';
  69. this.log.http('server', `Request on route '${route}'`);
  70. body(req, (err, parsed) => {
  71. if (err) {
  72. this.log.error('server', 'Body parser error', err);
  73. return;
  74. }
  75. for (const bot of this.bots) {
  76. bot.handle(parsed, passedUrl, route, res);
  77. }
  78. });
  79. } else {
  80. res.writeHead(400, { 'Content-Type': 'text/plain' });
  81. res.end('Nothing to do here!');
  82. }
  83. }
  84. }
  85. module.exports = Server;