@voltrix/websocket 0.3.0
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/LICENSE +21 -0
- package/README.md +10 -0
- package/dist/adapters/index.d.ts +1 -0
- package/dist/adapters/index.js +2 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/uws-adapter.d.ts +87 -0
- package/dist/adapters/uws-adapter.js +295 -0
- package/dist/adapters/uws-adapter.js.map +1 -0
- package/dist/decorators/index.d.ts +43 -0
- package/dist/decorators/index.js +90 -0
- package/dist/decorators/index.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/pipeline/index.d.ts +19 -0
- package/dist/pipeline/index.js +45 -0
- package/dist/pipeline/index.js.map +1 -0
- package/dist/pipeline/parser.d.ts +21 -0
- package/dist/pipeline/parser.js +46 -0
- package/dist/pipeline/parser.js.map +1 -0
- package/dist/processors/websocket.processor.d.ts +12 -0
- package/dist/processors/websocket.processor.js +108 -0
- package/dist/processors/websocket.processor.js.map +1 -0
- package/dist/pubsub/index.d.ts +3 -0
- package/dist/pubsub/index.js +4 -0
- package/dist/pubsub/index.js.map +1 -0
- package/dist/pubsub/memory-engine.d.ts +16 -0
- package/dist/pubsub/memory-engine.js +29 -0
- package/dist/pubsub/memory-engine.js.map +1 -0
- package/dist/pubsub/redis-engine.d.ts +31 -0
- package/dist/pubsub/redis-engine.js +99 -0
- package/dist/pubsub/redis-engine.js.map +1 -0
- package/dist/types/index.d.ts +134 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/pipeline/index.ts"],"names":[],"mappings":"AACA,cAAc,aAAa,CAAC;AAE5B;;;;GAIG;AACH,MAAM,OAAO,UAAU;IACJ,WAAW,GAA0B,EAAE,CAAC;IAEzD;;OAEG;IACH,GAAG,CAAC,UAA+B;QACjC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,GAAG,CACP,MAAuB,EACvB,KAAa,EACb,OAAY,EACZ,OAAqE;QAErE,MAAM,OAAO,GAA4B;YACvC,MAAM;YACN,KAAK;YACL,OAAO;SACR,CAAC;QAEF,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC;QAEf,MAAM,QAAQ,GAAG,KAAK,EAAE,CAAS,EAAiB,EAAE;YAClD,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC;gBACf,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;YACpE,CAAC;YACD,KAAK,GAAG,CAAC,CAAC;YAEV,iFAAiF;YACjF,IAAI,CAAC,KAAK,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;gBAClC,MAAM,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;gBAC/C,OAAO;YACT,CAAC;YAED,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAE,CAAC;YACxC,MAAM,UAAU,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE;gBACnC,MAAM,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACxB,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;QAEF,MAAM,QAAQ,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;CACF"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 📨 Normalization interface for WebSocket packets
|
|
3
|
+
*/
|
|
4
|
+
export interface WsPacket {
|
|
5
|
+
readonly event: string;
|
|
6
|
+
readonly data: any;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* ⚙️ High-performance packet parser/serializer.
|
|
10
|
+
*/
|
|
11
|
+
export declare class WsPacketParser {
|
|
12
|
+
/**
|
|
13
|
+
* Parses a raw string or ArrayBuffer payload into a normalized WsPacket.
|
|
14
|
+
* Returns null if the payload does not conform to the expected format.
|
|
15
|
+
*/
|
|
16
|
+
static parse(payload: string | ArrayBuffer | Buffer): WsPacket | null;
|
|
17
|
+
/**
|
|
18
|
+
* Serializes an event and data object into a JSON string payload.
|
|
19
|
+
*/
|
|
20
|
+
static serialize(event: string, data: any): string;
|
|
21
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ⚙️ High-performance packet parser/serializer.
|
|
3
|
+
*/
|
|
4
|
+
export class WsPacketParser {
|
|
5
|
+
/**
|
|
6
|
+
* Parses a raw string or ArrayBuffer payload into a normalized WsPacket.
|
|
7
|
+
* Returns null if the payload does not conform to the expected format.
|
|
8
|
+
*/
|
|
9
|
+
static parse(payload) {
|
|
10
|
+
let rawStr;
|
|
11
|
+
if (payload instanceof ArrayBuffer) {
|
|
12
|
+
rawStr = Buffer.from(payload).toString('utf8');
|
|
13
|
+
}
|
|
14
|
+
else if (Buffer.isBuffer(payload)) {
|
|
15
|
+
rawStr = payload.toString('utf8');
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
rawStr = payload;
|
|
19
|
+
}
|
|
20
|
+
const trimmed = rawStr.trim();
|
|
21
|
+
// Quick early boundary validation: Must look like a JSON object
|
|
22
|
+
if (!trimmed.startsWith('{') || !trimmed.endsWith('}')) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
const parsed = JSON.parse(trimmed);
|
|
27
|
+
if (parsed && typeof parsed === 'object' && typeof parsed.event === 'string') {
|
|
28
|
+
return {
|
|
29
|
+
event: parsed.event,
|
|
30
|
+
data: parsed.data !== undefined ? parsed.data : null
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// Fail gracefully on invalid JSON structure
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Serializes an event and data object into a JSON string payload.
|
|
41
|
+
*/
|
|
42
|
+
static serialize(event, data) {
|
|
43
|
+
return JSON.stringify({ event, data });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/pipeline/parser.ts"],"names":[],"mappings":"AAQA;;GAEG;AACH,MAAM,OAAO,cAAc;IACzB;;;OAGG;IACH,MAAM,CAAC,KAAK,CAAC,OAAsC;QACjD,IAAI,MAAc,CAAC;QAEnB,IAAI,OAAO,YAAY,WAAW,EAAE,CAAC;YACnC,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACjD,CAAC;aAAM,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YACpC,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACpC,CAAC;aAAM,CAAC;YACN,MAAM,GAAG,OAAO,CAAC;QACnB,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;QAE9B,gEAAgE;QAChE,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACvD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACnC,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAC7E,OAAO;oBACL,KAAK,EAAE,MAAM,CAAC,KAAK;oBACnB,IAAI,EAAE,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI;iBACrD,CAAC;YACJ,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,4CAA4C;QAC9C,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,SAAS,CAAC,KAAa,EAAE,IAAS;QACvC,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,CAAC;CACF"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { DIContainer } from '@voltrix/injector';
|
|
2
|
+
/**
|
|
3
|
+
* 🚀 Voltrix WebSocket Processor (The Compiler)
|
|
4
|
+
* Discovers gateways, binds dependency injection, and pre-compiles execution pipelines.
|
|
5
|
+
*/
|
|
6
|
+
export declare class WebSocketProcessor {
|
|
7
|
+
/**
|
|
8
|
+
* Compiles and registers all decorated WebSocket Gateways within the Voltrix application.
|
|
9
|
+
* Auto-resolves dependencies from the DI Container and attaches to the uWS server instance.
|
|
10
|
+
*/
|
|
11
|
+
static process(container: DIContainer, uwsApp?: any, port?: number): void;
|
|
12
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { Metadata } from '@voltrix/core';
|
|
2
|
+
import { WS_KEYS } from '../decorators/index.js';
|
|
3
|
+
import { UwsWebSocketAdapter } from '../adapters/uws-adapter.js';
|
|
4
|
+
/**
|
|
5
|
+
* 🚀 Voltrix WebSocket Processor (The Compiler)
|
|
6
|
+
* Discovers gateways, binds dependency injection, and pre-compiles execution pipelines.
|
|
7
|
+
*/
|
|
8
|
+
export class WebSocketProcessor {
|
|
9
|
+
/**
|
|
10
|
+
* Compiles and registers all decorated WebSocket Gateways within the Voltrix application.
|
|
11
|
+
* Auto-resolves dependencies from the DI Container and attaches to the uWS server instance.
|
|
12
|
+
*/
|
|
13
|
+
static process(container, uwsApp, port = 3000) {
|
|
14
|
+
// 1. Scan the global metadata index for tracked classes
|
|
15
|
+
const classes = Metadata.getTrackedClasses();
|
|
16
|
+
for (const ctor of classes) {
|
|
17
|
+
const meta = Metadata.get(ctor);
|
|
18
|
+
const gatewayOptions = meta[WS_KEYS.GATEWAY];
|
|
19
|
+
// Skip classes that do not declare `@WebSocketGateway()`
|
|
20
|
+
if (!gatewayOptions)
|
|
21
|
+
continue;
|
|
22
|
+
// 2. Resolve the Gateway instance from the DI Container with full dependency injection
|
|
23
|
+
const gatewayInstance = container.resolve(ctor);
|
|
24
|
+
if (!gatewayInstance) {
|
|
25
|
+
throw new Error(`Failed to resolve WebSocket Gateway: ${ctor.name}`);
|
|
26
|
+
}
|
|
27
|
+
// 3. Configure Handshake Guard if defined
|
|
28
|
+
const path = gatewayOptions.path || '/ws';
|
|
29
|
+
let onUpgradeHook = undefined;
|
|
30
|
+
if (gatewayOptions.guard) {
|
|
31
|
+
const guardInstance = container.resolve(gatewayOptions.guard);
|
|
32
|
+
if (!guardInstance) {
|
|
33
|
+
throw new Error(`Failed to resolve WebSocket Guard: ${gatewayOptions.guard.name}`);
|
|
34
|
+
}
|
|
35
|
+
onUpgradeHook = async (req, res) => {
|
|
36
|
+
let resolvedUser = null;
|
|
37
|
+
const context = {
|
|
38
|
+
getRequest: () => req,
|
|
39
|
+
getResponse: () => res,
|
|
40
|
+
setUser: (user) => { resolvedUser = user; },
|
|
41
|
+
getUser: () => resolvedUser
|
|
42
|
+
};
|
|
43
|
+
const canActivate = await guardInstance.canActivate(context);
|
|
44
|
+
if (!canActivate)
|
|
45
|
+
return false;
|
|
46
|
+
return resolvedUser || true;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
// 4. Instantiate Adapter and create the server WebSocket listener
|
|
50
|
+
const adapter = new UwsWebSocketAdapter();
|
|
51
|
+
const server = adapter.create(port, {
|
|
52
|
+
app: uwsApp,
|
|
53
|
+
path,
|
|
54
|
+
onUpgrade: onUpgradeHook
|
|
55
|
+
});
|
|
56
|
+
// 5. Bind Connection events and lifecycles
|
|
57
|
+
const onConnectKey = meta[WS_KEYS.ON_CONNECT];
|
|
58
|
+
const onDisconnectKey = meta[WS_KEYS.ON_DISCONNECT];
|
|
59
|
+
adapter.bindClientConnect(server, async (socket) => {
|
|
60
|
+
// Trigger OnConnect lifecycle hook if declared
|
|
61
|
+
if (onConnectKey) {
|
|
62
|
+
const paramsMeta = Metadata.get(ctor, onConnectKey)[WS_KEYS.PARAMS] || [];
|
|
63
|
+
const args = new Array(paramsMeta.length);
|
|
64
|
+
paramsMeta.forEach((p) => {
|
|
65
|
+
if (p.type === 'socket')
|
|
66
|
+
args[p.index] = socket;
|
|
67
|
+
});
|
|
68
|
+
await gatewayInstance[onConnectKey](...args);
|
|
69
|
+
}
|
|
70
|
+
// Trigger OnDisconnect lifecycle hook if declared
|
|
71
|
+
if (onDisconnectKey) {
|
|
72
|
+
adapter.bindClientDisconnect(socket, async (client, code, reason) => {
|
|
73
|
+
const paramsMeta = Metadata.get(ctor, onDisconnectKey)[WS_KEYS.PARAMS] || [];
|
|
74
|
+
const args = new Array(paramsMeta.index + 1 || paramsMeta.length);
|
|
75
|
+
paramsMeta.forEach((p) => {
|
|
76
|
+
if (p.type === 'socket')
|
|
77
|
+
args[p.index] = client;
|
|
78
|
+
});
|
|
79
|
+
await gatewayInstance[onDisconnectKey](...args);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
// 6. Compile and bind message handlers
|
|
84
|
+
const eventsList = meta[WS_KEYS.EVENTS] || [];
|
|
85
|
+
const handlers = eventsList.map((e) => {
|
|
86
|
+
const methodKey = e.propertyKey;
|
|
87
|
+
const paramsMeta = Metadata.get(ctor, methodKey)[WS_KEYS.PARAMS] || [];
|
|
88
|
+
return {
|
|
89
|
+
event: e.event,
|
|
90
|
+
handler: async (client, data) => {
|
|
91
|
+
// Build the arguments array programmatically in O(1)
|
|
92
|
+
const args = new Array(paramsMeta.length);
|
|
93
|
+
paramsMeta.forEach((p) => {
|
|
94
|
+
if (p.type === 'socket')
|
|
95
|
+
args[p.index] = client;
|
|
96
|
+
else if (p.type === 'body')
|
|
97
|
+
args[p.index] = data;
|
|
98
|
+
});
|
|
99
|
+
await gatewayInstance[methodKey](...args);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
});
|
|
103
|
+
// Bind all pre-compiled handlers globally on the adapter
|
|
104
|
+
adapter.bindMessageHandlers(server, handlers);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=websocket.processor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket.processor.js","sourceRoot":"","sources":["../../src/processors/websocket.processor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/pubsub/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { IPubSubEngine, WsSocket } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* 📡 In-Memory Pub/Sub Engine using native C++ uWebSockets.js capabilities.
|
|
4
|
+
* Delivers extreme performance and near-zero memory footprint.
|
|
5
|
+
*/
|
|
6
|
+
export declare class MemoryEngine implements IPubSubEngine {
|
|
7
|
+
private readonly app;
|
|
8
|
+
/**
|
|
9
|
+
* @param app The raw uWS TemplatedApp instance.
|
|
10
|
+
*/
|
|
11
|
+
constructor(app: any);
|
|
12
|
+
subscribe(client: WsSocket, topic: string): void;
|
|
13
|
+
unsubscribe(client: WsSocket, topic: string): void;
|
|
14
|
+
publish(topic: string, message: any, isBinary?: boolean): void;
|
|
15
|
+
broadcast(message: any, isBinary?: boolean): void;
|
|
16
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 📡 In-Memory Pub/Sub Engine using native C++ uWebSockets.js capabilities.
|
|
3
|
+
* Delivers extreme performance and near-zero memory footprint.
|
|
4
|
+
*/
|
|
5
|
+
export class MemoryEngine {
|
|
6
|
+
app;
|
|
7
|
+
/**
|
|
8
|
+
* @param app The raw uWS TemplatedApp instance.
|
|
9
|
+
*/
|
|
10
|
+
constructor(app) {
|
|
11
|
+
this.app = app;
|
|
12
|
+
}
|
|
13
|
+
subscribe(client, topic) {
|
|
14
|
+
client.subscribe(topic);
|
|
15
|
+
}
|
|
16
|
+
unsubscribe(client, topic) {
|
|
17
|
+
client.unsubscribe(topic);
|
|
18
|
+
}
|
|
19
|
+
publish(topic, message, isBinary) {
|
|
20
|
+
const payload = typeof message === 'string' ? message : JSON.stringify(message);
|
|
21
|
+
this.app.publish(topic, payload, isBinary ?? false);
|
|
22
|
+
}
|
|
23
|
+
broadcast(message, isBinary) {
|
|
24
|
+
// Standardized global room for broadcasts
|
|
25
|
+
const payload = typeof message === 'string' ? message : JSON.stringify(message);
|
|
26
|
+
this.app.publish('global', payload, isBinary ?? false);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=memory-engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-engine.js","sourceRoot":"","sources":["../../src/pubsub/memory-engine.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,OAAO,YAAY;IAIM;IAH7B;;OAEG;IACH,YAA6B,GAAQ;QAAR,QAAG,GAAH,GAAG,CAAK;IAAG,CAAC;IAEzC,SAAS,CAAC,MAAgB,EAAE,KAAa;QACvC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;IAED,WAAW,CAAC,MAAgB,EAAE,KAAa;QACzC,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IAED,OAAO,CAAC,KAAa,EAAE,OAAY,EAAE,QAAkB;QACrD,MAAM,OAAO,GAAG,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAChF,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,IAAI,KAAK,CAAC,CAAC;IACtD,CAAC;IAED,SAAS,CAAC,OAAY,EAAE,QAAkB;QACxC,0CAA0C;QAC1C,MAAM,OAAO,GAAG,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAChF,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,IAAI,KAAK,CAAC,CAAC;IACzD,CAAC;CACF"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type RedisOptions } from 'ioredis';
|
|
2
|
+
import type { IPubSubEngine, WsSocket } from '../types/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* 📡 Distributed Redis Pub/Sub Engine.
|
|
5
|
+
* Syncs Rooms/Topics in real-time across a cluster of multiple Voltrix server instances.
|
|
6
|
+
*/
|
|
7
|
+
export declare class RedisEngine implements IPubSubEngine {
|
|
8
|
+
private readonly localEngine;
|
|
9
|
+
private readonly pubClient;
|
|
10
|
+
private readonly subClient;
|
|
11
|
+
private readonly prefix;
|
|
12
|
+
private isSubscribed;
|
|
13
|
+
/**
|
|
14
|
+
* @param app The raw uWS TemplatedApp instance.
|
|
15
|
+
* @param redisConfig Either a Redis URL string or full connection options.
|
|
16
|
+
*/
|
|
17
|
+
constructor(app: any, redisConfig: string | RedisOptions);
|
|
18
|
+
subscribe(client: WsSocket, topic: string): void;
|
|
19
|
+
unsubscribe(client: WsSocket, topic: string): void;
|
|
20
|
+
publish(topic: string, message: any, isBinary?: boolean): Promise<void>;
|
|
21
|
+
broadcast(message: any, isBinary?: boolean): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* 🚏 Clustered pattern subscription bridge.
|
|
24
|
+
* Listens to Redis channels and pipes messages into local uWS channels natively.
|
|
25
|
+
*/
|
|
26
|
+
private setupSubscriptionBridge;
|
|
27
|
+
/**
|
|
28
|
+
* Securely disconnects the Redis client connections
|
|
29
|
+
*/
|
|
30
|
+
close(): Promise<void>;
|
|
31
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { Redis } from 'ioredis';
|
|
2
|
+
import { MemoryEngine } from './memory-engine.js';
|
|
3
|
+
/**
|
|
4
|
+
* 📡 Distributed Redis Pub/Sub Engine.
|
|
5
|
+
* Syncs Rooms/Topics in real-time across a cluster of multiple Voltrix server instances.
|
|
6
|
+
*/
|
|
7
|
+
export class RedisEngine {
|
|
8
|
+
localEngine;
|
|
9
|
+
pubClient;
|
|
10
|
+
subClient;
|
|
11
|
+
prefix = 'vltx:ws:';
|
|
12
|
+
isSubscribed = false;
|
|
13
|
+
/**
|
|
14
|
+
* @param app The raw uWS TemplatedApp instance.
|
|
15
|
+
* @param redisConfig Either a Redis URL string or full connection options.
|
|
16
|
+
*/
|
|
17
|
+
constructor(app, redisConfig) {
|
|
18
|
+
this.localEngine = new MemoryEngine(app);
|
|
19
|
+
// Initialize Redis clients for Publishing and Subscribing
|
|
20
|
+
if (typeof redisConfig === 'string') {
|
|
21
|
+
this.pubClient = new Redis(redisConfig, { maxRetriesPerRequest: null });
|
|
22
|
+
this.subClient = new Redis(redisConfig, { maxRetriesPerRequest: null });
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
this.pubClient = new Redis({ ...redisConfig, maxRetriesPerRequest: null });
|
|
26
|
+
this.subClient = new Redis({ ...redisConfig, maxRetriesPerRequest: null });
|
|
27
|
+
}
|
|
28
|
+
// Suppress unhandled connection errors to prevent crashes if Redis is offline
|
|
29
|
+
this.pubClient.on('error', () => { });
|
|
30
|
+
this.subClient.on('error', () => { });
|
|
31
|
+
this.setupSubscriptionBridge();
|
|
32
|
+
}
|
|
33
|
+
subscribe(client, topic) {
|
|
34
|
+
this.localEngine.subscribe(client, topic);
|
|
35
|
+
if (topic !== 'global') {
|
|
36
|
+
this.localEngine.subscribe(client, 'global');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
unsubscribe(client, topic) {
|
|
40
|
+
this.localEngine.unsubscribe(client, topic);
|
|
41
|
+
}
|
|
42
|
+
async publish(topic, message, isBinary) {
|
|
43
|
+
this.localEngine.publish(topic, message, isBinary);
|
|
44
|
+
const payload = typeof message === 'string' ? message : JSON.stringify(message);
|
|
45
|
+
const packet = JSON.stringify({
|
|
46
|
+
message: payload,
|
|
47
|
+
isBinary: isBinary ?? false
|
|
48
|
+
});
|
|
49
|
+
try {
|
|
50
|
+
await this.pubClient.publish(`${this.prefix}${topic}`, packet);
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
// Degrade gracefully if Redis publisher is offline
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async broadcast(message, isBinary) {
|
|
57
|
+
await this.publish('global', message, isBinary);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* 🚏 Clustered pattern subscription bridge.
|
|
61
|
+
* Listens to Redis channels and pipes messages into local uWS channels natively.
|
|
62
|
+
*/
|
|
63
|
+
setupSubscriptionBridge() {
|
|
64
|
+
if (this.isSubscribed)
|
|
65
|
+
return;
|
|
66
|
+
this.isSubscribed = true;
|
|
67
|
+
// Pattern subscribe to all voltrix ws channels
|
|
68
|
+
this.subClient.psubscribe(`${this.prefix}*`).catch(() => {
|
|
69
|
+
this.isSubscribed = false;
|
|
70
|
+
});
|
|
71
|
+
this.subClient.on('pmessage', (_pattern, channel, message) => {
|
|
72
|
+
const topic = channel.slice(this.prefix.length);
|
|
73
|
+
try {
|
|
74
|
+
const data = JSON.parse(message);
|
|
75
|
+
if (data && data.message !== undefined) {
|
|
76
|
+
this.localEngine.publish(topic, data.message, data.isBinary);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
// Suppress parsing errors
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Securely disconnects the Redis client connections
|
|
86
|
+
*/
|
|
87
|
+
async close() {
|
|
88
|
+
try {
|
|
89
|
+
await Promise.all([
|
|
90
|
+
this.pubClient.quit(),
|
|
91
|
+
this.subClient.quit()
|
|
92
|
+
]);
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
// Safe exit
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=redis-engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis-engine.js","sourceRoot":"","sources":["../../src/pubsub/redis-engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import type { IRequest, IResponse } from '@voltrix/core';
|
|
2
|
+
/**
|
|
3
|
+
* 🔌 Core WsSocket normalization interface wrapper.
|
|
4
|
+
* Encapsulates client socket operations for engine-agnostic code.
|
|
5
|
+
*/
|
|
6
|
+
export interface WsSocket<TUser = any, TRawSocket = any> {
|
|
7
|
+
/**
|
|
8
|
+
* Unique connection ID.
|
|
9
|
+
*/
|
|
10
|
+
readonly id: string;
|
|
11
|
+
/**
|
|
12
|
+
* Authenticated user object/context.
|
|
13
|
+
*/
|
|
14
|
+
user?: TUser;
|
|
15
|
+
/**
|
|
16
|
+
* Send a message to this specific client.
|
|
17
|
+
*/
|
|
18
|
+
send(message: string | ArrayBufferView | ArrayBuffer, isBinary?: boolean): void;
|
|
19
|
+
/**
|
|
20
|
+
* Subscribe this client to a room/topic.
|
|
21
|
+
*/
|
|
22
|
+
subscribe(topic: string): void;
|
|
23
|
+
/**
|
|
24
|
+
* Unsubscribe this client from a room/topic.
|
|
25
|
+
*/
|
|
26
|
+
unsubscribe(topic: string): void;
|
|
27
|
+
/**
|
|
28
|
+
* Publish a message to a topic.
|
|
29
|
+
*/
|
|
30
|
+
publish(topic: string, message: string | ArrayBufferView | ArrayBuffer, isBinary?: boolean): void;
|
|
31
|
+
/**
|
|
32
|
+
* Close the connection securely.
|
|
33
|
+
*/
|
|
34
|
+
close(code?: number, reason?: string): void;
|
|
35
|
+
/**
|
|
36
|
+
* The raw underlying engine socket instance (e.g. uWS.WebSocket).
|
|
37
|
+
*/
|
|
38
|
+
readonly raw: TRawSocket;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* 🎯 Structure of a registered message handler.
|
|
42
|
+
*/
|
|
43
|
+
export interface WsMessageHandler<TClient extends WsSocket = WsSocket> {
|
|
44
|
+
readonly event: string;
|
|
45
|
+
readonly handler: (client: TClient, data: any) => void | Promise<void>;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* 🔌 Pluggable WebSocket Adapter Contract.
|
|
49
|
+
*/
|
|
50
|
+
export interface IWebSocketAdapter<TServer = any, TClient extends WsSocket = WsSocket, TOptions = any> {
|
|
51
|
+
/**
|
|
52
|
+
* Creates the WebSocket server.
|
|
53
|
+
*/
|
|
54
|
+
create(port: number, options?: TOptions): TServer;
|
|
55
|
+
/**
|
|
56
|
+
* Binds callback to client connection events.
|
|
57
|
+
*/
|
|
58
|
+
bindClientConnect(server: TServer, callback: (client: TClient) => void | Promise<void>): void;
|
|
59
|
+
/**
|
|
60
|
+
* Binds callback to client disconnection events.
|
|
61
|
+
*/
|
|
62
|
+
bindClientDisconnect(client: TClient, callback: (client: TClient, code: number, reason: ArrayBuffer) => void | Promise<void>): void;
|
|
63
|
+
/**
|
|
64
|
+
* Binds handlers for events sent by the client.
|
|
65
|
+
*/
|
|
66
|
+
bindMessageHandlers(client: TClient, handlers: WsMessageHandler<TClient>[]): void;
|
|
67
|
+
/**
|
|
68
|
+
* Closes the server.
|
|
69
|
+
*/
|
|
70
|
+
close(): void | Promise<void>;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* 📡 Pluggable Pub/Sub and Distributed Broadcasting Engine.
|
|
74
|
+
*/
|
|
75
|
+
export interface IPubSubEngine<TClient extends WsSocket = WsSocket, TPayload = any> {
|
|
76
|
+
/**
|
|
77
|
+
* Subscribes a client to a topic.
|
|
78
|
+
*/
|
|
79
|
+
subscribe(client: TClient, topic: string): void | Promise<void>;
|
|
80
|
+
/**
|
|
81
|
+
* Unsubscribes a client from a topic.
|
|
82
|
+
*/
|
|
83
|
+
unsubscribe(client: TClient, topic: string): void | Promise<void>;
|
|
84
|
+
/**
|
|
85
|
+
* Publishes a message to a topic.
|
|
86
|
+
*/
|
|
87
|
+
publish(topic: string, message: TPayload, isBinary?: boolean): void | Promise<void>;
|
|
88
|
+
/**
|
|
89
|
+
* Broadcasts a message globally to all connections.
|
|
90
|
+
*/
|
|
91
|
+
broadcast(message: TPayload, isBinary?: boolean): void | Promise<void>;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* 🔒 Handshake Context for Pre-Upgrade Authentication.
|
|
95
|
+
*/
|
|
96
|
+
export interface HandshakeContext<TUser = any> {
|
|
97
|
+
/**
|
|
98
|
+
* Returns the underlying HTTP Request interface.
|
|
99
|
+
*/
|
|
100
|
+
getRequest(): IRequest;
|
|
101
|
+
/**
|
|
102
|
+
* Returns the underlying HTTP Response interface.
|
|
103
|
+
*/
|
|
104
|
+
getResponse(): IResponse;
|
|
105
|
+
/**
|
|
106
|
+
* Sets the resolved/authenticated user metadata.
|
|
107
|
+
*/
|
|
108
|
+
setUser(user: TUser): void;
|
|
109
|
+
/**
|
|
110
|
+
* Gets the active user metadata.
|
|
111
|
+
*/
|
|
112
|
+
getUser(): TUser | undefined;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* 📨 WebSocket Message Context for Pipelines.
|
|
116
|
+
*/
|
|
117
|
+
export interface WsMessageContext<TUser = any> {
|
|
118
|
+
/**
|
|
119
|
+
* The client socket that sent the message.
|
|
120
|
+
*/
|
|
121
|
+
readonly client: WsSocket<TUser>;
|
|
122
|
+
/**
|
|
123
|
+
* The event name.
|
|
124
|
+
*/
|
|
125
|
+
readonly event: string;
|
|
126
|
+
/**
|
|
127
|
+
* The parsed payload.
|
|
128
|
+
*/
|
|
129
|
+
payload: any;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* ⚙️ Interceptor / Middleware for message events.
|
|
133
|
+
*/
|
|
134
|
+
export type WsMiddleware<TUser = any> = (context: WsMessageContext<TUser>, next: (err?: Error) => void | Promise<void>) => void | Promise<void>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@voltrix/websocket",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "High-performance, programmatic-first and decorator-driven WebSocket package with pluggable adapters and distributed pub/sub for Voltrix",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"module": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"voltrix",
|
|
18
|
+
"websocket",
|
|
19
|
+
"uWebSockets.js",
|
|
20
|
+
"pubsub",
|
|
21
|
+
"redis",
|
|
22
|
+
"realtime",
|
|
23
|
+
"gateway"
|
|
24
|
+
],
|
|
25
|
+
"author": "Voltrix Team",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"ioredis": "^5.4.1",
|
|
29
|
+
"reflect-metadata": "^0.2.2",
|
|
30
|
+
"tslib": "^2.8.1",
|
|
31
|
+
"uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.60.0",
|
|
32
|
+
"@voltrix/core": "0.3.0",
|
|
33
|
+
"@voltrix/injector": "0.2.2"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@types/node": "^20.0.0",
|
|
37
|
+
"typescript": "5.9.3",
|
|
38
|
+
"vitest": "^4.1.0",
|
|
39
|
+
"ws": "^8.18.0",
|
|
40
|
+
"@types/ws": "^8.5.10",
|
|
41
|
+
"@voltrix/decorator": "0.2.2",
|
|
42
|
+
"@voltrix/server": "0.2.1"
|
|
43
|
+
},
|
|
44
|
+
"files": [
|
|
45
|
+
"dist",
|
|
46
|
+
"README.md",
|
|
47
|
+
"LICENSE"
|
|
48
|
+
],
|
|
49
|
+
"engines": {
|
|
50
|
+
"node": ">=18.0.0"
|
|
51
|
+
},
|
|
52
|
+
"publishConfig": {
|
|
53
|
+
"access": "public"
|
|
54
|
+
},
|
|
55
|
+
"scripts": {
|
|
56
|
+
"build": "tsc -p tsconfig.json",
|
|
57
|
+
"dev": "tsc --watch",
|
|
58
|
+
"test": "vitest run",
|
|
59
|
+
"type-check": "tsc --noEmit"
|
|
60
|
+
}
|
|
61
|
+
}
|