switcher.js 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. var EventEmitter = require('events').EventEmitter;
  2. var util = require('util');
  3. var WSProcessor = require('./wsprocessor');
  4. var TCPProcessor = require('./tcpprocessor');
  5. var logger = require('pomelo-logger').getLogger('pomelo', __filename);
  6. var HTTP_METHODS = [
  7. 'GET', 'POST', 'DELETE', 'PUT', 'HEAD'
  8. ];
  9. var ST_STARTED = 1;
  10. var ST_CLOSED = 2;
  11. var DEFAULT_TIMEOUT = 90;
  12. /**
  13. * Switcher for tcp and websocket protocol
  14. *
  15. * @param {Object} server tcp server instance from node.js net module
  16. */
  17. var Switcher = function(server, opts) {
  18. EventEmitter.call(this);
  19. this.server = server;
  20. this.wsprocessor = new WSProcessor();
  21. this.tcpprocessor = new TCPProcessor(opts.closeMethod);
  22. this.id = 1;
  23. this.timeout = (opts.timeout || DEFAULT_TIMEOUT) * 1000;
  24. this.setNoDelay = opts.setNoDelay;
  25. if (!opts.ssl) {
  26. this.server.on('connection', this.newSocket.bind(this));
  27. } else {
  28. this.server.on('secureConnection', this.newSocket.bind(this));
  29. this.server.on('clientError', function(e) {
  30. logger.warn('an ssl error occured before handshake established: ', e);
  31. });
  32. }
  33. this.wsprocessor.on('connection', this.emit.bind(this, 'connection'));
  34. this.tcpprocessor.on('connection', this.emit.bind(this, 'connection'));
  35. this.state = ST_STARTED;
  36. };
  37. util.inherits(Switcher, EventEmitter);
  38. module.exports = Switcher;
  39. Switcher.prototype.newSocket = function(socket) {
  40. if(this.state !== ST_STARTED) {
  41. return;
  42. }
  43. socket.setTimeout(this.timeout, function() {
  44. logger.warn('connection is timeout without communication, the remote ip is %s && port is %s',
  45. socket.remoteAddress, socket.remotePort);
  46. socket.destroy();
  47. });
  48. var self = this;
  49. socket.once('data', function(data) {
  50. // FIXME: handle incomplete HTTP method
  51. if(isHttp(data)) {
  52. processHttp(self, self.wsprocessor, socket, data);
  53. } else {
  54. if(!!self.setNoDelay) {
  55. socket.setNoDelay(true);
  56. }
  57. processTcp(self, self.tcpprocessor, socket, data);
  58. }
  59. });
  60. };
  61. Switcher.prototype.close = function() {
  62. if(this.state !== ST_STARTED) {
  63. return;
  64. }
  65. this.state = ST_CLOSED;
  66. this.wsprocessor.close();
  67. this.tcpprocessor.close();
  68. };
  69. var isHttp = function(data) {
  70. var head = data.toString('utf8', 0, 4);
  71. for(var i=0, l=HTTP_METHODS.length; i<l; i++) {
  72. if(head.indexOf(HTTP_METHODS[i]) === 0) {
  73. return true;
  74. }
  75. }
  76. return false;
  77. };
  78. var processHttp = function(switcher, processor, socket, data) {
  79. processor.add(socket, data);
  80. };
  81. var processTcp = function(switcher, processor, socket, data) {
  82. processor.add(socket, data);
  83. };