/server/socket.io/lib/socket.io/client.js

https://github.com/mzupan/varnishspy · JavaScript · 193 lines · 169 code · 24 blank · 0 comment · 42 complexity · ecf3b0e0b1a57702ecfcc651781ff2e5 MD5 · raw file

  1. var urlparse = require('url').parse
  2. , OutgoingMessage = require('http').OutgoingMessage
  3. , Stream = require('net').Stream
  4. , options = require('./utils').options
  5. , encode = require('./utils').encode
  6. , decode = require('./utils').decode
  7. , merge = require('./utils').merge;
  8. var Client = module.exports = function(listener, req, res, options, head){
  9. process.EventEmitter.call(this);
  10. this.listener = listener;
  11. this.options(merge({
  12. timeout: 8000,
  13. heartbeatInterval: 10000,
  14. closeTimeout: 0
  15. }, this.getOptions ? this.getOptions() : {}), options);
  16. this.connections = 0;
  17. this._open = false;
  18. this._heartbeats = 0;
  19. this.connected = false;
  20. this.upgradeHead = head;
  21. this._onConnect(req, res);
  22. };
  23. require('sys').inherits(Client, process.EventEmitter);
  24. Client.prototype.send = function(message){
  25. if (!this._open || !(this.connection.readyState === 'open' || this.connection.readyState === 'writeOnly')){
  26. return this._queue(message);
  27. }
  28. this._write(encode(message));
  29. return this;
  30. };
  31. Client.prototype.broadcast = function(message){
  32. if (!('sessionId' in this)) return this;
  33. this.listener.broadcast(message, this.sessionId);
  34. return this;
  35. };
  36. Client.prototype._onMessage = function(data){
  37. var messages = decode(data);
  38. if (messages === false) return this.listener.options.log('Bad message received from client ' + this.sessionId);
  39. for (var i = 0, l = messages.length, frame; i < l; i++){
  40. frame = messages[i].substr(0, 3);
  41. switch (frame){
  42. case '~h~':
  43. return this._onHeartbeat(messages[i].substr(3));
  44. case '~j~':
  45. messages[i] = JSON.parse(messages[i].substr(3));
  46. break;
  47. }
  48. this.emit('message', messages[i]);
  49. this.listener._onClientMessage(messages[i], this);
  50. }
  51. };
  52. Client.prototype._onConnect = function(req, res){
  53. var self = this;
  54. this.request = req;
  55. this.response = res;
  56. this.connection = req.connection;
  57. this.connection.addListener('end', function(){
  58. if (self.connection){
  59. self.connection.end();
  60. self.connection.destroy();
  61. }
  62. self._onClose();
  63. });
  64. if (req){
  65. req.addListener('error', function(err){
  66. req.end && req.end() || req.destroy && req.destroy();
  67. });
  68. if (res) res.addListener('error', function(err){
  69. res.end && res.end() || res.destroy && res.destroy();
  70. });
  71. req.connection.addListener('error', function(err){
  72. req.connection.end && req.connection.end() || req.connection.destroy && req.connection.destroy();
  73. });
  74. if (this._disconnectTimeout) clearTimeout(this._disconnectTimeout);
  75. }
  76. };
  77. Client.prototype._payload = function(){
  78. var payload = [];
  79. this.connections++;
  80. this.connected = true;
  81. this._open = true;
  82. if (!this.handshaked){
  83. this._generateSessionId();
  84. payload.push(this.sessionId);
  85. this.handshaked = true;
  86. }
  87. payload = payload.concat(this._writeQueue || []);
  88. this._writeQueue = [];
  89. if (payload.length) this._write(encode(payload));
  90. if (this.connections === 1) this.listener._onClientConnect(this);
  91. if (this.options.timeout) this._heartbeat();
  92. };
  93. Client.prototype._heartbeat = function(){
  94. var self = this;
  95. this._heartbeatInterval = setTimeout(function(){
  96. self.send('~h~' + ++self._heartbeats);
  97. self._heartbeatTimeout = setTimeout(function(){
  98. self._onClose();
  99. }, self.options.timeout);
  100. }, self.options.heartbeatInterval);
  101. };
  102. Client.prototype._onHeartbeat = function(h){
  103. if (h == this._heartbeats){
  104. clearTimeout(this._heartbeatTimeout);
  105. this._heartbeat();
  106. }
  107. };
  108. Client.prototype._onClose = function(skipDisconnect){
  109. if (this._open){
  110. var self = this;
  111. if ('_heartbeatInterval' in this) clearTimeout(this._heartbeatInterval);
  112. if ('_heartbeatTimeout' in this) clearTimeout(this._heartbeatTimeout);
  113. this._open = false;
  114. if (skipDisconnect !== false){
  115. if (this.handshaked)
  116. this._disconnectTimeout = setTimeout(function(){
  117. self._onDisconnect();
  118. }, this.options.closeTimeout);
  119. else
  120. this._onDisconnect();
  121. }
  122. }
  123. };
  124. Client.prototype._onDisconnect = function(){
  125. if (this._open) this._onClose(true);
  126. if (this._disconnectTimeout) clearTimeout(this._disconnectTimeout);
  127. if (this.connected){
  128. this._writeQueue = [];
  129. this._open = false;
  130. this.connected = false;
  131. this.request = null;
  132. this.response = null;
  133. if (this.connection){
  134. this.connection.end();
  135. this.connection.destroy();
  136. this.connection = null;
  137. }
  138. if (this.handshaked){
  139. this.emit('disconnect');
  140. this.listener._onClientDisconnect(this);
  141. }
  142. }
  143. };
  144. Client.prototype._queue = function(message){
  145. this._writeQueue = this._writeQueue || [];
  146. this._writeQueue.push(message);
  147. return this;
  148. };
  149. Client.prototype._generateSessionId = function(){
  150. if (this.sessionId) return this.listener.options.log('This client already has a session id');
  151. this.sessionId = Math.random().toString().substr(2);
  152. return this;
  153. };
  154. Client.prototype._verifyOrigin = function(origin){
  155. var origins = this.listener.options.origins;
  156. if (origins.indexOf('*:*') !== -1) {
  157. return true;
  158. }
  159. if (origin) {
  160. try {
  161. var parts = urlparse(origin);
  162. return origins.indexOf(parts.host + ':' + parts.port) !== -1 ||
  163. origins.indexOf(parts.host + ':*') !== -1 ||
  164. origins.indexOf('*:' + parts.port) !== -1;
  165. } catch (ex) {}
  166. }
  167. return false;
  168. };
  169. for (var i in options) Client.prototype[i] = options[i];