@nyirusu/nact-websocket-server 0.0.0-stage → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +108 -0
- package/dist/index.js.map +1 -0
- package/package.json +12 -4
- package/README.md +0 -3
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import http from 'node:http';
|
|
2
|
+
import type { ServerHandle, ServerProvider, Channel } from '@nyirusu/nasdk/NACT';
|
|
3
|
+
export type WebSocketServerOptions = {
|
|
4
|
+
host: string;
|
|
5
|
+
port: number;
|
|
6
|
+
path?: string;
|
|
7
|
+
noServer?: false;
|
|
8
|
+
} | {
|
|
9
|
+
noServer: true;
|
|
10
|
+
path?: never;
|
|
11
|
+
host?: never;
|
|
12
|
+
port?: never;
|
|
13
|
+
};
|
|
14
|
+
export interface WebSocketServerTransportSpec {
|
|
15
|
+
type: 'websocket';
|
|
16
|
+
provider: WebSocketServerOptions;
|
|
17
|
+
nact?: {
|
|
18
|
+
chunkSize?: number;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export default class WebSocketServerProvider implements ServerProvider<'websocket', WebSocketServerOptions> {
|
|
22
|
+
readonly type = "websocket";
|
|
23
|
+
readonly role = "server";
|
|
24
|
+
readonly defaultChunkSize: number;
|
|
25
|
+
private websocket?;
|
|
26
|
+
private detach;
|
|
27
|
+
attach(server: http.Server, options?: {
|
|
28
|
+
path?: string;
|
|
29
|
+
}): () => void;
|
|
30
|
+
private attachServer;
|
|
31
|
+
listen(options: WebSocketServerOptions, accept: (channel: Channel) => void): Promise<ServerHandle>;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAA;AAG5B,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAEhF,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,KAAK,CAAA;CACjB,GAAG;IACF,QAAQ,EAAE,IAAI,CAAA;IACd,IAAI,CAAC,EAAE,KAAK,CAAA;IACZ,IAAI,CAAC,EAAE,KAAK,CAAA;IACZ,IAAI,CAAC,EAAE,KAAK,CAAA;CACb,CAAA;AACD,MAAM,WAAW,4BAA4B;IAC3C,IAAI,EAAE,WAAW,CAAA;IACjB,QAAQ,EAAE,sBAAsB,CAAA;IAChC,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAC9B;AAgCD,MAAM,CAAC,OAAO,OAAO,uBACnB,YAAW,cAAc,CAAC,WAAW,EAAE,sBAAsB,CAAC;IAC9D,QAAQ,CAAC,IAAI,eAAc;IAC3B,QAAQ,CAAC,IAAI,YAAW;IACxB,QAAQ,CAAC,gBAAgB,SAAoB;IAC7C,OAAO,CAAC,SAAS,CAAC,CAAiB;IACnC,OAAO,CAAC,MAAM,CAAwB;IAEtC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,GAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,MAAM,IAAI;IAKxE,OAAO,CAAC,YAAY;IAed,MAAM,CAAC,OAAO,EAAE,sBAAsB,EAAE,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC;CAiCzG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import http from 'node:http';
|
|
2
|
+
import { WebSocketServer } from 'ws';
|
|
3
|
+
class WebSocketChannel {
|
|
4
|
+
socket;
|
|
5
|
+
errorHandlers = new Set();
|
|
6
|
+
constructor(socket) {
|
|
7
|
+
this.socket = socket;
|
|
8
|
+
}
|
|
9
|
+
send(frame) {
|
|
10
|
+
if (this.socket.readyState !== 1)
|
|
11
|
+
throw Object.assign(new Error('transport-closed'), { code: 'transport-closed' });
|
|
12
|
+
const size = frame.reduce((sum, part) => sum + part.byteLength, 0);
|
|
13
|
+
const bytes = new Uint8Array(size);
|
|
14
|
+
let offset = 0;
|
|
15
|
+
for (const part of frame) {
|
|
16
|
+
bytes.set(part, offset);
|
|
17
|
+
offset += part.byteLength;
|
|
18
|
+
}
|
|
19
|
+
this.socket.send(bytes);
|
|
20
|
+
}
|
|
21
|
+
close() { this.socket.close(); }
|
|
22
|
+
terminate() { this.socket.terminate(); }
|
|
23
|
+
onReceive(handler) {
|
|
24
|
+
const listener = (data, isBinary) => {
|
|
25
|
+
if (!isBinary)
|
|
26
|
+
return this.fail('non-binary-frame');
|
|
27
|
+
handler([data]); // default binaryType 'nodebuffer': one Buffer per message
|
|
28
|
+
};
|
|
29
|
+
this.socket.on('message', listener);
|
|
30
|
+
return () => this.socket.off('message', listener);
|
|
31
|
+
}
|
|
32
|
+
onClose(handler) { this.socket.on('close', handler); return () => this.socket.off('close', handler); }
|
|
33
|
+
onError(handler) {
|
|
34
|
+
this.errorHandlers.add(handler);
|
|
35
|
+
this.socket.on('error', handler);
|
|
36
|
+
return () => { this.errorHandlers.delete(handler); this.socket.off('error', handler); };
|
|
37
|
+
}
|
|
38
|
+
fail(reason) { for (const handler of this.errorHandlers)
|
|
39
|
+
handler(reason); }
|
|
40
|
+
}
|
|
41
|
+
export default class WebSocketServerProvider {
|
|
42
|
+
type = 'websocket';
|
|
43
|
+
role = 'server';
|
|
44
|
+
defaultChunkSize = 100 * 1024 * 1024;
|
|
45
|
+
websocket;
|
|
46
|
+
detach = new Set();
|
|
47
|
+
attach(server, options = {}) {
|
|
48
|
+
if (!this.websocket)
|
|
49
|
+
throw Object.assign(new Error('provider-not-listening'), { code: 'provider-not-listening' });
|
|
50
|
+
return this.attachServer(server, options);
|
|
51
|
+
}
|
|
52
|
+
attachServer(server, options, owned = false) {
|
|
53
|
+
const websocket = this.websocket;
|
|
54
|
+
const upgrade = (request, socket, head) => {
|
|
55
|
+
if (options.path && new URL(request.url ?? '/', 'http://localhost').pathname !== options.path) {
|
|
56
|
+
if (owned)
|
|
57
|
+
socket.end('HTTP/1.1 404 Not Found\r\nConnection: close\r\n\r\n');
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
websocket.handleUpgrade(request, socket, head, ws => websocket.emit('connection', ws, request));
|
|
61
|
+
};
|
|
62
|
+
const detach = () => { server.off('upgrade', upgrade); this.detach.delete(detach); };
|
|
63
|
+
server.on('upgrade', upgrade);
|
|
64
|
+
this.detach.add(detach);
|
|
65
|
+
return detach;
|
|
66
|
+
}
|
|
67
|
+
async listen(options, accept) {
|
|
68
|
+
if (this.websocket)
|
|
69
|
+
throw Object.assign(new Error('provider-already-listening'), { code: 'provider-already-listening' });
|
|
70
|
+
const server = options.noServer ? undefined : http.createServer();
|
|
71
|
+
const websocket = new WebSocketServer({ noServer: true, perMessageDeflate: false });
|
|
72
|
+
this.websocket = websocket;
|
|
73
|
+
websocket.on('connection', socket => accept(new WebSocketChannel(socket)));
|
|
74
|
+
if (server && !options.noServer) {
|
|
75
|
+
this.attachServer(server, options, true);
|
|
76
|
+
try {
|
|
77
|
+
await new Promise((resolve, reject) => {
|
|
78
|
+
server.once('error', reject);
|
|
79
|
+
server.listen(options.port, options.host, () => { server.off('error', reject); resolve(); });
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
catch (reason) {
|
|
83
|
+
for (const detach of this.detach)
|
|
84
|
+
detach();
|
|
85
|
+
this.websocket = undefined;
|
|
86
|
+
websocket.close();
|
|
87
|
+
throw reason;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
let closing;
|
|
91
|
+
return {
|
|
92
|
+
close: () => closing ??= new Promise(resolve => {
|
|
93
|
+
this.websocket = undefined;
|
|
94
|
+
for (const detach of this.detach)
|
|
95
|
+
detach();
|
|
96
|
+
for (const socket of websocket.clients)
|
|
97
|
+
socket.terminate();
|
|
98
|
+
websocket.close(() => {
|
|
99
|
+
if (server)
|
|
100
|
+
server.close(() => resolve());
|
|
101
|
+
else
|
|
102
|
+
resolve();
|
|
103
|
+
});
|
|
104
|
+
}),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nyirusu/nact-websocket-server",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.0.4",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"files": ["dist/index.js", "dist/index.js.map", "dist/index.d.ts", "dist/index.d.ts.map"],
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": { ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" } },
|
|
9
|
+
"scripts": { "build": "tsc -p tsconfig.build.json", "typecheck": "tsc -p tsconfig.json --noEmit", "test": "npm run test:simple", "test:simple": "node --import tsx --test test/simple.test.mjs", "test:full": "node --import tsx --test test/full.test.mjs", "test:edge": "node --import tsx --test test/edge.test.mjs" },
|
|
10
|
+
"dependencies": { "ws": "8.21.3" },
|
|
11
|
+
"devDependencies": { "@types/ws": "8.18.1" },
|
|
12
|
+
"peerDependencies": { "@nyirusu/nasdk": ">=1.0.4" },
|
|
13
|
+
"peerDependenciesMeta": { "@nyirusu/nasdk": { "optional": true } }
|
|
14
|
+
}
|
package/README.md
DELETED