164 lines
4.4 KiB
JavaScript
164 lines
4.4 KiB
JavaScript
import { M as Message, P as Peer, t as toBufferLike } from '../shared/crossws.DfCzGthR.mjs';
|
|
import { A as AdapterHookable, a as adapterUtils } from '../shared/crossws.D9ehKjSh.mjs';
|
|
import { W as WSError } from '../shared/crossws.By9qWDAI.mjs';
|
|
import { _ as _WebSocketServer } from '../shared/crossws.CipVM6lf.mjs';
|
|
import 'uncrypto';
|
|
import 'stream';
|
|
import 'events';
|
|
import 'http';
|
|
import 'crypto';
|
|
import 'buffer';
|
|
import 'zlib';
|
|
import 'https';
|
|
import 'net';
|
|
import 'tls';
|
|
import 'url';
|
|
|
|
const nodeAdapter = (options = {}) => {
|
|
const hooks = new AdapterHookable(options);
|
|
const peers = /* @__PURE__ */ new Set();
|
|
const wss = options.wss || new _WebSocketServer({
|
|
noServer: true,
|
|
...options.serverOptions
|
|
});
|
|
wss.on("connection", (ws, nodeReq) => {
|
|
const request = new NodeReqProxy(nodeReq);
|
|
const peer = new NodePeer({ ws, request, peers, nodeReq });
|
|
peers.add(peer);
|
|
hooks.callHook("open", peer);
|
|
ws.on("message", (data) => {
|
|
if (Array.isArray(data)) {
|
|
data = Buffer.concat(data);
|
|
}
|
|
hooks.callHook("message", peer, new Message(data, peer));
|
|
});
|
|
ws.on("error", (error) => {
|
|
peers.delete(peer);
|
|
hooks.callHook("error", peer, new WSError(error));
|
|
});
|
|
ws.on("close", (code, reason) => {
|
|
peers.delete(peer);
|
|
hooks.callHook("close", peer, {
|
|
code,
|
|
reason: reason?.toString()
|
|
});
|
|
});
|
|
});
|
|
wss.on("headers", (outgoingHeaders, req) => {
|
|
const upgradeHeaders = req._upgradeHeaders;
|
|
if (upgradeHeaders) {
|
|
for (const [key, value] of new Headers(upgradeHeaders)) {
|
|
outgoingHeaders.push(`${key}: ${value}`);
|
|
}
|
|
}
|
|
});
|
|
return {
|
|
...adapterUtils(peers),
|
|
handleUpgrade: async (nodeReq, socket, head) => {
|
|
const request = new NodeReqProxy(nodeReq);
|
|
const { upgradeHeaders, endResponse, context } = await hooks.upgrade(request);
|
|
if (endResponse) {
|
|
return sendResponse(socket, endResponse);
|
|
}
|
|
nodeReq._request = request;
|
|
nodeReq._upgradeHeaders = upgradeHeaders;
|
|
nodeReq._context = context;
|
|
wss.handleUpgrade(nodeReq, socket, head, (ws) => {
|
|
wss.emit("connection", ws, nodeReq);
|
|
});
|
|
},
|
|
closeAll: (code, data, force) => {
|
|
for (const client of wss.clients) {
|
|
if (force) {
|
|
client.terminate();
|
|
} else {
|
|
client.close(code, data);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
};
|
|
class NodePeer extends Peer {
|
|
get remoteAddress() {
|
|
return this._internal.nodeReq.socket?.remoteAddress;
|
|
}
|
|
get context() {
|
|
return this._internal.nodeReq._context;
|
|
}
|
|
send(data, options) {
|
|
const dataBuff = toBufferLike(data);
|
|
const isBinary = typeof dataBuff !== "string";
|
|
this._internal.ws.send(dataBuff, {
|
|
compress: options?.compress,
|
|
binary: isBinary,
|
|
...options
|
|
});
|
|
return 0;
|
|
}
|
|
publish(topic, data, options) {
|
|
const dataBuff = toBufferLike(data);
|
|
const isBinary = typeof data !== "string";
|
|
const sendOptions = {
|
|
compress: options?.compress,
|
|
binary: isBinary,
|
|
...options
|
|
};
|
|
for (const peer of this._internal.peers) {
|
|
if (peer !== this && peer._topics.has(topic)) {
|
|
peer._internal.ws.send(dataBuff, sendOptions);
|
|
}
|
|
}
|
|
}
|
|
close(code, data) {
|
|
this._internal.ws.close(code, data);
|
|
}
|
|
terminate() {
|
|
this._internal.ws.terminate();
|
|
}
|
|
}
|
|
class NodeReqProxy {
|
|
_req;
|
|
_headers;
|
|
_url;
|
|
constructor(req) {
|
|
this._req = req;
|
|
}
|
|
get url() {
|
|
if (!this._url) {
|
|
const req = this._req;
|
|
const host = req.headers["host"] || "localhost";
|
|
const isSecure = req.socket?.encrypted ?? req.headers["x-forwarded-proto"] === "https";
|
|
this._url = `${isSecure ? "https" : "http"}://${host}${req.url}`;
|
|
}
|
|
return this._url;
|
|
}
|
|
get headers() {
|
|
if (!this._headers) {
|
|
this._headers = new Headers(this._req.headers);
|
|
}
|
|
return this._headers;
|
|
}
|
|
}
|
|
async function sendResponse(socket, res) {
|
|
const head = [
|
|
`HTTP/1.1 ${res.status || 200} ${res.statusText || ""}`,
|
|
...[...res.headers.entries()].map(
|
|
([key, value]) => `${encodeURIComponent(key)}: ${encodeURIComponent(value)}`
|
|
)
|
|
];
|
|
socket.write(head.join("\r\n") + "\r\n\r\n");
|
|
if (res.body) {
|
|
for await (const chunk of res.body) {
|
|
socket.write(chunk);
|
|
}
|
|
}
|
|
return new Promise((resolve) => {
|
|
socket.end(() => {
|
|
socket.destroy();
|
|
resolve();
|
|
});
|
|
});
|
|
}
|
|
|
|
export { nodeAdapter as default };
|