Lightcord/modules/discord_rpc/RPCWebSocket.js

176 lines
5.4 KiB
JavaScript
Raw Normal View History

2020-05-16 23:24:51 +02:00
"use strict";
2020-09-05 12:14:21 +02:00
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; }
2020-05-16 23:24:51 +02:00
2020-09-05 12:14:21 +02:00
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; }
2020-05-16 23:24:51 +02:00
2020-09-05 12:14:21 +02:00
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; }
2020-05-16 23:24:51 +02:00
// Provides native APIs for RPCWebSocket transport.
//
// Because we're passing through some native APIs, e.g. net, we recast its API
// to something more browser-safe, so don't assume the APIs are 1:1 or behave
// exactly like the native APIs.
2020-09-05 12:14:21 +02:00
var _require = require('./safeEmitter'),
createSafeEmitter = _require.createSafeEmitter;
2020-05-16 23:24:51 +02:00
var http = require('http');
var ws = require('ws');
2020-09-05 12:14:21 +02:00
var origInstanceMap = new Map();
var nextInstanceId = 1; // converts Node.js Buffer to ArrayBuffer
2020-05-16 23:24:51 +02:00
function toArrayBuffer(buffer) {
return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
}
function recastWSSocket(socket, req) {
2020-09-05 12:14:21 +02:00
var emitter = createSafeEmitter();
socket.on('error', function (err) {
return emitter.emit('error', err);
});
socket.on('close', function (code, message) {
return emitter.emit('close', code, message);
});
socket.on('message', function (data) {
if (data instanceof Buffer) {
data = toArrayBuffer(data);
}
2020-05-16 23:24:51 +02:00
2020-09-05 12:14:21 +02:00
emitter.emit('message', data);
});
return _objectSpread({
upgradeReq: function upgradeReq() {
return {
2020-05-16 23:24:51 +02:00
url: req.url,
headers: {
origin: req.headers.origin
}
};
2020-09-05 12:14:21 +02:00
},
send: function send(data) {
var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
2020-05-16 23:24:51 +02:00
2020-09-05 12:14:21 +02:00
if (opts.binary) {
data = Buffer.from(data);
2020-05-16 23:24:51 +02:00
}
2020-09-05 12:14:21 +02:00
try {
socket.send(data, opts);
} catch (e) {
// ws shouldn't be throwing when CLOSED or CLOSING
// currently being addressed in https://github.com/websockets/ws/pull/1532
if (!e.message.match(/CLOS(ED|ING)/)) {
throw e;
2020-05-16 23:24:51 +02:00
}
}
2020-09-05 12:14:21 +02:00
},
close: function close(code, message) {
return socket.close(code, message);
}
}, emitter);
2020-05-16 23:24:51 +02:00
}
2020-09-05 12:14:21 +02:00
function createWrappedWSServer(opts) {
// opts.server that comes in is our remapped server, so we
// get the original
if (opts.instanceId) {
opts.server = origInstanceMap.get(opts.instanceId);
2020-05-16 23:24:51 +02:00
}
2020-09-05 12:14:21 +02:00
var wss = new ws.Server(opts);
var emitter = createSafeEmitter();
wss.on('connection', function (socket, req) {
return emitter.emit('connection', recastWSSocket(socket, req));
});
return _objectSpread({}, emitter);
}
2020-05-16 23:24:51 +02:00
function recastHTTPReq(req) {
2020-09-05 12:14:21 +02:00
var attached = false;
var emitter = createSafeEmitter();
return {
url: function url() {
return req.url;
},
method: function method() {
return req.method;
},
headers: function headers() {
return req.headers;
},
on: function on(name, listener) {
// We need to attach listeners for data only on data event, which sets the
// request to flowing mode.
if (name === 'data' && !attached) {
req.on('error', function (err) {
return emitter.emit('error', err);
});
req.on('end', function () {
return emitter.emit('end');
});
req.on('data', function (data) {
// force cast the data to a string
// this is because we only deal with string data on http requests so far
emitter.emit('data', '' + data);
});
attached = true;
2020-05-16 23:24:51 +02:00
}
2020-09-05 12:14:21 +02:00
emitter.on(name, listener);
2020-05-16 23:24:51 +02:00
}
2020-09-05 12:14:21 +02:00
};
2020-05-16 23:24:51 +02:00
}
function recastHTTPRes(res) {
2020-09-05 12:14:21 +02:00
return {
setHeader: function setHeader(header, value) {
return res.setHeader(header, value);
},
writeHead: function writeHead(status, headers) {
return res.writeHead(status, headers);
},
end: function end(body) {
return res.end(body);
2020-05-16 23:24:51 +02:00
}
2020-09-05 12:14:21 +02:00
};
2020-05-16 23:24:51 +02:00
}
function createWrappedHTTPServer() {
var server = http.createServer();
2020-09-05 12:14:21 +02:00
var emitter = createSafeEmitter();
server.on('error', function (err) {
return emitter.emit('error', err);
});
server.on('request', function (req, res) {
return emitter.emit('request', recastHTTPReq(req), recastHTTPRes(res));
});
var recast = _objectSpread({
address: function address() {
return server.address();
},
listening: function listening() {
return server.listening;
},
listen: function listen(port, host, callback) {
return server.listen(port, host, callback);
},
instanceId: nextInstanceId
}, emitter);
origInstanceMap.set(nextInstanceId, server);
nextInstanceId += 1;
2020-05-16 23:24:51 +02:00
return recast;
}
module.exports = {
2020-09-05 12:14:21 +02:00
ws: {
Server: createWrappedWSServer
},
http: {
createServer: createWrappedHTTPServer
}
2020-05-16 23:24:51 +02:00
};