@scpxl/nodejs-framework 1.0.22 → 1.0.25
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/README.md +264 -26
- package/dist/api-requester/api-requester.d.ts +32 -0
- package/dist/api-requester/api-requester.d.ts.map +1 -0
- package/dist/api-requester/api-requester.js +2 -1
- package/dist/api-requester/api-requester.js.map +2 -2
- package/dist/api-requester/index.d.ts +3 -0
- package/dist/api-requester/index.d.ts.map +1 -0
- package/dist/application/base-application.d.ts +106 -0
- package/dist/application/base-application.d.ts.map +1 -0
- package/dist/application/base-application.interface.d.ts +162 -0
- package/dist/application/base-application.interface.d.ts.map +1 -0
- package/dist/application/base-application.js +7 -3
- package/dist/application/base-application.js.map +2 -2
- package/dist/application/command-application.d.ts +18 -0
- package/dist/application/command-application.d.ts.map +1 -0
- package/dist/application/command-application.interface.d.ts +26 -0
- package/dist/application/command-application.interface.d.ts.map +1 -0
- package/dist/application/index.d.ts +5 -0
- package/dist/application/index.d.ts.map +1 -0
- package/dist/application/web-application.d.ts +43 -0
- package/dist/application/web-application.d.ts.map +1 -0
- package/dist/application/web-application.interface.d.ts +21 -0
- package/dist/application/web-application.interface.d.ts.map +1 -0
- package/dist/application/web-application.js +1 -0
- package/dist/application/web-application.js.map +2 -2
- package/dist/auth/index.d.ts +2 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/jwt.d.ts +25 -0
- package/dist/auth/jwt.d.ts.map +1 -0
- package/dist/cache/index.d.ts +2 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/manager.d.ts +107 -0
- package/dist/cache/manager.d.ts.map +1 -0
- package/dist/cache/manager.js +2 -1
- package/dist/cache/manager.js.map +2 -2
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +12591 -0
- package/dist/cli/index.js.map +7 -0
- package/dist/cluster/cluster-manager.d.ts +18 -0
- package/dist/cluster/cluster-manager.d.ts.map +1 -0
- package/dist/cluster/cluster-manager.interface.d.ts +23 -0
- package/dist/cluster/cluster-manager.interface.d.ts.map +1 -0
- package/dist/cluster/cluster-manager.js +45 -8
- package/dist/cluster/cluster-manager.js.map +2 -2
- package/dist/cluster/index.d.ts +2 -0
- package/dist/cluster/index.d.ts.map +1 -0
- package/dist/command/command-manager.d.ts +19 -0
- package/dist/command/command-manager.d.ts.map +1 -0
- package/dist/command/command.d.ts +27 -0
- package/dist/command/command.d.ts.map +1 -0
- package/dist/command/command.interface.d.ts +11 -0
- package/dist/command/command.interface.d.ts.map +1 -0
- package/dist/command/index.d.ts +3 -0
- package/dist/command/index.d.ts.map +1 -0
- package/dist/config/env.d.ts +11 -0
- package/dist/config/env.d.ts.map +1 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/schema.d.ts +432 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/database/dynamic-entity-form-decorators.d.ts +31 -0
- package/dist/database/dynamic-entity-form-decorators.d.ts.map +1 -0
- package/dist/database/dynamic-entity-form-decorators.js.map +1 -1
- package/dist/database/dynamic-entity.d.ts +18 -0
- package/dist/database/dynamic-entity.d.ts.map +1 -0
- package/dist/database/dynamic-entity.js +11 -1
- package/dist/database/dynamic-entity.js.map +2 -2
- package/dist/database/index.d.ts +5 -0
- package/dist/database/index.d.ts.map +1 -0
- package/dist/database/instance.d.ts +36 -0
- package/dist/database/instance.d.ts.map +1 -0
- package/dist/database/instance.interface.d.ts +5 -0
- package/dist/database/instance.interface.d.ts.map +1 -0
- package/dist/database/manager.d.ts +27 -0
- package/dist/database/manager.d.ts.map +1 -0
- package/dist/database/manager.interface.d.ts +18 -0
- package/dist/database/manager.interface.d.ts.map +1 -0
- package/dist/database/manager.js +3 -2
- package/dist/database/manager.js.map +2 -2
- package/dist/error/error-reporter.d.ts +109 -0
- package/dist/error/error-reporter.d.ts.map +1 -0
- package/dist/error/error-reporter.js +32 -29
- package/dist/error/error-reporter.js.map +2 -2
- package/dist/error/error.interface.d.ts +126 -0
- package/dist/error/error.interface.d.ts.map +1 -0
- package/dist/error/framework-errors.d.ts +113 -0
- package/dist/error/framework-errors.d.ts.map +1 -0
- package/dist/error/index.d.ts +6 -0
- package/dist/error/index.d.ts.map +1 -0
- package/dist/error/index.js +3 -2
- package/dist/error/index.js.map +2 -2
- package/dist/event/controller/base.d.ts +23 -0
- package/dist/event/controller/base.d.ts.map +1 -0
- package/dist/event/controller/base.interface.d.ts +11 -0
- package/dist/event/controller/base.interface.d.ts.map +1 -0
- package/dist/event/controller/base.js +2 -1
- package/dist/event/controller/base.js.map +2 -2
- package/dist/event/index.d.ts +5 -0
- package/dist/event/index.d.ts.map +1 -0
- package/dist/event/manager.d.ts +21 -0
- package/dist/event/manager.d.ts.map +1 -0
- package/dist/event/manager.interface.d.ts +137 -0
- package/dist/event/manager.interface.d.ts.map +1 -0
- package/dist/event/manager.js +5 -4
- package/dist/event/manager.js.map +2 -2
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/lifecycle/exit.d.ts +11 -0
- package/dist/lifecycle/exit.d.ts.map +1 -0
- package/dist/lifecycle/exit.js.map +2 -2
- package/dist/lifecycle/index.d.ts +7 -0
- package/dist/lifecycle/index.d.ts.map +1 -0
- package/dist/lifecycle/lifecycle-manager.d.ts +66 -0
- package/dist/lifecycle/lifecycle-manager.d.ts.map +1 -0
- package/dist/lifecycle/lifecycle-manager.js +6 -11
- package/dist/lifecycle/lifecycle-manager.js.map +2 -2
- package/dist/lifecycle/shutdown-controller.d.ts +15 -0
- package/dist/lifecycle/shutdown-controller.d.ts.map +1 -0
- package/dist/lifecycle/types.d.ts +28 -0
- package/dist/lifecycle/types.d.ts.map +1 -0
- package/dist/logger/index.d.ts +2 -0
- package/dist/logger/index.d.ts.map +1 -0
- package/dist/logger/logger.d.ts +59 -0
- package/dist/logger/logger.d.ts.map +1 -0
- package/dist/logger/logger.interface.d.ts +2 -0
- package/dist/logger/logger.interface.d.ts.map +1 -0
- package/dist/logger/logger.js +11 -3
- package/dist/logger/logger.js.map +2 -2
- package/dist/performance/cache-performance.d.ts +64 -0
- package/dist/performance/cache-performance.d.ts.map +1 -0
- package/dist/performance/database-performance.d.ts +40 -0
- package/dist/performance/database-performance.d.ts.map +1 -0
- package/dist/performance/index.d.ts +8 -0
- package/dist/performance/index.d.ts.map +1 -0
- package/dist/performance/performance-monitor.d.ts +68 -0
- package/dist/performance/performance-monitor.d.ts.map +1 -0
- package/dist/performance/performance-monitor.js +10 -3
- package/dist/performance/performance-monitor.js.map +2 -2
- package/dist/performance/performance-monitor.plugin.d.ts +24 -0
- package/dist/performance/performance-monitor.plugin.d.ts.map +1 -0
- package/dist/performance/queue-performance.d.ts +46 -0
- package/dist/performance/queue-performance.d.ts.map +1 -0
- package/dist/performance/webserver-performance.d.ts +69 -0
- package/dist/performance/webserver-performance.d.ts.map +1 -0
- package/dist/performance/websocket-performance.d.ts +44 -0
- package/dist/performance/websocket-performance.d.ts.map +1 -0
- package/dist/queue/index.d.ts +6 -0
- package/dist/queue/index.d.ts.map +1 -0
- package/dist/queue/index.interface.d.ts +10 -0
- package/dist/queue/index.interface.d.ts.map +1 -0
- package/dist/queue/job.interface.d.ts +43 -0
- package/dist/queue/job.interface.d.ts.map +1 -0
- package/dist/queue/manager.d.ts +44 -0
- package/dist/queue/manager.d.ts.map +1 -0
- package/dist/queue/manager.interface.d.ts +18 -0
- package/dist/queue/manager.interface.d.ts.map +1 -0
- package/dist/queue/processor/base.d.ts +29 -0
- package/dist/queue/processor/base.d.ts.map +1 -0
- package/dist/queue/processor/base.js +2 -1
- package/dist/queue/processor/base.js.map +2 -2
- package/dist/queue/processor/processor.interface.d.ts +16 -0
- package/dist/queue/processor/processor.interface.d.ts.map +1 -0
- package/dist/queue/worker.d.ts +14 -0
- package/dist/queue/worker.d.ts.map +1 -0
- package/dist/queue/worker.interface.d.ts +13 -0
- package/dist/queue/worker.interface.d.ts.map +1 -0
- package/dist/redis/index.d.ts +3 -0
- package/dist/redis/index.d.ts.map +1 -0
- package/dist/redis/instance.d.ts +32 -0
- package/dist/redis/instance.d.ts.map +1 -0
- package/dist/redis/instance.interface.d.ts +9 -0
- package/dist/redis/instance.interface.d.ts.map +1 -0
- package/dist/redis/manager.d.ts +15 -0
- package/dist/redis/manager.d.ts.map +1 -0
- package/dist/redis/manager.interface.d.ts +8 -0
- package/dist/redis/manager.interface.d.ts.map +1 -0
- package/dist/redis/manager.js +16 -16
- package/dist/redis/manager.js.map +2 -2
- package/dist/request-context/index.d.ts +3 -0
- package/dist/request-context/index.d.ts.map +1 -0
- package/dist/request-context/request-context.d.ts +108 -0
- package/dist/request-context/request-context.d.ts.map +1 -0
- package/dist/request-context/request-context.interface.d.ts +46 -0
- package/dist/request-context/request-context.interface.d.ts.map +1 -0
- package/dist/schemas/common.d.ts +197 -0
- package/dist/schemas/common.d.ts.map +1 -0
- package/dist/schemas/common.js +108 -0
- package/dist/schemas/common.js.map +7 -0
- package/dist/schemas/index.d.ts +6 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +2 -0
- package/dist/schemas/index.js.map +7 -0
- package/dist/services/aws/index.d.ts +2 -0
- package/dist/services/aws/index.d.ts.map +1 -0
- package/dist/services/aws/s3.d.ts +54 -0
- package/dist/services/aws/s3.d.ts.map +1 -0
- package/dist/services/aws/s3.interface.d.ts +14 -0
- package/dist/services/aws/s3.interface.d.ts.map +1 -0
- package/dist/services/index.d.ts +2 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/util/file.d.ts +58 -0
- package/dist/util/file.d.ts.map +1 -0
- package/dist/util/helper.d.ts +51 -0
- package/dist/util/helper.d.ts.map +1 -0
- package/dist/util/helper.js +72 -10
- package/dist/util/helper.js.map +2 -2
- package/dist/util/image.d.ts +12 -0
- package/dist/util/image.d.ts.map +1 -0
- package/dist/util/index.d.ts +11 -0
- package/dist/util/index.d.ts.map +1 -0
- package/dist/util/loader.d.ts +21 -0
- package/dist/util/loader.d.ts.map +1 -0
- package/dist/util/loader.js +5 -2
- package/dist/util/loader.js.map +2 -2
- package/dist/util/num.d.ts +13 -0
- package/dist/util/num.d.ts.map +1 -0
- package/dist/util/os.d.ts +6 -0
- package/dist/util/os.d.ts.map +1 -0
- package/dist/util/str.d.ts +39 -0
- package/dist/util/str.d.ts.map +1 -0
- package/dist/util/time.d.ts +19 -0
- package/dist/util/time.d.ts.map +1 -0
- package/dist/util/time.interface.d.ts +12 -0
- package/dist/util/time.interface.d.ts.map +1 -0
- package/dist/util/timing.d.ts +36 -0
- package/dist/util/timing.d.ts.map +1 -0
- package/dist/util/timing.interface.d.ts +47 -0
- package/dist/util/timing.interface.d.ts.map +1 -0
- package/dist/util/url.d.ts +7 -0
- package/dist/util/url.d.ts.map +1 -0
- package/dist/webserver/controller/auth-middleware.d.ts +21 -0
- package/dist/webserver/controller/auth-middleware.d.ts.map +1 -0
- package/dist/webserver/controller/base.d.ts +41 -0
- package/dist/webserver/controller/base.d.ts.map +1 -0
- package/dist/webserver/controller/base.interface.d.ts +50 -0
- package/dist/webserver/controller/base.interface.d.ts.map +1 -0
- package/dist/webserver/controller/base.js +4 -4
- package/dist/webserver/controller/base.js.map +2 -2
- package/dist/webserver/controller/entity.d.ts +94 -0
- package/dist/webserver/controller/entity.d.ts.map +1 -0
- package/dist/webserver/controller/entity.js.map +2 -2
- package/dist/webserver/controller/example-auth.d.ts +12 -0
- package/dist/webserver/controller/example-auth.d.ts.map +1 -0
- package/dist/webserver/controller/health.d.ts +13 -0
- package/dist/webserver/controller/health.d.ts.map +1 -0
- package/dist/webserver/controller/health.js +0 -14
- package/dist/webserver/controller/health.js.map +2 -2
- package/dist/webserver/define-action.d.ts +26 -0
- package/dist/webserver/define-action.d.ts.map +1 -0
- package/dist/webserver/define-action.js +16 -0
- package/dist/webserver/define-action.js.map +7 -0
- package/dist/webserver/define-route.d.ts +53 -0
- package/dist/webserver/define-route.d.ts.map +1 -0
- package/dist/webserver/define-route.js +11 -6
- package/dist/webserver/define-route.js.map +2 -2
- package/dist/webserver/index.d.ts +14 -0
- package/dist/webserver/index.d.ts.map +1 -0
- package/dist/webserver/index.js +2 -0
- package/dist/webserver/index.js.map +2 -2
- package/dist/webserver/util.d.ts +10 -0
- package/dist/webserver/util.d.ts.map +1 -0
- package/dist/webserver/util.js +5 -2
- package/dist/webserver/util.js.map +2 -2
- package/dist/webserver/webserver.d.ts +93 -0
- package/dist/webserver/webserver.d.ts.map +1 -0
- package/dist/webserver/webserver.interface.d.ts +181 -0
- package/dist/webserver/webserver.interface.d.ts.map +1 -0
- package/dist/webserver/webserver.interface.js.map +1 -1
- package/dist/webserver/webserver.js +30 -33
- package/dist/webserver/webserver.js.map +2 -2
- package/dist/websocket/controller/client/base.d.ts +12 -0
- package/dist/websocket/controller/client/base.d.ts.map +1 -0
- package/dist/websocket/controller/client/base.interface.d.ts +12 -0
- package/dist/websocket/controller/client/base.interface.d.ts.map +1 -0
- package/dist/websocket/controller/server/base.d.ts +13 -0
- package/dist/websocket/controller/server/base.d.ts.map +1 -0
- package/dist/websocket/controller/server/base.interface.d.ts +13 -0
- package/dist/websocket/controller/server/base.interface.d.ts.map +1 -0
- package/dist/websocket/controllers/client/system.d.ts +6 -0
- package/dist/websocket/controllers/client/system.d.ts.map +1 -0
- package/dist/websocket/controllers/server/system.d.ts +7 -0
- package/dist/websocket/controllers/server/system.d.ts.map +1 -0
- package/dist/websocket/index.d.ts +9 -0
- package/dist/websocket/index.d.ts.map +1 -0
- package/dist/websocket/index.js +2 -0
- package/dist/websocket/index.js.map +2 -2
- package/dist/websocket/routes/client/system.d.ts +3 -0
- package/dist/websocket/routes/client/system.d.ts.map +1 -0
- package/dist/websocket/routes/server/system.d.ts +3 -0
- package/dist/websocket/routes/server/system.d.ts.map +1 -0
- package/dist/websocket/utils.d.ts +9 -0
- package/dist/websocket/utils.d.ts.map +1 -0
- package/dist/websocket/websocket-auth.d.ts +17 -0
- package/dist/websocket/websocket-auth.d.ts.map +1 -0
- package/dist/websocket/websocket-auth.js +46 -0
- package/dist/websocket/websocket-auth.js.map +7 -0
- package/dist/websocket/websocket-base.d.ts +19 -0
- package/dist/websocket/websocket-base.d.ts.map +1 -0
- package/dist/websocket/websocket-client-manager.d.ts +53 -0
- package/dist/websocket/websocket-client-manager.d.ts.map +1 -0
- package/dist/websocket/websocket-client-manager.interface.d.ts +8 -0
- package/dist/websocket/websocket-client-manager.interface.d.ts.map +1 -0
- package/dist/websocket/websocket-client-manager.js +6 -5
- package/dist/websocket/websocket-client-manager.js.map +2 -2
- package/dist/websocket/websocket-client.d.ts +64 -0
- package/dist/websocket/websocket-client.d.ts.map +1 -0
- package/dist/websocket/websocket-client.interface.d.ts +14 -0
- package/dist/websocket/websocket-client.interface.d.ts.map +1 -0
- package/dist/websocket/websocket-client.js +97 -3
- package/dist/websocket/websocket-client.js.map +2 -2
- package/dist/websocket/websocket-room-manager.d.ts +32 -0
- package/dist/websocket/websocket-room-manager.d.ts.map +1 -0
- package/dist/websocket/websocket-server.d.ts +102 -0
- package/dist/websocket/websocket-server.d.ts.map +1 -0
- package/dist/websocket/websocket-server.interface.d.ts +16 -0
- package/dist/websocket/websocket-server.interface.d.ts.map +1 -0
- package/dist/websocket/websocket-server.js +62 -50
- package/dist/websocket/websocket-server.js.map +2 -2
- package/dist/websocket/websocket-service.d.ts +44 -0
- package/dist/websocket/websocket-service.d.ts.map +1 -0
- package/dist/websocket/websocket.interface.d.ts +137 -0
- package/dist/websocket/websocket.interface.d.ts.map +1 -0
- package/dist/websocket/websocket.interface.js.map +2 -2
- package/package.json +21 -24
- package/pxl.js +0 -4
|
@@ -4,6 +4,7 @@ import WebSocket from "ws";
|
|
|
4
4
|
import { generateClientId, log, parseServerMessage } from "./utils.js";
|
|
5
5
|
import WebSocketBase from "./websocket-base.js";
|
|
6
6
|
import path from "path";
|
|
7
|
+
import { safeSerializeError } from "../error/error-reporter.js";
|
|
7
8
|
import { baseDir } from "../index.js";
|
|
8
9
|
class WebSocketClient extends WebSocketBase {
|
|
9
10
|
static {
|
|
@@ -24,6 +25,12 @@ class WebSocketClient extends WebSocketBase {
|
|
|
24
25
|
ws;
|
|
25
26
|
clientId;
|
|
26
27
|
isConnected = false;
|
|
28
|
+
reconnectAttempts = 0;
|
|
29
|
+
maxReconnectAttempts = 10;
|
|
30
|
+
reconnectDelay = 1e3;
|
|
31
|
+
// Start with 1 second
|
|
32
|
+
reconnectTimer;
|
|
33
|
+
shouldReconnect = true;
|
|
27
34
|
constructor(props) {
|
|
28
35
|
super();
|
|
29
36
|
this.applicationConfig = props.applicationConfig;
|
|
@@ -75,15 +82,18 @@ class WebSocketClient extends WebSocketBase {
|
|
|
75
82
|
resolve();
|
|
76
83
|
});
|
|
77
84
|
ws.on("message", this.handleIncomingMessage);
|
|
78
|
-
ws.on("close", () => {
|
|
85
|
+
ws.on("close", (code) => {
|
|
79
86
|
this.isConnected = false;
|
|
80
|
-
log("Connection to server closed");
|
|
87
|
+
log("Connection to server closed", { Code: code });
|
|
81
88
|
if (this.options.events?.onDisconnected) {
|
|
82
89
|
this.options.events.onDisconnected({ clientId: this.clientId });
|
|
83
90
|
}
|
|
84
91
|
ws.removeAllListeners();
|
|
85
92
|
this.ws = void 0;
|
|
86
93
|
this.clientId = void 0;
|
|
94
|
+
if (this.shouldReconnect) {
|
|
95
|
+
this.scheduleReconnect();
|
|
96
|
+
}
|
|
87
97
|
});
|
|
88
98
|
ws.on("error", (error) => {
|
|
89
99
|
log("WebSocket error", { error: error.message });
|
|
@@ -132,13 +142,17 @@ class WebSocketClient extends WebSocketBase {
|
|
|
132
142
|
return;
|
|
133
143
|
}
|
|
134
144
|
const webSocketMessage = JSON.stringify(data);
|
|
135
|
-
console.log("SENDING LCIENT MESSAGE: ", webSocketMessage);
|
|
136
145
|
this.ws.send(webSocketMessage, { binary });
|
|
137
146
|
}, "sendClientMessage");
|
|
138
147
|
sendMessage = /* @__PURE__ */ __name((data) => {
|
|
139
148
|
this.sendClientMessage(data);
|
|
140
149
|
}, "sendMessage");
|
|
141
150
|
disconnect() {
|
|
151
|
+
this.shouldReconnect = false;
|
|
152
|
+
if (this.reconnectTimer) {
|
|
153
|
+
clearTimeout(this.reconnectTimer);
|
|
154
|
+
this.reconnectTimer = void 0;
|
|
155
|
+
}
|
|
142
156
|
if (this.ws && this.isConnected) {
|
|
143
157
|
this.ws.removeAllListeners();
|
|
144
158
|
this.ws.close();
|
|
@@ -151,6 +165,86 @@ class WebSocketClient extends WebSocketBase {
|
|
|
151
165
|
isClientConnected() {
|
|
152
166
|
return this.isConnected && this.ws?.readyState === WebSocket.OPEN;
|
|
153
167
|
}
|
|
168
|
+
/**
|
|
169
|
+
* Schedule a reconnection attempt with exponential backoff
|
|
170
|
+
*/
|
|
171
|
+
scheduleReconnect() {
|
|
172
|
+
if (this.reconnectAttempts >= this.maxReconnectAttempts) {
|
|
173
|
+
log("Max reconnection attempts reached", {
|
|
174
|
+
Attempts: this.reconnectAttempts
|
|
175
|
+
});
|
|
176
|
+
if (this.options.events?.onReconnectFailed) {
|
|
177
|
+
this.options.events.onReconnectFailed({
|
|
178
|
+
attempts: this.reconnectAttempts
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const delay = Math.min(this.reconnectDelay * Math.pow(2, this.reconnectAttempts), 3e4);
|
|
184
|
+
this.reconnectAttempts++;
|
|
185
|
+
log("Scheduling reconnection", {
|
|
186
|
+
Attempt: this.reconnectAttempts,
|
|
187
|
+
Delay: `${delay}ms`
|
|
188
|
+
});
|
|
189
|
+
if (this.options.events?.onReconnecting) {
|
|
190
|
+
this.options.events.onReconnecting({
|
|
191
|
+
attempt: this.reconnectAttempts,
|
|
192
|
+
delay
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
this.reconnectTimer = setTimeout(() => {
|
|
196
|
+
this.attemptReconnect();
|
|
197
|
+
}, delay);
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Attempt to reconnect to the server
|
|
201
|
+
*/
|
|
202
|
+
async attemptReconnect() {
|
|
203
|
+
try {
|
|
204
|
+
log("Attempting to reconnect...", {
|
|
205
|
+
Attempt: this.reconnectAttempts
|
|
206
|
+
});
|
|
207
|
+
await this.connectToServer();
|
|
208
|
+
this.reconnectAttempts = 0;
|
|
209
|
+
log("Reconnection successful");
|
|
210
|
+
if (this.options.events?.onReconnected) {
|
|
211
|
+
this.options.events.onReconnected({
|
|
212
|
+
clientId: this.clientId
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
} catch (error) {
|
|
216
|
+
log("Reconnection failed", {
|
|
217
|
+
Error: error instanceof Error ? error.message : safeSerializeError(error)
|
|
218
|
+
});
|
|
219
|
+
this.scheduleReconnect();
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Enable auto-reconnection
|
|
224
|
+
*/
|
|
225
|
+
enableAutoReconnect() {
|
|
226
|
+
this.shouldReconnect = true;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Disable auto-reconnection
|
|
230
|
+
*/
|
|
231
|
+
disableAutoReconnect() {
|
|
232
|
+
this.shouldReconnect = false;
|
|
233
|
+
if (this.reconnectTimer) {
|
|
234
|
+
clearTimeout(this.reconnectTimer);
|
|
235
|
+
this.reconnectTimer = void 0;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Get connection status
|
|
240
|
+
*/
|
|
241
|
+
getConnectionStatus() {
|
|
242
|
+
return {
|
|
243
|
+
isConnected: this.isConnected,
|
|
244
|
+
reconnectAttempts: this.reconnectAttempts,
|
|
245
|
+
autoReconnectEnabled: this.shouldReconnect
|
|
246
|
+
};
|
|
247
|
+
}
|
|
154
248
|
}
|
|
155
249
|
export {
|
|
156
250
|
WebSocketClient as default
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/websocket/websocket-client.ts"],
|
|
4
|
-
"sourcesContent": ["import WebSocket, { type RawData } from 'ws';\nimport type { WebSocketOptions, WebSocketRoute, WebSocketType } from './websocket.interface.js';\nimport type RedisInstance from '../redis/instance.js';\nimport type QueueManager from '../queue/manager.js';\nimport type DatabaseInstance from '../database/instance.js';\nimport type { WebSocketClientProps } from './websocket-client.interface.js';\nimport { generateClientId, log, parseServerMessage } from './utils.js';\nimport WebSocketBase from './websocket-base.js';\nimport type { ApplicationConfig } from '../application/base-application.interface.js';\nimport path from 'path';\nimport { baseDir } from '../index.js';\n\nexport default class WebSocketClient extends WebSocketBase {\n protected defaultRoutes: WebSocketRoute[] = [\n {\n type: 'system',\n action: 'clientList',\n controllerName: 'system',\n },\n ];\n\n private applicationConfig: ApplicationConfig;\n private options: WebSocketOptions;\n private redisInstance: RedisInstance;\n private queueManager: QueueManager;\n private databaseInstance: DatabaseInstance;\n private ws?: WebSocket;\n private clientId?: string;\n private isConnected: boolean = false;\n\n constructor(props: WebSocketClientProps) {\n super();\n\n this.applicationConfig = props.applicationConfig;\n this.options = props.options;\n this.redisInstance = props.redisInstance;\n this.queueManager = props.queueManager;\n this.databaseInstance = props.databaseInstance;\n this.routes = props.routes;\n }\n\n public get type(): WebSocketType {\n return 'client';\n }\n\n public async load(): Promise<void> {\n const libraryControllersDirectory = path.join(baseDir, 'websocket', 'controllers', 'client');\n\n await this.configureRoutes(this.defaultRoutes, libraryControllersDirectory);\n\n await this.configureRoutes(this.routes, this.options.controllersDirectory);\n }\n\n public async connectToServer(): Promise<void> {\n const url = this.options.url;\n // const host = this.options.host;\n // const port = this.options.port;\n\n return new Promise(resolve => {\n const ws = new WebSocket(url);\n\n ws.on('open', () => {\n this.clientId = generateClientId();\n this.isConnected = true;\n\n log('Connected to server', { ID: this.clientId });\n\n if (this.options.events?.onConnected) {\n this.options.events.onConnected({\n ws,\n clientId: this.clientId,\n joinRoom: ({\n userId,\n userType,\n username,\n roomName,\n }: {\n userId?: string;\n userType?: string;\n username: string;\n roomName: string;\n }) => {\n this.sendClientMessage({\n type: 'system',\n action: 'joinRoom',\n data: {\n userId,\n userType,\n username,\n roomName,\n },\n });\n },\n });\n }\n\n resolve();\n });\n\n ws.on('message', this.handleIncomingMessage);\n\n ws.on('close',
|
|
5
|
-
"mappings": ";;AAAA,OAAO,eAAiC;AAMxC,SAAS,kBAAkB,KAAK,0BAA0B;AAC1D,OAAO,mBAAmB;AAE1B,OAAO,UAAU;AACjB,SAAS,eAAe;AAExB,MAAO,wBAAsC,cAAc;AAAA,
|
|
4
|
+
"sourcesContent": ["import WebSocket, { type RawData } from 'ws';\nimport type { WebSocketOptions, WebSocketRoute, WebSocketType } from './websocket.interface.js';\nimport type RedisInstance from '../redis/instance.js';\nimport type QueueManager from '../queue/manager.js';\nimport type DatabaseInstance from '../database/instance.js';\nimport type { WebSocketClientProps } from './websocket-client.interface.js';\nimport { generateClientId, log, parseServerMessage } from './utils.js';\nimport WebSocketBase from './websocket-base.js';\nimport type { ApplicationConfig } from '../application/base-application.interface.js';\nimport path from 'path';\nimport { safeSerializeError } from '../error/error-reporter.js';\nimport { baseDir } from '../index.js';\n\nexport default class WebSocketClient extends WebSocketBase {\n protected defaultRoutes: WebSocketRoute[] = [\n {\n type: 'system',\n action: 'clientList',\n controllerName: 'system',\n },\n ];\n\n private applicationConfig: ApplicationConfig;\n private options: WebSocketOptions;\n private redisInstance: RedisInstance;\n private queueManager: QueueManager;\n private databaseInstance: DatabaseInstance;\n private ws?: WebSocket;\n private clientId?: string;\n private isConnected: boolean = false;\n private reconnectAttempts: number = 0;\n private maxReconnectAttempts: number = 10;\n private reconnectDelay: number = 1000; // Start with 1 second\n private reconnectTimer?: NodeJS.Timeout;\n private shouldReconnect: boolean = true;\n\n constructor(props: WebSocketClientProps) {\n super();\n\n this.applicationConfig = props.applicationConfig;\n this.options = props.options;\n this.redisInstance = props.redisInstance;\n this.queueManager = props.queueManager;\n this.databaseInstance = props.databaseInstance;\n this.routes = props.routes;\n }\n\n public get type(): WebSocketType {\n return 'client';\n }\n\n public async load(): Promise<void> {\n const libraryControllersDirectory = path.join(baseDir, 'websocket', 'controllers', 'client');\n\n await this.configureRoutes(this.defaultRoutes, libraryControllersDirectory);\n\n await this.configureRoutes(this.routes, this.options.controllersDirectory);\n }\n\n public async connectToServer(): Promise<void> {\n const url = this.options.url;\n // const host = this.options.host;\n // const port = this.options.port;\n\n return new Promise(resolve => {\n const ws = new WebSocket(url);\n\n ws.on('open', () => {\n this.clientId = generateClientId();\n this.isConnected = true;\n\n log('Connected to server', { ID: this.clientId });\n\n if (this.options.events?.onConnected) {\n this.options.events.onConnected({\n ws,\n clientId: this.clientId,\n joinRoom: ({\n userId,\n userType,\n username,\n roomName,\n }: {\n userId?: string;\n userType?: string;\n username: string;\n roomName: string;\n }) => {\n this.sendClientMessage({\n type: 'system',\n action: 'joinRoom',\n data: {\n userId,\n userType,\n username,\n roomName,\n },\n });\n },\n });\n }\n\n resolve();\n });\n\n ws.on('message', this.handleIncomingMessage);\n\n ws.on('close', code => {\n this.isConnected = false;\n log('Connection to server closed', { Code: code });\n\n if (this.options.events?.onDisconnected) {\n this.options.events.onDisconnected({ clientId: this.clientId });\n }\n\n // Clean up event listeners to prevent memory leaks\n ws.removeAllListeners();\n this.ws = undefined;\n this.clientId = undefined;\n\n // Attempt to reconnect if not manually disconnected\n if (this.shouldReconnect) {\n this.scheduleReconnect();\n }\n });\n\n ws.on('error', error => {\n log('WebSocket error', { error: error.message });\n\n if (this.options.events?.onError) {\n this.options.events.onError({ error });\n }\n });\n\n this.ws = ws;\n });\n }\n\n protected getControllerDependencies(): {\n sendMessage: (data: unknown) => void;\n redisInstance: RedisInstance;\n queueManager: QueueManager;\n databaseInstance: DatabaseInstance;\n } {\n return {\n sendMessage: this.sendMessage,\n redisInstance: this.redisInstance,\n queueManager: this.queueManager,\n databaseInstance: this.databaseInstance,\n };\n }\n protected shouldPrintRoutes(): boolean {\n return this.options.debug?.printRoutes ?? false;\n }\n\n private handleIncomingMessage = async (message: RawData): Promise<void> => {\n if (!this.ws || !this.clientId) {\n log('WebSocket not initialized or client ID not set');\n\n return;\n }\n\n if (this.options.events?.onMessage) {\n const parsedMessage = parseServerMessage(message);\n\n this.options.events.onMessage({\n ws: this.ws,\n clientId: this.clientId,\n data: parsedMessage as { type: string; action: string; data: unknown },\n redisInstance: this.redisInstance,\n queueManager: this.queueManager,\n databaseInstance: this.databaseInstance,\n });\n }\n\n await this.handleServerMessage(this.ws, message, this.clientId);\n };\n\n protected handleMessageError(clientId: string, error: string): void {\n log(error);\n }\n\n public sendClientMessage = (data: unknown, binary: boolean = false): void => {\n if (!this.ws) {\n log('WebSocket not initialized');\n\n return;\n }\n\n const webSocketMessage = JSON.stringify(data);\n\n this.ws.send(webSocketMessage, { binary });\n };\n\n public sendMessage = (data: unknown): void => {\n this.sendClientMessage(data);\n };\n\n public disconnect(): void {\n // Disable auto-reconnect on manual disconnect\n this.shouldReconnect = false;\n\n // Clear any pending reconnect timer\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n\n if (this.ws && this.isConnected) {\n this.ws.removeAllListeners();\n this.ws.close();\n this.ws = undefined;\n this.clientId = undefined;\n this.isConnected = false;\n log('WebSocket client disconnected');\n }\n }\n\n public isClientConnected(): boolean {\n return this.isConnected && this.ws?.readyState === WebSocket.OPEN;\n }\n\n /**\n * Schedule a reconnection attempt with exponential backoff\n */\n private scheduleReconnect(): void {\n // Don't reconnect if we've exceeded max attempts\n if (this.reconnectAttempts >= this.maxReconnectAttempts) {\n log('Max reconnection attempts reached', {\n Attempts: this.reconnectAttempts,\n });\n\n if (this.options.events?.onReconnectFailed) {\n this.options.events.onReconnectFailed({\n attempts: this.reconnectAttempts,\n });\n }\n\n return;\n }\n\n // Calculate delay with exponential backoff (max 30 seconds)\n const delay = Math.min(this.reconnectDelay * Math.pow(2, this.reconnectAttempts), 30000);\n this.reconnectAttempts++;\n\n log('Scheduling reconnection', {\n Attempt: this.reconnectAttempts,\n Delay: `${delay}ms`,\n });\n\n if (this.options.events?.onReconnecting) {\n this.options.events.onReconnecting({\n attempt: this.reconnectAttempts,\n delay,\n });\n }\n\n this.reconnectTimer = setTimeout(() => {\n this.attemptReconnect();\n }, delay);\n }\n\n /**\n * Attempt to reconnect to the server\n */\n private async attemptReconnect(): Promise<void> {\n try {\n log('Attempting to reconnect...', {\n Attempt: this.reconnectAttempts,\n });\n\n await this.connectToServer();\n\n // Reset reconnect attempts on successful connection\n this.reconnectAttempts = 0;\n\n log('Reconnection successful');\n\n if (this.options.events?.onReconnected) {\n this.options.events.onReconnected({\n clientId: this.clientId,\n });\n }\n } catch (error) {\n log('Reconnection failed', {\n Error: error instanceof Error ? error.message : safeSerializeError(error),\n });\n\n // Schedule next attempt\n this.scheduleReconnect();\n }\n }\n\n /**\n * Enable auto-reconnection\n */\n public enableAutoReconnect(): void {\n this.shouldReconnect = true;\n }\n\n /**\n * Disable auto-reconnection\n */\n public disableAutoReconnect(): void {\n this.shouldReconnect = false;\n\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n }\n\n /**\n * Get connection status\n */\n public getConnectionStatus(): {\n isConnected: boolean;\n reconnectAttempts: number;\n autoReconnectEnabled: boolean;\n } {\n return {\n isConnected: this.isConnected,\n reconnectAttempts: this.reconnectAttempts,\n autoReconnectEnabled: this.shouldReconnect,\n };\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type WebSocketClientManager from './websocket-client-manager.js';
|
|
2
|
+
export default class WebSocketRoomManager {
|
|
3
|
+
private clientManager;
|
|
4
|
+
rooms: Map<string, Set<string>>;
|
|
5
|
+
constructor({ clientManager }: {
|
|
6
|
+
clientManager: WebSocketClientManager;
|
|
7
|
+
});
|
|
8
|
+
addClientToRoom({ clientId, user, roomName, broadcast, }: {
|
|
9
|
+
clientId: string;
|
|
10
|
+
user: any;
|
|
11
|
+
roomName: string;
|
|
12
|
+
broadcast?: boolean;
|
|
13
|
+
}): void;
|
|
14
|
+
removeClientFromRoom({ roomName, clientId, broadcast, }: {
|
|
15
|
+
roomName: string;
|
|
16
|
+
clientId: string;
|
|
17
|
+
broadcast?: boolean;
|
|
18
|
+
}): void;
|
|
19
|
+
removeClientFromAllRooms({ clientId }: {
|
|
20
|
+
clientId: string;
|
|
21
|
+
}): void;
|
|
22
|
+
isClientInRoom({ clientId, roomName }: {
|
|
23
|
+
clientId: string;
|
|
24
|
+
roomName: string;
|
|
25
|
+
}): boolean;
|
|
26
|
+
printRooms(): void;
|
|
27
|
+
getRoomClients({ roomName }: {
|
|
28
|
+
roomName: string;
|
|
29
|
+
}): string[];
|
|
30
|
+
cleanup(): void;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=websocket-room-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket-room-manager.d.ts","sourceRoot":"","sources":["../../src/websocket/websocket-room-manager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,sBAAsB,MAAM,+BAA+B,CAAC;AAExE,MAAM,CAAC,OAAO,OAAO,oBAAoB;IACvC,OAAO,CAAC,aAAa,CAAyB;IAEvC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAa;gBAEvC,EAAE,aAAa,EAAE,EAAE;QAAE,aAAa,EAAE,sBAAsB,CAAA;KAAE;IAIjE,eAAe,CAAC,EACrB,QAAQ,EACR,IAAI,EACJ,QAAQ,EACR,SAAS,GACV,EAAE;QACD,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,GAAG,CAAC;QACV,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,CAAC,EAAE,OAAO,CAAC;KACrB;IAwCM,oBAAoB,CAAC,EAC1B,QAAQ,EACR,QAAQ,EACR,SAAS,GACV,EAAE;QACD,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,CAAC,EAAE,OAAO,CAAC;KACrB;IA0CM,wBAAwB,CAAC,EAAE,QAAQ,EAAE,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE;IAc3D,cAAc,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE;IAY7E,UAAU;IAqCV,cAAc,CAAC,EAAE,QAAQ,EAAE,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,EAAE;IAK5D,OAAO,IAAI,IAAI;CAKvB"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { WebSocketServer as WS, WebSocket } from 'ws';
|
|
2
|
+
import { type WebSocketRoute, type WebSocketType } from './websocket.interface.js';
|
|
3
|
+
import type RedisInstance from '../redis/instance.js';
|
|
4
|
+
import type QueueManager from '../queue/manager.js';
|
|
5
|
+
import type DatabaseInstance from '../database/instance.js';
|
|
6
|
+
import type { WebSocketServerProps } from './websocket-server.interface.js';
|
|
7
|
+
import WebSocketClientManager from './websocket-client-manager.js';
|
|
8
|
+
import WebSocketBase from './websocket-base.js';
|
|
9
|
+
import type { FastifyInstance } from 'fastify';
|
|
10
|
+
export default class WebSocketServer extends WebSocketBase {
|
|
11
|
+
protected defaultRoutes: WebSocketRoute[];
|
|
12
|
+
private server?;
|
|
13
|
+
private abortController;
|
|
14
|
+
private workerId;
|
|
15
|
+
private uniqueInstanceId;
|
|
16
|
+
private applicationConfig;
|
|
17
|
+
private options;
|
|
18
|
+
clientManager: WebSocketClientManager;
|
|
19
|
+
private roomManager;
|
|
20
|
+
private authService;
|
|
21
|
+
get rooms(): Map<string, Set<string>>;
|
|
22
|
+
private redisInstance;
|
|
23
|
+
private queueManager;
|
|
24
|
+
private databaseInstance;
|
|
25
|
+
/** Redis subscriber events */
|
|
26
|
+
private redisSubscriberEvents;
|
|
27
|
+
constructor(props: WebSocketServerProps);
|
|
28
|
+
get type(): WebSocketType;
|
|
29
|
+
private validateWebSocketAuth;
|
|
30
|
+
load(): Promise<void>;
|
|
31
|
+
start({ fastifyServer }: {
|
|
32
|
+
fastifyServer: FastifyInstance;
|
|
33
|
+
}): Promise<{
|
|
34
|
+
server: WS;
|
|
35
|
+
}>;
|
|
36
|
+
stop(): Promise<void>;
|
|
37
|
+
protected getControllerDependencies(): {
|
|
38
|
+
webSocketServer: WebSocketServer;
|
|
39
|
+
redisInstance: RedisInstance;
|
|
40
|
+
queueManager: QueueManager;
|
|
41
|
+
databaseInstance: DatabaseInstance;
|
|
42
|
+
};
|
|
43
|
+
protected shouldPrintRoutes(): boolean;
|
|
44
|
+
private handleServerStart;
|
|
45
|
+
/**
|
|
46
|
+
* Handle subscriber message.
|
|
47
|
+
*/
|
|
48
|
+
private handleSubscriberMessage;
|
|
49
|
+
private handleServerError;
|
|
50
|
+
private handleServerClientConnection;
|
|
51
|
+
leaveRoom({ ws, roomName }: {
|
|
52
|
+
ws: WebSocket;
|
|
53
|
+
roomName: string;
|
|
54
|
+
}): void;
|
|
55
|
+
private onClientConnect;
|
|
56
|
+
private onClientDisconnect;
|
|
57
|
+
private handleServerClientDisconnection;
|
|
58
|
+
private handleClientMessage;
|
|
59
|
+
protected handleMessageError(clientId: string, error: string): void;
|
|
60
|
+
/**
|
|
61
|
+
* Check and disconnect inactive clients based on configuration
|
|
62
|
+
* This helps prevent stale connections from accumulating
|
|
63
|
+
*/
|
|
64
|
+
private checkInactiveClients;
|
|
65
|
+
/**
|
|
66
|
+
* Broadcast a message to all connected WebSocket clients
|
|
67
|
+
* @param data - The data to broadcast (will be JSON stringified)
|
|
68
|
+
* @param excludeClientId - Optional client ID to exclude from broadcast
|
|
69
|
+
*/
|
|
70
|
+
broadcastToAllClients({ data, excludeClientId, }: {
|
|
71
|
+
data: {
|
|
72
|
+
[key: string]: any;
|
|
73
|
+
};
|
|
74
|
+
excludeClientId?: string;
|
|
75
|
+
}): void;
|
|
76
|
+
sendMessageError({ webSocketClientId, error }: {
|
|
77
|
+
webSocketClientId: string;
|
|
78
|
+
error: string;
|
|
79
|
+
}): void;
|
|
80
|
+
private onJoinRoom;
|
|
81
|
+
joinRoom({ ws, userId, userType, username, roomName, }: {
|
|
82
|
+
ws: WebSocket;
|
|
83
|
+
userId?: number;
|
|
84
|
+
userType?: string;
|
|
85
|
+
username?: string;
|
|
86
|
+
roomName: string;
|
|
87
|
+
}): Promise<true | undefined>;
|
|
88
|
+
sendClientMessage: (ws: WebSocket, data: unknown, binary?: boolean) => void;
|
|
89
|
+
sendMessage: ({ data }: {
|
|
90
|
+
data: unknown;
|
|
91
|
+
}) => void;
|
|
92
|
+
sendMessageToAll: ({ data }: {
|
|
93
|
+
data: unknown;
|
|
94
|
+
}) => void;
|
|
95
|
+
sendCustomMessage: ({ data }: {
|
|
96
|
+
data: unknown;
|
|
97
|
+
}) => void;
|
|
98
|
+
getClients({ userType }: {
|
|
99
|
+
userType?: string;
|
|
100
|
+
}): any[];
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=websocket-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket-server.d.ts","sourceRoot":"","sources":["../../src/websocket/websocket-server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ApplicationConfig } from '../application/base-application.interface.js';
|
|
2
|
+
import type DatabaseInstance from '../database/instance.js';
|
|
3
|
+
import type QueueManager from '../queue/manager.js';
|
|
4
|
+
import type { RedisInstance } from '../redis/index.js';
|
|
5
|
+
import type { WebSocketOptions, WebSocketRoute } from './websocket.interface.js';
|
|
6
|
+
export interface WebSocketServerProps {
|
|
7
|
+
uniqueInstanceId: string;
|
|
8
|
+
applicationConfig: ApplicationConfig;
|
|
9
|
+
options: WebSocketOptions;
|
|
10
|
+
redisInstance: RedisInstance;
|
|
11
|
+
queueManager: QueueManager;
|
|
12
|
+
databaseInstance: DatabaseInstance;
|
|
13
|
+
routes: WebSocketRoute[];
|
|
14
|
+
workerId: number | null;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=websocket-server.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket-server.interface.d.ts","sourceRoot":"","sources":["../../src/websocket/websocket-server.interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8CAA8C,CAAC;AACtF,OAAO,KAAK,gBAAgB,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,YAAY,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAEjF,MAAM,WAAW,oBAAoB;IACnC,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,OAAO,EAAE,gBAAgB,CAAC;IAC1B,aAAa,EAAE,aAAa,CAAC;IAC7B,YAAY,EAAE,YAAY,CAAC;IAC3B,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB"}
|
|
@@ -12,8 +12,7 @@ import path from "path";
|
|
|
12
12
|
import { baseDir } from "../index.js";
|
|
13
13
|
import WebSocketRoomManager from "./websocket-room-manager.js";
|
|
14
14
|
import logger from "../logger/logger.js";
|
|
15
|
-
import {
|
|
16
|
-
import Jwt from "../auth/jwt.js";
|
|
15
|
+
import { WebSocketAuthService } from "./websocket-auth.js";
|
|
17
16
|
class WebSocketServer extends WebSocketBase {
|
|
18
17
|
static {
|
|
19
18
|
__name(this, "WebSocketServer");
|
|
@@ -40,6 +39,7 @@ class WebSocketServer extends WebSocketBase {
|
|
|
40
39
|
roomManager = new WebSocketRoomManager({
|
|
41
40
|
clientManager: this.clientManager
|
|
42
41
|
});
|
|
42
|
+
authService;
|
|
43
43
|
get rooms() {
|
|
44
44
|
return this.roomManager.rooms;
|
|
45
45
|
}
|
|
@@ -70,33 +70,13 @@ class WebSocketServer extends WebSocketBase {
|
|
|
70
70
|
this.databaseInstance = props.databaseInstance;
|
|
71
71
|
this.routes = props.routes;
|
|
72
72
|
this.workerId = props.workerId;
|
|
73
|
+
this.authService = new WebSocketAuthService(props.applicationConfig);
|
|
73
74
|
}
|
|
74
75
|
get type() {
|
|
75
76
|
return "server";
|
|
76
77
|
}
|
|
77
78
|
async validateWebSocketAuth(url) {
|
|
78
|
-
|
|
79
|
-
const parsedUrl = new URL(url, "ws://localhost");
|
|
80
|
-
const token = parsedUrl.searchParams.get("token");
|
|
81
|
-
if (!token) {
|
|
82
|
-
return null;
|
|
83
|
-
}
|
|
84
|
-
const jwtSecretKey = this.applicationConfig.auth?.jwtSecretKey;
|
|
85
|
-
if (!jwtSecretKey) {
|
|
86
|
-
throw new Error("JWT secret key not configured");
|
|
87
|
-
}
|
|
88
|
-
const importedJwtSecretKey = await Jwt.importJwtSecretKey({
|
|
89
|
-
jwtSecretKey
|
|
90
|
-
});
|
|
91
|
-
const { payload } = await Jwt.jwtVerify(token, importedJwtSecretKey);
|
|
92
|
-
const userId = parseInt(payload.sub);
|
|
93
|
-
if (isNaN(userId)) {
|
|
94
|
-
throw new Error("Invalid user ID in token");
|
|
95
|
-
}
|
|
96
|
-
return { userId, payload };
|
|
97
|
-
} catch (error) {
|
|
98
|
-
throw new Error(`JWT verification failed: ${error.message}`);
|
|
99
|
-
}
|
|
79
|
+
return this.authService.validateAuth(url);
|
|
100
80
|
}
|
|
101
81
|
async load() {
|
|
102
82
|
const libraryControllersDirectory = path.join(baseDir, "websocket", "controllers", "server");
|
|
@@ -241,10 +221,6 @@ class WebSocketServer extends WebSocketBase {
|
|
|
241
221
|
clientId: parsedMessage.clientId
|
|
242
222
|
// requireWs: true,
|
|
243
223
|
});
|
|
244
|
-
log(
|
|
245
|
-
`GOT A REQUEST TO POTENTIALLY DISCONNECT LCIENT IF THIS CLIENT IS CONNETED HERE, GET CLIENT ------------------------- ${clientToDisconnect ?? "NO CLIENT"}`
|
|
246
|
-
);
|
|
247
|
-
console.log("clientToDisconnect", clientToDisconnect, "workerId: ", this.workerId);
|
|
248
224
|
if (clientToDisconnect) {
|
|
249
225
|
this.clientManager.disconnectClient({
|
|
250
226
|
clientId: parsedMessage.clientId
|
|
@@ -288,7 +264,10 @@ class WebSocketServer extends WebSocketBase {
|
|
|
288
264
|
break;
|
|
289
265
|
}
|
|
290
266
|
case WebSocketRedisSubscriberEvent.QueueJobError: {
|
|
291
|
-
parsedMessage.data =
|
|
267
|
+
parsedMessage.data = {
|
|
268
|
+
...parsedMessage.data ?? {},
|
|
269
|
+
error: parsedMessage.error
|
|
270
|
+
};
|
|
292
271
|
break;
|
|
293
272
|
}
|
|
294
273
|
case WebSocketRedisSubscriberEvent.Custom: {
|
|
@@ -441,7 +420,14 @@ class WebSocketServer extends WebSocketBase {
|
|
|
441
420
|
response: serverMessageResponse?.response
|
|
442
421
|
});
|
|
443
422
|
if (serverMessageResponse?.response && typeof serverMessageResponse.response === "object" && "error" in serverMessageResponse.response) {
|
|
444
|
-
Logger.error({
|
|
423
|
+
Logger.error({
|
|
424
|
+
error: serverMessageResponse.response.error,
|
|
425
|
+
meta: {
|
|
426
|
+
clientId,
|
|
427
|
+
type: serverMessageResponse.type,
|
|
428
|
+
action: serverMessageResponse.action
|
|
429
|
+
}
|
|
430
|
+
});
|
|
445
431
|
}
|
|
446
432
|
}
|
|
447
433
|
} catch (error) {
|
|
@@ -461,11 +447,38 @@ class WebSocketServer extends WebSocketBase {
|
|
|
461
447
|
})
|
|
462
448
|
);
|
|
463
449
|
}
|
|
450
|
+
/**
|
|
451
|
+
* Check and disconnect inactive clients based on configuration
|
|
452
|
+
* This helps prevent stale connections from accumulating
|
|
453
|
+
*/
|
|
464
454
|
checkInactiveClients() {
|
|
465
|
-
|
|
455
|
+
const config = this.options.disconnectInactiveClients;
|
|
456
|
+
if (!config?.enabled || !config.inactiveTime) {
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
if (config.log) {
|
|
466
460
|
log("Checking inactive clients...");
|
|
467
461
|
}
|
|
462
|
+
const now = Date.now();
|
|
463
|
+
const clients = this.clientManager.getClients();
|
|
464
|
+
for (const client of clients) {
|
|
465
|
+
const inactiveTime = now - client.lastActivity;
|
|
466
|
+
if (inactiveTime > config.inactiveTime) {
|
|
467
|
+
this.clientManager.disconnectClient(client.clientId);
|
|
468
|
+
if (config.log) {
|
|
469
|
+
log("Disconnected inactive client", {
|
|
470
|
+
"Client ID": client.clientId,
|
|
471
|
+
"Inactive Time": `${inactiveTime}ms`
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
468
476
|
}
|
|
477
|
+
/**
|
|
478
|
+
* Broadcast a message to all connected WebSocket clients
|
|
479
|
+
* @param data - The data to broadcast (will be JSON stringified)
|
|
480
|
+
* @param excludeClientId - Optional client ID to exclude from broadcast
|
|
481
|
+
*/
|
|
469
482
|
broadcastToAllClients({
|
|
470
483
|
data,
|
|
471
484
|
excludeClientId
|
|
@@ -474,18 +487,18 @@ class WebSocketServer extends WebSocketBase {
|
|
|
474
487
|
log("Server not started when broadcasting to all clients");
|
|
475
488
|
return;
|
|
476
489
|
}
|
|
477
|
-
this.server.clients
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
const clientId = this.clientManager.getClientId({
|
|
481
|
-
ws: client
|
|
482
|
-
});
|
|
483
|
-
excludeClient = clientId === excludeClientId;
|
|
490
|
+
for (const client of this.server.clients) {
|
|
491
|
+
if (client.readyState !== WebSocket.OPEN) {
|
|
492
|
+
continue;
|
|
484
493
|
}
|
|
485
|
-
if (
|
|
486
|
-
|
|
494
|
+
if (excludeClientId) {
|
|
495
|
+
const clientId = this.clientManager.getClientId({ ws: client });
|
|
496
|
+
if (clientId === excludeClientId) {
|
|
497
|
+
continue;
|
|
498
|
+
}
|
|
487
499
|
}
|
|
488
|
-
|
|
500
|
+
client.send(JSON.stringify(data));
|
|
501
|
+
}
|
|
489
502
|
}
|
|
490
503
|
sendMessageError({ webSocketClientId, error }) {
|
|
491
504
|
const client = this.clientManager.getClient({
|
|
@@ -532,14 +545,14 @@ class WebSocketServer extends WebSocketBase {
|
|
|
532
545
|
});
|
|
533
546
|
return;
|
|
534
547
|
}
|
|
535
|
-
const
|
|
536
|
-
if (
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
}
|
|
548
|
+
const canJoinMultipleRooms = this.options.rooms?.clientCanJoinMultipleRooms ?? true;
|
|
549
|
+
if (!canJoinMultipleRooms && client.roomName) {
|
|
550
|
+
this.roomManager.removeClientFromRoom({
|
|
551
|
+
roomName: client.roomName,
|
|
552
|
+
clientId,
|
|
553
|
+
broadcast: false
|
|
554
|
+
// Don't broadcast here, will broadcast after adding to new room
|
|
555
|
+
});
|
|
543
556
|
}
|
|
544
557
|
this.clientManager.updateClient({
|
|
545
558
|
clientId,
|
|
@@ -649,7 +662,6 @@ class WebSocketServer extends WebSocketBase {
|
|
|
649
662
|
...data,
|
|
650
663
|
workerId: this.workerId
|
|
651
664
|
};
|
|
652
|
-
console.log("SEND CUSTOM MESSAGE:", formattedData);
|
|
653
665
|
this.redisInstance.publisherClient.publish(WebSocketRedisSubscriberEvent.Custom, JSON.stringify(formattedData));
|
|
654
666
|
}, "sendCustomMessage");
|
|
655
667
|
getClients({ userType }) {
|