RPCWebSocket.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. "use strict";
  2. function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
  3. function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
  4. function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
  5. // Provides native APIs for RPCWebSocket transport.
  6. //
  7. // Because we're passing through some native APIs, e.g. net, we recast its API
  8. // to something more browser-safe, so don't assume the APIs are 1:1 or behave
  9. // exactly like the native APIs.
  10. var _require = require('./safeEmitter'),
  11. createSafeEmitter = _require.createSafeEmitter;
  12. var http = require('http');
  13. var ws = require('ws');
  14. var origInstanceMap = new Map();
  15. var nextInstanceId = 1; // converts Node.js Buffer to ArrayBuffer
  16. function toArrayBuffer(buffer) {
  17. return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
  18. }
  19. function recastWSSocket(socket, req) {
  20. var emitter = createSafeEmitter();
  21. socket.on('error', function (err) {
  22. return emitter.emit('error', err);
  23. });
  24. socket.on('close', function (code, message) {
  25. return emitter.emit('close', code, message);
  26. });
  27. socket.on('message', function (data) {
  28. if (data instanceof Buffer) {
  29. data = toArrayBuffer(data);
  30. }
  31. emitter.emit('message', data);
  32. });
  33. return _objectSpread({
  34. upgradeReq: function upgradeReq() {
  35. return {
  36. url: req.url,
  37. headers: {
  38. origin: req.headers.origin
  39. }
  40. };
  41. },
  42. send: function send(data) {
  43. var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  44. if (opts.binary) {
  45. data = Buffer.from(data);
  46. }
  47. try {
  48. socket.send(data, opts);
  49. } catch (e) {
  50. // ws shouldn't be throwing when CLOSED or CLOSING
  51. // currently being addressed in https://github.com/websockets/ws/pull/1532
  52. if (!e.message.match(/CLOS(ED|ING)/)) {
  53. throw e;
  54. }
  55. }
  56. },
  57. close: function close(code, message) {
  58. return socket.close(code, message);
  59. }
  60. }, emitter);
  61. }
  62. function createWrappedWSServer(opts) {
  63. // opts.server that comes in is our remapped server, so we
  64. // get the original
  65. if (opts.instanceId) {
  66. opts.server = origInstanceMap.get(opts.instanceId);
  67. }
  68. var wss = new ws.Server(opts);
  69. var emitter = createSafeEmitter();
  70. wss.on('connection', function (socket, req) {
  71. return emitter.emit('connection', recastWSSocket(socket, req));
  72. });
  73. return _objectSpread({}, emitter);
  74. }
  75. function recastHTTPReq(req) {
  76. var attached = false;
  77. var emitter = createSafeEmitter();
  78. return {
  79. url: function url() {
  80. return req.url;
  81. },
  82. method: function method() {
  83. return req.method;
  84. },
  85. headers: function headers() {
  86. return req.headers;
  87. },
  88. on: function on(name, listener) {
  89. // We need to attach listeners for data only on data event, which sets the
  90. // request to flowing mode.
  91. if (name === 'data' && !attached) {
  92. req.on('error', function (err) {
  93. return emitter.emit('error', err);
  94. });
  95. req.on('end', function () {
  96. return emitter.emit('end');
  97. });
  98. req.on('data', function (data) {
  99. // force cast the data to a string
  100. // this is because we only deal with string data on http requests so far
  101. emitter.emit('data', '' + data);
  102. });
  103. attached = true;
  104. }
  105. emitter.on(name, listener);
  106. }
  107. };
  108. }
  109. function recastHTTPRes(res) {
  110. return {
  111. setHeader: function setHeader(header, value) {
  112. return res.setHeader(header, value);
  113. },
  114. writeHead: function writeHead(status, headers) {
  115. return res.writeHead(status, headers);
  116. },
  117. end: function end(body) {
  118. return res.end(body);
  119. }
  120. };
  121. }
  122. function createWrappedHTTPServer() {
  123. var server = http.createServer();
  124. var emitter = createSafeEmitter();
  125. server.on('error', function (err) {
  126. return emitter.emit('error', err);
  127. });
  128. server.on('request', function (req, res) {
  129. return emitter.emit('request', recastHTTPReq(req), recastHTTPRes(res));
  130. });
  131. var recast = _objectSpread({
  132. address: function address() {
  133. return server.address();
  134. },
  135. listening: function listening() {
  136. return server.listening;
  137. },
  138. listen: function listen(port, host, callback) {
  139. return server.listen(port, host, callback);
  140. },
  141. instanceId: nextInstanceId
  142. }, emitter);
  143. origInstanceMap.set(nextInstanceId, server);
  144. nextInstanceId += 1;
  145. return recast;
  146. }
  147. module.exports = {
  148. ws: {
  149. Server: createWrappedWSServer
  150. },
  151. http: {
  152. createServer: createWrappedHTTPServer
  153. }
  154. };