hybridsocket.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. var util = require('util');
  2. var EventEmitter = require('events').EventEmitter;
  3. var handler = require('./common/handler');
  4. var protocol = require('pomelo-protocol');
  5. var logger = require('pomelo-logger').getLogger('pomelo', __filename);
  6. var Package = protocol.Package;
  7. var ST_INITED = 0;
  8. var ST_WAIT_ACK = 1;
  9. var ST_WORKING = 2;
  10. var ST_CLOSED = 3;
  11. /**
  12. * Socket class that wraps socket and websocket to provide unified interface for up level.
  13. */
  14. var Socket = function(id, socket) {
  15. EventEmitter.call(this);
  16. this.id = id;
  17. this.socket = socket;
  18. if(!socket._socket) {
  19. this.remoteAddress = {
  20. ip: socket.address().address,
  21. port: socket.address().port
  22. };
  23. } else {
  24. this.remoteAddress = {
  25. ip: socket._socket.remoteAddress,
  26. port: socket._socket.remotePort
  27. };
  28. }
  29. var self = this;
  30. socket.once('close', this.emit.bind(this, 'disconnect'));
  31. socket.on('error', this.emit.bind(this, 'error'));
  32. socket.on('message', function(msg) {
  33. if(msg) {
  34. msg = Package.decode(msg);
  35. handler(self, msg);
  36. }
  37. });
  38. this.state = ST_INITED;
  39. // TODO: any other events?
  40. };
  41. util.inherits(Socket, EventEmitter);
  42. module.exports = Socket;
  43. /**
  44. * Send raw byte data.
  45. *
  46. * @api private
  47. */
  48. Socket.prototype.sendRaw = function(msg) {
  49. if(this.state !== ST_WORKING) {
  50. return;
  51. }
  52. var self = this;
  53. this.socket.send(msg, {binary: true}, function(err) {
  54. if(!!err) {
  55. logger.error('websocket send binary data failed: %j', err.stack);
  56. return;
  57. }
  58. });
  59. };
  60. /**
  61. * Send byte data package to client.
  62. *
  63. * @param {Buffer} msg byte data
  64. */
  65. Socket.prototype.send = function(msg) {
  66. if(msg instanceof String) {
  67. msg = new Buffer(msg);
  68. } else if(!(msg instanceof Buffer)) {
  69. msg = new Buffer(JSON.stringify(msg));
  70. }
  71. this.sendRaw(Package.encode(Package.TYPE_DATA, msg));
  72. };
  73. /**
  74. * Send byte data packages to client in batch.
  75. *
  76. * @param {Buffer} msgs byte data
  77. */
  78. Socket.prototype.sendBatch = function(msgs) {
  79. var rs = [];
  80. for(var i=0; i<msgs.length; i++) {
  81. var src = Package.encode(Package.TYPE_DATA, msgs[i]);
  82. rs.push(src);
  83. }
  84. this.sendRaw(Buffer.concat(rs));
  85. };
  86. /**
  87. * Send message to client no matter whether handshake.
  88. *
  89. * @api private
  90. */
  91. Socket.prototype.sendForce = function(msg) {
  92. if(this.state === ST_CLOSED) {
  93. return;
  94. }
  95. this.socket.send(msg, {binary: true});
  96. };
  97. /**
  98. * Response handshake request
  99. *
  100. * @api private
  101. */
  102. Socket.prototype.handshakeResponse = function(resp) {
  103. if(this.state !== ST_INITED) {
  104. return;
  105. }
  106. this.socket.send(resp, {binary: true});
  107. this.state = ST_WAIT_ACK;
  108. };
  109. /**
  110. * Close the connection.
  111. *
  112. * @api private
  113. */
  114. Socket.prototype.disconnect = function() {
  115. if(this.state === ST_CLOSED) {
  116. return;
  117. }
  118. this.state = ST_CLOSED;
  119. this.socket.emit('close');
  120. this.socket.close();
  121. };