JAVASCRIPT   71

api.js

Guest on 21st August 2021 08:49:52 PM

  1. var Stream      = require('stream').Stream,
  2.     util        = require('util'),
  3.     driver      = require('websocket-driver'),
  4.     EventTarget = require('./api/event_target'),
  5.     Event       = require('./api/event');
  6.  
  7. var API = function(options) {
  8.   options = options || {};
  9.   driver.validateOptions(options, ['headers', 'extensions', 'maxLength', 'ping', 'proxy', 'tls', 'ca']);
  10.  
  11.   this.readable = this.writable = true;
  12.  
  13.   var headers = options.headers;
  14.   if (headers) {
  15.     for (var name in headers) this._driver.setHeader(name, headers[name]);
  16.   }
  17.  
  18.   var extensions = options.extensions;
  19.   if (extensions) {
  20.     [].concat(extensions).forEach(this._driver.addExtension, this._driver);
  21.   }
  22.  
  23.   this._ping          = options.ping;
  24.   this._pingId        = 0;
  25.   this.readyState     = API.CONNECTING;
  26.   this.bufferedAmount = 0;
  27.   this.protocol       = '';
  28.   this.url            = this._driver.url;
  29.   this.version        = this._driver.version;
  30.  
  31.   var self = this;
  32.  
  33.   this._driver.on('open',    function(e) { self._open() });
  34.   this._driver.on('message', function(e) { self._receiveMessage(e.data) });
  35.   this._driver.on('close',   function(e) { self._beginClose(e.reason, e.code) });
  36.  
  37.   this._driver.on('error', function(error) {
  38.     self._emitError(error.message);
  39.   });
  40.   this.on('error', function() {});
  41.  
  42.   this._driver.messages.on('drain', function() {
  43.     self.emit('drain');
  44.   });
  45.  
  46.   if (this._ping)
  47.     this._pingTimer = setInterval(function() {
  48.       self._pingId += 1;
  49.       self.ping(self._pingId.toString());
  50.     }, this._ping * 1000);
  51.  
  52.   this._configureStream();
  53.  
  54.   if (!this._proxy) {
  55.     this._stream.pipe(this._driver.io);
  56.     this._driver.io.pipe(this._stream);
  57.   }
  58. };
  59. util.inherits(API, Stream);
  60.  
  61. API.CONNECTING = 0;
  62. API.OPEN       = 1;
  63. API.CLOSING    = 2;
  64. API.CLOSED     = 3;
  65.  
  66. API.CLOSE_TIMEOUT = 30000;
  67.  
  68. var instance = {
  69.   write: function(data) {
  70.     return this.send(data);
  71.   },
  72.  
  73.   end: function(data) {
  74.     if (data !== undefined) this.send(data);
  75.     this.close();
  76.   },
  77.  
  78.   pause: function() {
  79.     return this._driver.messages.pause();
  80.   },
  81.  
  82.   resume: function() {
  83.     return this._driver.messages.resume();
  84.   },
  85.  
  86.   send: function(data) {
  87.     if (this.readyState > API.OPEN) return false;
  88.     if (!(data instanceof Buffer)) data = String(data);
  89.     return this._driver.messages.write(data);
  90.   },
  91.  
  92.   ping: function(message, callback) {
  93.     if (this.readyState > API.OPEN) return false;
  94.     return this._driver.ping(message, callback);
  95.   },
  96.  
  97.   close: function(code, reason) {
  98.     if (code === undefined) code = 1000;
  99.     if (reason === undefined) reason = '';
  100.  
  101.     if (code !== 1000 && (code < 3000 || code > 4999))
  102.       throw new Error("Failed to execute 'close' on WebSocket: " +
  103.                       "The code must be either 1000, or between 3000 and 4999. " +
  104.                       code + " is neither.");
  105.  
  106.     if (this.readyState !== API.CLOSED) this.readyState = API.CLOSING;
  107.     this._driver.close(reason, code);
  108.  
  109.     var self = this;
  110.  
  111.     this._closeTimer = setTimeout(function() {
  112.       self._beginClose('', 1006);
  113.     }, API.CLOSE_TIMEOUT);
  114.   },
  115.  
  116.   _configureStream: function() {
  117.     var self = this;
  118.  
  119.     this._stream.setTimeout(0);
  120.     this._stream.setNoDelay(true);
  121.  
  122.     ['close', 'end'].forEach(function(event) {
  123.       this._stream.on(event, function() { self._finalizeClose() });
  124.     }, this);
  125.  
  126.     this._stream.on('error', function(error) {
  127.       self._emitError('Network error: ' + self.url + ': ' + error.message);
  128.       self._finalizeClose();
  129.     });
  130.   },
  131.  
  132.  _open: function() {
  133.     if (this.readyState !== API.CONNECTING) return;
  134.  
  135.     this.readyState = API.OPEN;
  136.     this.protocol = this._driver.protocol || '';
  137.  
  138.     var event = new Event('open');
  139.     event.initEvent('open', false, false);
  140.     this.dispatchEvent(event);
  141.   },
  142.  
  143.   _receiveMessage: function(data) {
  144.     if (this.readyState > API.OPEN) return false;
  145.  
  146.     if (this.readable) this.emit('data', data);
  147.  
  148.     var event = new Event('message', {data: data});
  149.     event.initEvent('message', false, false);
  150.     this.dispatchEvent(event);
  151.   },
  152.  
  153.   _emitError: function(message) {
  154.     if (this.readyState >= API.CLOSING) return;
  155.  
  156.     var event = new Event('error', {message: message});
  157.     event.initEvent('error', false, false);
  158.     this.dispatchEvent(event);
  159.   },
  160.  
  161.   _beginClose: function(reason, code) {
  162.     if (this.readyState === API.CLOSED) return;
  163.     this.readyState = API.CLOSING;
  164.     this._closeParams = [reason, code];
  165.  
  166.     if (this._stream) {
  167.       this._stream.destroy();
  168.       if (!this._stream.readable) this._finalizeClose();
  169.     }
  170.   },
  171.  
  172.   _finalizeClose: function() {
  173.     if (this.readyState === API.CLOSED) return;
  174.     this.readyState = API.CLOSED;
  175.  
  176.     if (this._closeTimer) clearTimeout(this._closeTimer);
  177.     if (this._pingTimer) clearInterval(this._pingTimer);
  178.     if (this._stream) this._stream.end();
  179.  
  180.     if (this.readable) this.emit('end');
  181.     this.readable = this.writable = false;
  182.  
  183.     var reason = this._closeParams ? this._closeParams[0] : '',
  184.         code   = this._closeParams ? this._closeParams[1] : 1006;
  185.  
  186.     var event = new Event('close', {code: code, reason: reason});
  187.     event.initEvent('close', false, false);
  188.     this.dispatchEvent(event);
  189.   }
  190. };
  191.  
  192. for (var method in instance) API.prototype[method] = instance[method];
  193. for (var key in EventTarget) API.prototype[key] = EventTarget[key];
  194.  
  195. module.exports = API;

Raw Paste


Login or Register to edit or fork this paste. It's free.