@push.rocks/smartsocket 2.0.27 → 3.0.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/dist_bundle/bundle.js +11562 -7527
- package/dist_bundle/bundle.js.map +4 -4
- package/dist_ts/00_commitinfo_data.d.ts +1 -1
- package/dist_ts/00_commitinfo_data.js +3 -3
- package/dist_ts/interfaces/index.d.ts +1 -0
- package/dist_ts/interfaces/index.js +2 -1
- package/dist_ts/interfaces/message.d.ts +55 -0
- package/dist_ts/interfaces/message.js +2 -0
- package/dist_ts/smartsocket.classes.smartsocket.d.ts +10 -6
- package/dist_ts/smartsocket.classes.smartsocket.js +43 -39
- package/dist_ts/smartsocket.classes.smartsocketclient.d.ts +15 -0
- package/dist_ts/smartsocket.classes.smartsocketclient.js +148 -74
- package/dist_ts/smartsocket.classes.socketconnection.d.ts +15 -4
- package/dist_ts/smartsocket.classes.socketconnection.js +139 -62
- package/dist_ts/smartsocket.classes.socketrequest.js +18 -12
- package/dist_ts/smartsocket.classes.socketserver.d.ts +15 -15
- package/dist_ts/smartsocket.classes.socketserver.js +152 -45
- package/dist_ts/smartsocket.pluginstyped.d.ts +31 -12
- package/package.json +26 -27
- package/readme.md +216 -74
- package/ts/00_commitinfo_data.ts +2 -2
- package/ts/interfaces/index.ts +1 -0
- package/ts/interfaces/message.ts +67 -0
- package/ts/smartsocket.classes.smartsocket.ts +47 -40
- package/ts/smartsocket.classes.smartsocketclient.ts +183 -80
- package/ts/smartsocket.classes.socketconnection.ts +161 -74
- package/ts/smartsocket.classes.socketrequest.ts +18 -11
- package/ts/smartsocket.classes.socketserver.ts +161 -52
- package/ts/smartsocket.pluginstyped.ts +35 -12
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* autocreated commitinfo by @
|
|
2
|
+
* autocreated commitinfo by @push.rocks/commitinfo
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@push.rocks/smartsocket',
|
|
6
|
-
version: '
|
|
6
|
+
version: '3.0.0',
|
|
7
7
|
description: 'Provides easy and secure websocket communication mechanisms, including server and client implementation, function call routing, connection management, and tagging.'
|
|
8
8
|
};
|
|
9
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
9
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx5QkFBeUI7SUFDL0IsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLHFLQUFxSztDQUNuTCxDQUFBIn0=
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export * from './connection.js';
|
|
2
2
|
export * from './tag.js';
|
|
3
|
-
|
|
3
|
+
export * from './message.js';
|
|
4
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9pbnRlcmZhY2VzL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGNBQWMsaUJBQWlCLENBQUM7QUFDaEMsY0FBYyxVQUFVLENBQUM7QUFDekIsY0FBYyxjQUFjLENBQUMifQ==
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message types for the smartsocket protocol
|
|
3
|
+
*/
|
|
4
|
+
export type TMessageType = 'authRequest' | 'auth' | 'authResponse' | 'serverReady' | 'function' | 'functionResponse' | 'tagUpdate';
|
|
5
|
+
/**
|
|
6
|
+
* Base message interface for all smartsocket messages
|
|
7
|
+
*/
|
|
8
|
+
export interface ISocketMessage<T = any> {
|
|
9
|
+
type: TMessageType;
|
|
10
|
+
id?: string;
|
|
11
|
+
payload: T;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Authentication request payload (server -> client)
|
|
15
|
+
*/
|
|
16
|
+
export interface IAuthRequestPayload {
|
|
17
|
+
serverAlias: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Authentication data payload (client -> server)
|
|
21
|
+
*/
|
|
22
|
+
export interface IAuthPayload {
|
|
23
|
+
alias: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Authentication response payload (server -> client)
|
|
27
|
+
*/
|
|
28
|
+
export interface IAuthResponsePayload {
|
|
29
|
+
success: boolean;
|
|
30
|
+
error?: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Function call payload
|
|
34
|
+
*/
|
|
35
|
+
export interface IFunctionCallPayload {
|
|
36
|
+
funcName: string;
|
|
37
|
+
funcData: any;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Tag update payload
|
|
41
|
+
*/
|
|
42
|
+
export interface ITagUpdatePayload {
|
|
43
|
+
tags: {
|
|
44
|
+
[key: string]: any;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Helper type for creating typed messages
|
|
49
|
+
*/
|
|
50
|
+
export type TAuthRequestMessage = ISocketMessage<IAuthRequestPayload>;
|
|
51
|
+
export type TAuthMessage = ISocketMessage<IAuthPayload>;
|
|
52
|
+
export type TAuthResponseMessage = ISocketMessage<IAuthResponsePayload>;
|
|
53
|
+
export type TFunctionMessage = ISocketMessage<IFunctionCallPayload>;
|
|
54
|
+
export type TFunctionResponseMessage = ISocketMessage<IFunctionCallPayload>;
|
|
55
|
+
export type TTagUpdateMessage = ISocketMessage<ITagUpdatePayload>;
|
|
@@ -15,18 +15,26 @@ export declare class Smartsocket {
|
|
|
15
15
|
alias: string;
|
|
16
16
|
smartenv: plugins.smartenv.Smartenv;
|
|
17
17
|
options: ISmartsocketConstructorOptions;
|
|
18
|
-
io: pluginsTyped.socketIo.Server;
|
|
19
18
|
socketConnections: plugins.lik.ObjectMap<SocketConnection>;
|
|
20
19
|
socketFunctions: plugins.lik.ObjectMap<SocketFunction<any>>;
|
|
21
20
|
socketRequests: plugins.lik.ObjectMap<SocketRequest<any>>;
|
|
22
21
|
eventSubject: plugins.smartrx.rxjs.Subject<interfaces.TConnectionStatus>;
|
|
23
22
|
private socketServer;
|
|
24
23
|
constructor(optionsArg: ISmartsocketConstructorOptions);
|
|
25
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Returns WebSocket hooks for integration with smartserve
|
|
26
|
+
* Pass these hooks to SmartServe's websocket config
|
|
27
|
+
*/
|
|
28
|
+
getSmartserveWebSocketHooks(): pluginsTyped.ISmartserveWebSocketHooks;
|
|
26
29
|
/**
|
|
27
30
|
* starts smartsocket
|
|
28
31
|
*/
|
|
29
32
|
start(): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Handle a new WebSocket connection
|
|
35
|
+
* Called by SocketServer when a new connection is established
|
|
36
|
+
*/
|
|
37
|
+
handleNewConnection(socket: WebSocket | pluginsTyped.ws.WebSocket): Promise<void>;
|
|
30
38
|
/**
|
|
31
39
|
* stops smartsocket
|
|
32
40
|
*/
|
|
@@ -36,8 +44,4 @@ export declare class Smartsocket {
|
|
|
36
44
|
*/
|
|
37
45
|
clientCall<T extends plugins.typedrequestInterfaces.ITypedRequest>(functionNameArg: T['method'], dataArg: T['request'], targetSocketConnectionArg: SocketConnection): Promise<T['response']>;
|
|
38
46
|
addSocketFunction(socketFunction: SocketFunction<any>): void;
|
|
39
|
-
/**
|
|
40
|
-
* the standard handler for new socket connections
|
|
41
|
-
*/
|
|
42
|
-
private _handleSocketConnection;
|
|
43
47
|
}
|
|
@@ -18,25 +18,53 @@ export class Smartsocket {
|
|
|
18
18
|
this.options = optionsArg;
|
|
19
19
|
this.alias = plugins.isounique.uni(this.options.alias);
|
|
20
20
|
}
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Returns WebSocket hooks for integration with smartserve
|
|
23
|
+
* Pass these hooks to SmartServe's websocket config
|
|
24
|
+
*/
|
|
25
|
+
getSmartserveWebSocketHooks() {
|
|
26
|
+
return this.socketServer.getSmartserveWebSocketHooks();
|
|
23
27
|
}
|
|
24
28
|
/**
|
|
25
29
|
* starts smartsocket
|
|
26
30
|
*/
|
|
27
31
|
async start() {
|
|
28
|
-
const socketIoModule = await this.smartenv.getSafeNodeModule('socket.io');
|
|
29
|
-
this.io = new socketIoModule.Server(await this.socketServer.getServerForSocketIo(), {
|
|
30
|
-
cors: {
|
|
31
|
-
allowedHeaders: '*',
|
|
32
|
-
methods: '*',
|
|
33
|
-
origin: '*',
|
|
34
|
-
},
|
|
35
|
-
});
|
|
36
32
|
await this.socketServer.start();
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Handle a new WebSocket connection
|
|
36
|
+
* Called by SocketServer when a new connection is established
|
|
37
|
+
*/
|
|
38
|
+
async handleNewConnection(socket) {
|
|
39
|
+
const socketConnection = new SocketConnection({
|
|
40
|
+
alias: undefined,
|
|
41
|
+
authenticated: false,
|
|
42
|
+
side: 'server',
|
|
43
|
+
smartsocketHost: this,
|
|
44
|
+
socket: socket,
|
|
39
45
|
});
|
|
46
|
+
logger.log('info', 'Socket connected. Trying to authenticate...');
|
|
47
|
+
this.socketConnections.add(socketConnection);
|
|
48
|
+
// Handle disconnection
|
|
49
|
+
const handleClose = () => {
|
|
50
|
+
this.socketConnections.remove(socketConnection);
|
|
51
|
+
socketConnection.eventSubject.next('disconnected');
|
|
52
|
+
};
|
|
53
|
+
socket.addEventListener('close', handleClose);
|
|
54
|
+
socket.addEventListener('error', handleClose);
|
|
55
|
+
try {
|
|
56
|
+
await socketConnection.authenticate();
|
|
57
|
+
await socketConnection.listenToFunctionRequests();
|
|
58
|
+
// Signal that the server is ready
|
|
59
|
+
socketConnection.sendMessage({
|
|
60
|
+
type: 'serverReady',
|
|
61
|
+
payload: {},
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
logger.log('warn', `Authentication failed: ${err}`);
|
|
66
|
+
this.socketConnections.remove(socketConnection);
|
|
67
|
+
}
|
|
40
68
|
}
|
|
41
69
|
/**
|
|
42
70
|
* stops smartsocket
|
|
@@ -50,9 +78,8 @@ export class Smartsocket {
|
|
|
50
78
|
}
|
|
51
79
|
});
|
|
52
80
|
this.socketConnections.wipe();
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
this.socketServer.stop();
|
|
81
|
+
// stop the corresponding server
|
|
82
|
+
await this.socketServer.stop();
|
|
56
83
|
}
|
|
57
84
|
// communication
|
|
58
85
|
/**
|
|
@@ -75,28 +102,5 @@ export class Smartsocket {
|
|
|
75
102
|
addSocketFunction(socketFunction) {
|
|
76
103
|
this.socketFunctions.add(socketFunction);
|
|
77
104
|
}
|
|
78
|
-
/**
|
|
79
|
-
* the standard handler for new socket connections
|
|
80
|
-
*/
|
|
81
|
-
async _handleSocketConnection(socketArg) {
|
|
82
|
-
const socketConnection = new SocketConnection({
|
|
83
|
-
alias: undefined,
|
|
84
|
-
authenticated: false,
|
|
85
|
-
side: 'server',
|
|
86
|
-
smartsocketHost: this,
|
|
87
|
-
socket: socketArg,
|
|
88
|
-
});
|
|
89
|
-
logger.log('info', 'Socket connected. Trying to authenticate...');
|
|
90
|
-
this.socketConnections.add(socketConnection);
|
|
91
|
-
const disconnectSubscription = socketConnection.eventSubject.subscribe((eventArg) => {
|
|
92
|
-
if (eventArg === 'disconnected') {
|
|
93
|
-
this.socketConnections.remove(socketConnection);
|
|
94
|
-
disconnectSubscription.unsubscribe();
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
await socketConnection.authenticate();
|
|
98
|
-
await socketConnection.listenToFunctionRequests();
|
|
99
|
-
await socketConnection.socket.emit('serverFullyReactive');
|
|
100
|
-
}
|
|
101
105
|
}
|
|
102
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
106
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRzb2NrZXQuY2xhc3Nlcy5zbWFydHNvY2tldC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0c29ja2V0LmNsYXNzZXMuc21hcnRzb2NrZXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSwwQkFBMEIsQ0FBQztBQUNwRCxPQUFPLEtBQUssWUFBWSxNQUFNLCtCQUErQixDQUFDO0FBQzlELE9BQU8sS0FBSyxVQUFVLE1BQU0sdUJBQXVCLENBQUM7QUFFcEQsVUFBVTtBQUNWLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDJDQUEyQyxDQUFDO0FBQzdFLE9BQU8sRUFFTCxjQUFjLEdBRWYsTUFBTSx5Q0FBeUMsQ0FBQztBQUNqRCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sd0NBQXdDLENBQUM7QUFDdkUsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHVDQUF1QyxDQUFDO0FBRXJFLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQU9sRCxNQUFNLE9BQU8sV0FBVztJQWV0QixZQUFZLFVBQTBDO1FBVi9DLGFBQVEsR0FBRyxJQUFJLE9BQU8sQ0FBQyxRQUFRLENBQUMsUUFBUSxFQUFFLENBQUM7UUFFM0Msc0JBQWlCLEdBQUcsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLFNBQVMsRUFBb0IsQ0FBQztRQUNsRSxvQkFBZSxHQUFHLElBQUksT0FBTyxDQUFDLEdBQUcsQ0FBQyxTQUFTLEVBQXVCLENBQUM7UUFDbkUsbUJBQWMsR0FBRyxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsU0FBUyxFQUFzQixDQUFDO1FBRWpFLGlCQUFZLEdBQUcsSUFBSSxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQWdDLENBQUM7UUFFL0UsaUJBQVksR0FBRyxJQUFJLFlBQVksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUc1QyxJQUFJLENBQUMsT0FBTyxHQUFH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
|
|
@@ -11,6 +11,9 @@ export interface ISmartsocketClientOptions {
|
|
|
11
11
|
url: string;
|
|
12
12
|
alias: string;
|
|
13
13
|
autoReconnect?: boolean;
|
|
14
|
+
maxRetries?: number;
|
|
15
|
+
initialBackoffDelay?: number;
|
|
16
|
+
maxBackoffDelay?: number;
|
|
14
17
|
}
|
|
15
18
|
export declare class SmartsocketClient {
|
|
16
19
|
shortId: string;
|
|
@@ -20,6 +23,11 @@ export declare class SmartsocketClient {
|
|
|
20
23
|
serverUrl: string;
|
|
21
24
|
serverPort: number;
|
|
22
25
|
autoReconnect: boolean;
|
|
26
|
+
maxRetries: number;
|
|
27
|
+
initialBackoffDelay: number;
|
|
28
|
+
maxBackoffDelay: number;
|
|
29
|
+
currentRetryCount: number;
|
|
30
|
+
currentBackoffDelay: number;
|
|
23
31
|
eventSubject: plugins.smartrx.rxjs.Subject<interfaces.TConnectionStatus>;
|
|
24
32
|
eventStatus: interfaces.TConnectionStatus;
|
|
25
33
|
socketFunctions: plugins.lik.ObjectMap<SocketFunction<any>>;
|
|
@@ -41,11 +49,14 @@ export declare class SmartsocketClient {
|
|
|
41
49
|
removeTagById(tagIdArg: interfaces.ITag['id']): Promise<void>;
|
|
42
50
|
constructor(optionsArg: ISmartsocketClientOptions);
|
|
43
51
|
addSocketFunction(socketFunction: SocketFunction<any>): void;
|
|
52
|
+
private isReconnecting;
|
|
44
53
|
/**
|
|
45
54
|
* connect the client to the server
|
|
46
55
|
*/
|
|
47
56
|
connect(): Promise<unknown>;
|
|
48
57
|
private disconnectRunning;
|
|
58
|
+
private currentSocket;
|
|
59
|
+
private connectionAttemptId;
|
|
49
60
|
/**
|
|
50
61
|
* disconnect from the server
|
|
51
62
|
*/
|
|
@@ -61,4 +72,8 @@ export declare class SmartsocketClient {
|
|
|
61
72
|
*/
|
|
62
73
|
serverCall<T extends plugins.typedrequestInterfaces.ITypedRequest>(functionNameArg: T['method'], dataArg: T['request']): Promise<T['response']>;
|
|
63
74
|
private updateStatus;
|
|
75
|
+
/**
|
|
76
|
+
* Resets the reconnection state
|
|
77
|
+
*/
|
|
78
|
+
resetReconnectionState(): void;
|
|
64
79
|
}
|
|
@@ -40,6 +40,7 @@ export class SmartsocketClient {
|
|
|
40
40
|
this.shortId = plugins.isounique.uni();
|
|
41
41
|
// the shortId of the remote we connect to
|
|
42
42
|
this.remoteShortId = null;
|
|
43
|
+
this.currentRetryCount = 0;
|
|
43
44
|
// status handling
|
|
44
45
|
this.eventSubject = new plugins.smartrx.rxjs.Subject();
|
|
45
46
|
this.eventStatus = 'new';
|
|
@@ -47,11 +48,18 @@ export class SmartsocketClient {
|
|
|
47
48
|
this.socketRequests = new plugins.lik.ObjectMap();
|
|
48
49
|
// tagStore
|
|
49
50
|
this.tagStore = {};
|
|
51
|
+
this.isReconnecting = false;
|
|
50
52
|
this.disconnectRunning = false;
|
|
53
|
+
this.currentSocket = null;
|
|
54
|
+
this.connectionAttemptId = 0; // Increment on each connect attempt to invalidate old timers
|
|
51
55
|
this.alias = optionsArg.alias;
|
|
52
56
|
this.serverUrl = optionsArg.url;
|
|
53
57
|
this.serverPort = optionsArg.port;
|
|
54
58
|
this.autoReconnect = optionsArg.autoReconnect;
|
|
59
|
+
this.maxRetries = optionsArg.maxRetries ?? 100; // Default to 100 retries
|
|
60
|
+
this.initialBackoffDelay = optionsArg.initialBackoffDelay ?? 1000; // Default to 1 second
|
|
61
|
+
this.maxBackoffDelay = optionsArg.maxBackoffDelay ?? 60000; // Default to 1 minute
|
|
62
|
+
this.currentBackoffDelay = this.initialBackoffDelay;
|
|
55
63
|
}
|
|
56
64
|
addSocketFunction(socketFunction) {
|
|
57
65
|
this.socketFunctions.add(socketFunction);
|
|
@@ -60,91 +68,127 @@ export class SmartsocketClient {
|
|
|
60
68
|
* connect the client to the server
|
|
61
69
|
*/
|
|
62
70
|
async connect() {
|
|
71
|
+
// Only reset retry counters on fresh connection (not during auto-reconnect)
|
|
72
|
+
if (!this.isReconnecting) {
|
|
73
|
+
this.currentRetryCount = 0;
|
|
74
|
+
this.currentBackoffDelay = this.initialBackoffDelay;
|
|
75
|
+
}
|
|
76
|
+
this.isReconnecting = false;
|
|
63
77
|
const done = plugins.smartpromise.defer();
|
|
64
78
|
const smartenvInstance = new plugins.smartenv.Smartenv();
|
|
65
|
-
const socketIoClient = await smartenvInstance.getEnvAwareModule({
|
|
66
|
-
nodeModuleName: 'socket.io-client',
|
|
67
|
-
webUrlArg: 'https://cdn.jsdelivr.net/npm/socket.io-client@4/dist/socket.io.js',
|
|
68
|
-
getFunction: () => {
|
|
69
|
-
const socketIoBrowserModule = globalThis.io;
|
|
70
|
-
// console.log('loaded socket.io for browser');
|
|
71
|
-
return socketIoBrowserModule;
|
|
72
|
-
},
|
|
73
|
-
});
|
|
74
|
-
// console.log(socketIoClient);
|
|
75
79
|
logger.log('info', 'trying to connect...');
|
|
76
|
-
|
|
80
|
+
// Construct WebSocket URL
|
|
81
|
+
const protocol = this.serverUrl.startsWith('https') ? 'wss' : 'ws';
|
|
82
|
+
const host = this.serverUrl.replace(/^https?:\/\//, '');
|
|
83
|
+
const socketUrl = `${protocol}://${host}:${this.serverPort}`;
|
|
84
|
+
// Get WebSocket implementation (native in browser, ws in Node)
|
|
85
|
+
let WebSocketClass;
|
|
86
|
+
if (typeof WebSocket !== 'undefined') {
|
|
87
|
+
// Browser environment
|
|
88
|
+
WebSocketClass = WebSocket;
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
// Node.js environment
|
|
92
|
+
const wsModule = await smartenvInstance.getSafeNodeModule('ws');
|
|
93
|
+
WebSocketClass = wsModule.default || wsModule;
|
|
94
|
+
}
|
|
95
|
+
const socket = new WebSocketClass(socketUrl);
|
|
96
|
+
this.currentSocket = socket;
|
|
77
97
|
this.socketConnection = new SocketConnection({
|
|
78
98
|
alias: this.alias,
|
|
79
99
|
authenticated: false,
|
|
80
100
|
side: 'client',
|
|
81
101
|
smartsocketHost: this,
|
|
82
|
-
socket:
|
|
83
|
-
.connect(socketUrl, {
|
|
84
|
-
multiplex: true,
|
|
85
|
-
rememberUpgrade: true,
|
|
86
|
-
autoConnect: false,
|
|
87
|
-
reconnectionAttempts: 0,
|
|
88
|
-
rejectUnauthorized: socketUrl.startsWith('https://localhost') ? false : true,
|
|
89
|
-
})
|
|
90
|
-
.open(),
|
|
102
|
+
socket: socket,
|
|
91
103
|
});
|
|
104
|
+
// Increment attempt ID to invalidate any pending timers from previous attempts
|
|
105
|
+
this.connectionAttemptId++;
|
|
106
|
+
const currentAttemptId = this.connectionAttemptId;
|
|
92
107
|
const timer = new plugins.smarttime.Timer(5000);
|
|
93
108
|
timer.start();
|
|
94
109
|
timer.completed.then(() => {
|
|
95
|
-
this
|
|
96
|
-
|
|
97
|
-
|
|
110
|
+
// Only fire timeout if this is still the current connection attempt
|
|
111
|
+
if (currentAttemptId === this.connectionAttemptId && this.eventStatus !== 'connected') {
|
|
112
|
+
this.updateStatus('timedOut');
|
|
113
|
+
logger.log('warn', 'connection to server timed out.');
|
|
114
|
+
this.disconnect(true);
|
|
115
|
+
}
|
|
98
116
|
});
|
|
99
|
-
//
|
|
100
|
-
|
|
117
|
+
// Handle connection open
|
|
118
|
+
socket.addEventListener('open', () => {
|
|
101
119
|
timer.reset();
|
|
102
|
-
logger.log('info', `server ${dataArg.serverAlias} requested authentication`);
|
|
103
|
-
// lets register the authenticated event
|
|
104
|
-
this.socketConnection.socket.on('authenticated', async () => {
|
|
105
|
-
this.remoteShortId = dataArg.serverAlias;
|
|
106
|
-
logger.log('info', 'client is authenticated');
|
|
107
|
-
this.socketConnection.authenticated = true;
|
|
108
|
-
await this.socketConnection.listenToFunctionRequests();
|
|
109
|
-
});
|
|
110
|
-
this.socketConnection.socket.on('serverFullyReactive', async () => {
|
|
111
|
-
// lets take care of retagging
|
|
112
|
-
const oldTagStore = this.tagStore;
|
|
113
|
-
this.tagStoreSubscription?.unsubscribe();
|
|
114
|
-
for (const keyArg of Object.keys(this.tagStore)) {
|
|
115
|
-
this.socketConnection.addTag(this.tagStore[keyArg]);
|
|
116
|
-
}
|
|
117
|
-
this.tagStoreSubscription = this.socketConnection.tagStoreObservable.subscribe((tagStoreArg) => {
|
|
118
|
-
this.tagStore = tagStoreArg;
|
|
119
|
-
});
|
|
120
|
-
for (const tag of Object.keys(oldTagStore)) {
|
|
121
|
-
await this.addTag(oldTagStore[tag]);
|
|
122
|
-
}
|
|
123
|
-
this.updateStatus('connected');
|
|
124
|
-
done.resolve();
|
|
125
|
-
});
|
|
126
|
-
// lets register the forbidden event
|
|
127
|
-
this.socketConnection.socket.on('forbidden', async () => {
|
|
128
|
-
logger.log('warn', `disconnecting due to being forbidden to use the ressource`);
|
|
129
|
-
await this.disconnect();
|
|
130
|
-
});
|
|
131
|
-
// lets provide the actual auth data
|
|
132
|
-
this.socketConnection.socket.emit('dataAuth', {
|
|
133
|
-
alias: this.alias,
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
// handle connection
|
|
137
|
-
this.socketConnection.socket.on('connect', async () => { });
|
|
138
|
-
// handle disconnection and errors
|
|
139
|
-
this.socketConnection.socket.on('disconnect', async () => {
|
|
140
|
-
await this.disconnect(true);
|
|
141
120
|
});
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
121
|
+
// Handle messages
|
|
122
|
+
socket.addEventListener('message', async (event) => {
|
|
123
|
+
try {
|
|
124
|
+
const data = typeof event.data === 'string' ? event.data : event.data.toString();
|
|
125
|
+
const message = JSON.parse(data);
|
|
126
|
+
switch (message.type) {
|
|
127
|
+
case 'authRequest':
|
|
128
|
+
timer.reset();
|
|
129
|
+
const authRequestPayload = message.payload;
|
|
130
|
+
logger.log('info', `server ${authRequestPayload.serverAlias} requested authentication`);
|
|
131
|
+
this.remoteShortId = authRequestPayload.serverAlias;
|
|
132
|
+
// Send authentication data
|
|
133
|
+
this.socketConnection.sendMessage({
|
|
134
|
+
type: 'auth',
|
|
135
|
+
payload: { alias: this.alias },
|
|
136
|
+
});
|
|
137
|
+
break;
|
|
138
|
+
case 'authResponse':
|
|
139
|
+
const authResponse = message.payload;
|
|
140
|
+
if (authResponse.success) {
|
|
141
|
+
logger.log('info', 'client is authenticated');
|
|
142
|
+
this.socketConnection.authenticated = true;
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
logger.log('warn', `authentication failed: ${authResponse.error}`);
|
|
146
|
+
await this.disconnect();
|
|
147
|
+
}
|
|
148
|
+
break;
|
|
149
|
+
case 'serverReady':
|
|
150
|
+
// Set up function request listening
|
|
151
|
+
await this.socketConnection.listenToFunctionRequests();
|
|
152
|
+
// Handle retagging
|
|
153
|
+
const oldTagStore = this.tagStore;
|
|
154
|
+
this.tagStoreSubscription?.unsubscribe();
|
|
155
|
+
for (const keyArg of Object.keys(this.tagStore)) {
|
|
156
|
+
this.socketConnection.addTag(this.tagStore[keyArg]);
|
|
157
|
+
}
|
|
158
|
+
this.tagStoreSubscription = this.socketConnection.tagStoreObservable.subscribe((tagStoreArg) => {
|
|
159
|
+
this.tagStore = tagStoreArg;
|
|
160
|
+
});
|
|
161
|
+
for (const tag of Object.keys(oldTagStore)) {
|
|
162
|
+
await this.addTag(oldTagStore[tag]);
|
|
163
|
+
}
|
|
164
|
+
this.updateStatus('connected');
|
|
165
|
+
done.resolve();
|
|
166
|
+
break;
|
|
167
|
+
default:
|
|
168
|
+
// Other messages are handled by SocketConnection
|
|
169
|
+
this.socketConnection.handleMessage(message);
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
catch (err) {
|
|
174
|
+
// Not a valid JSON message, ignore
|
|
175
|
+
}
|
|
147
176
|
});
|
|
177
|
+
// Handle disconnection and errors
|
|
178
|
+
const closeHandler = async () => {
|
|
179
|
+
// Only handle close if this is still the current socket and we're not already disconnecting
|
|
180
|
+
if (this.currentSocket === socket && !this.disconnectRunning) {
|
|
181
|
+
logger.log('info', `SocketConnection with >alias ${this.alias} on >side client disconnected`);
|
|
182
|
+
await this.disconnect(true);
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
const errorHandler = async () => {
|
|
186
|
+
if (this.currentSocket === socket && !this.disconnectRunning) {
|
|
187
|
+
await this.disconnect(true);
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
socket.addEventListener('close', closeHandler);
|
|
191
|
+
socket.addEventListener('error', errorHandler);
|
|
148
192
|
return done.promise;
|
|
149
193
|
}
|
|
150
194
|
/**
|
|
@@ -157,12 +201,15 @@ export class SmartsocketClient {
|
|
|
157
201
|
this.disconnectRunning = true;
|
|
158
202
|
this.updateStatus('disconnecting');
|
|
159
203
|
this.tagStoreSubscription?.unsubscribe();
|
|
204
|
+
// Store reference to current socket before cleanup
|
|
205
|
+
const socketToClose = this.currentSocket;
|
|
206
|
+
this.currentSocket = null;
|
|
160
207
|
if (this.socketConnection) {
|
|
161
208
|
await this.socketConnection.disconnect();
|
|
162
209
|
this.socketConnection = undefined;
|
|
163
210
|
logger.log('ok', 'disconnected socket!');
|
|
164
211
|
}
|
|
165
|
-
else {
|
|
212
|
+
else if (!socketToClose) {
|
|
166
213
|
this.disconnectRunning = false;
|
|
167
214
|
logger.log('warn', 'tried to disconnect, without a SocketConnection');
|
|
168
215
|
return;
|
|
@@ -171,9 +218,23 @@ export class SmartsocketClient {
|
|
|
171
218
|
this.remoteShortId = null;
|
|
172
219
|
if (this.autoReconnect && useAutoReconnectSetting && this.eventStatus !== 'connecting') {
|
|
173
220
|
this.updateStatus('connecting');
|
|
174
|
-
|
|
175
|
-
|
|
221
|
+
// Check if we've exceeded the maximum number of retries
|
|
222
|
+
if (this.currentRetryCount >= this.maxRetries) {
|
|
223
|
+
logger.log('warn', `Maximum reconnection attempts (${this.maxRetries}) reached. Giving up.`);
|
|
224
|
+
this.disconnectRunning = false;
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
// Increment retry counter
|
|
228
|
+
this.currentRetryCount++;
|
|
229
|
+
// Calculate backoff with jitter (±20% randomness)
|
|
230
|
+
const jitter = this.currentBackoffDelay * 0.2 * (Math.random() * 2 - 1);
|
|
231
|
+
const delay = Math.min(this.currentBackoffDelay + jitter, this.maxBackoffDelay);
|
|
232
|
+
logger.log('info', `Reconnect attempt ${this.currentRetryCount}/${this.maxRetries} in ${Math.round(delay)}ms`);
|
|
233
|
+
// Apply exponential backoff for next time (doubling with each attempt)
|
|
234
|
+
this.currentBackoffDelay = Math.min(this.currentBackoffDelay * 2, this.maxBackoffDelay);
|
|
235
|
+
await plugins.smartdelay.delayFor(delay);
|
|
176
236
|
this.disconnectRunning = false;
|
|
237
|
+
this.isReconnecting = true;
|
|
177
238
|
await this.connect();
|
|
178
239
|
}
|
|
179
240
|
else {
|
|
@@ -185,6 +246,8 @@ export class SmartsocketClient {
|
|
|
185
246
|
*/
|
|
186
247
|
async stop() {
|
|
187
248
|
this.autoReconnect = false;
|
|
249
|
+
this.currentRetryCount = 0;
|
|
250
|
+
this.currentBackoffDelay = this.initialBackoffDelay;
|
|
188
251
|
await this.disconnect();
|
|
189
252
|
}
|
|
190
253
|
/**
|
|
@@ -193,7 +256,6 @@ export class SmartsocketClient {
|
|
|
193
256
|
* @param dataArg
|
|
194
257
|
*/
|
|
195
258
|
async serverCall(functionNameArg, dataArg) {
|
|
196
|
-
const done = plugins.smartpromise.defer();
|
|
197
259
|
const socketRequest = new SocketRequest(this, {
|
|
198
260
|
side: 'requesting',
|
|
199
261
|
originSocketConnection: this.socketConnection,
|
|
@@ -212,6 +274,18 @@ export class SmartsocketClient {
|
|
|
212
274
|
this.eventSubject.next(statusArg);
|
|
213
275
|
}
|
|
214
276
|
this.eventStatus = statusArg;
|
|
277
|
+
// Reset reconnection state when connection is successful
|
|
278
|
+
if (statusArg === 'connected') {
|
|
279
|
+
this.currentRetryCount = 0;
|
|
280
|
+
this.currentBackoffDelay = this.initialBackoffDelay;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Resets the reconnection state
|
|
285
|
+
*/
|
|
286
|
+
resetReconnectionState() {
|
|
287
|
+
this.currentRetryCount = 0;
|
|
288
|
+
this.currentBackoffDelay = this.initialBackoffDelay;
|
|
215
289
|
}
|
|
216
290
|
}
|
|
217
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRzb2NrZXQuY2xhc3Nlcy5zbWFydHNvY2tldGNsaWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0c29ja2V0LmNsYXNzZXMuc21hcnRzb2NrZXRjbGllbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSwwQkFBMEIsQ0FBQztBQUNwRCxPQUFPLEtBQUssWUFBWSxNQUFNLCtCQUErQixDQUFDO0FBQzlELE9BQU8sS0FBSyxVQUFVLE1BQU0sdUJBQXVCLENBQUM7QUFFcEQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sMkNBQTJDLENBQUM7QUFDN0UsT0FBTyxFQUVMLGNBQWMsR0FDZixNQUFNLHlDQUF5QyxDQUFDO0FBQ2pELE9BQU8sRUFBaUMsYUFBYSxFQUFFLE1BQU0sd0NBQXdDLENBQUM7QUFDdEcsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBWWxELE1BQU0sT0FBTyxpQkFBaUI7SUF3QjVCOztPQUVHO0lBQ0ksS0FBSyxDQUFDLE1BQU0sQ0FBQyxNQUF1QjtRQUN6QyxJQUFJLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1lBQzFCLE1BQU0sSUFBSSxDQUFDLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUM3QyxDQUFDO2FBQU0sQ0FBQztZQUNOLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxHQUFHLE1BQU0sQ0FBQztRQUNwQyxDQUFDO0lBQ0gsQ0FBQztJQUVEOzs7T0FHRztJQUNJLEtBQUssQ0FBQyxVQUFVLENBQUMsUUFBK0I7UUFDckQsT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQ2pDLENBQUM7SUFFRDs7T0FFRztJQUNJLEtBQUssQ0FBQyxhQUFhLENBQUMsUUFBK0I7UUFDeEQsSUFBSSxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztZQUMx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
|
|
291
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRzb2NrZXQuY2xhc3Nlcy5zbWFydHNvY2tldGNsaWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0c29ja2V0LmNsYXNzZXMuc21hcnRzb2NrZXRjbGllbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSwwQkFBMEIsQ0FBQztBQUNwRCxPQUFPLEtBQUssWUFBWSxNQUFNLCtCQUErQixDQUFDO0FBQzlELE9BQU8sS0FBSyxVQUFVLE1BQU0sdUJBQXVCLENBQUM7QUFFcEQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sMkNBQTJDLENBQUM7QUFDN0UsT0FBTyxFQUVMLGNBQWMsR0FDZixNQUFNLHlDQUF5QyxDQUFDO0FBQ2pELE9BQU8sRUFBaUMsYUFBYSxFQUFFLE1BQU0sd0NBQXdDLENBQUM7QUFDdEcsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBZWxELE1BQU0sT0FBTyxpQkFBaUI7SUE2QjVCOztPQUVHO0lBQ0ksS0FBSyxDQUFDLE1BQU0sQ0FBQyxNQUF1QjtRQUN6QyxJQUFJLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1lBQzFCLE1BQU0sSUFBSSxDQUFDLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUM3QyxDQUFDO2FBQU0sQ0FBQztZQUNOLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxHQUFHLE1BQU0sQ0FBQztRQUNwQyxDQUFDO0lBQ0gsQ0FBQztJQUVEOzs7T0FHRztJQUNJLEtBQUssQ0FBQyxVQUFVLENBQUMsUUFBK0I7UUFDckQsT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQ2pDLENBQUM7SUFFRDs7T0FFRztJQUNJLEtBQUssQ0FBQyxhQUFhLENBQUMsUUFBK0I7UUFDeEQsSUFBSSxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztZQUMx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
|