@livedigital/client 2.4.0-beta.2 → 2.4.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/README.md +1 -2
- package/dist/engine/index.d.ts +0 -4
- package/dist/engine/network/Socket.d.ts +0 -1
- package/dist/index.es.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/engine/index.ts +13 -56
- package/src/engine/network/Socket.ts +4 -10
- package/dist/helpers/datetime.d.ts +0 -5
- package/dist/helpers/retry.d.ts +0 -10
- package/src/helpers/datetime.ts +0 -13
- package/src/helpers/retry.ts +0 -50
package/package.json
CHANGED
package/src/engine/index.ts
CHANGED
|
@@ -26,7 +26,6 @@ import { GetNodeRequest } from '../types/network';
|
|
|
26
26
|
import VideoTrack from './media/tracks/VideoTrack';
|
|
27
27
|
import AudioTrack from './media/tracks/AudioTrack';
|
|
28
28
|
import PeerTrack from './media/tracks/PeerTrack';
|
|
29
|
-
import { retryAsync } from '../helpers/retry';
|
|
30
29
|
|
|
31
30
|
type EngineParams = {
|
|
32
31
|
clientEventEmitter: EnhancedEventEmitter,
|
|
@@ -119,7 +118,7 @@ class Engine {
|
|
|
119
118
|
this.network.socket.observer.on('state', ({ state }: { state: SocketIOEvents }) => {
|
|
120
119
|
this.clientEventEmitter.emit(state);
|
|
121
120
|
|
|
122
|
-
if (state === SocketIOEvents.
|
|
121
|
+
if (state === SocketIOEvents.Reconnected) {
|
|
123
122
|
this.network.socket.disconnect();
|
|
124
123
|
this.clientEventEmitter.emit(CLIENT_EVENTS.channelRejoinRequired);
|
|
125
124
|
}
|
|
@@ -146,7 +145,12 @@ class Engine {
|
|
|
146
145
|
try {
|
|
147
146
|
this.logger.debug('join()', { params });
|
|
148
147
|
this.isRoomJoining = true;
|
|
149
|
-
await this.
|
|
148
|
+
const { webSocketUrl } = await this.getAvailableNode({
|
|
149
|
+
channelId: params.channelId,
|
|
150
|
+
role: params.role,
|
|
151
|
+
});
|
|
152
|
+
this.network.socket.connect(webSocketUrl);
|
|
153
|
+
await this.waitForSocketConnection();
|
|
150
154
|
await this.performJoin(params);
|
|
151
155
|
} catch (error) {
|
|
152
156
|
this.logger.error('join()', { error });
|
|
@@ -420,37 +424,6 @@ class Engine {
|
|
|
420
424
|
return this.app;
|
|
421
425
|
}
|
|
422
426
|
|
|
423
|
-
private async connectToSocketServerWithRetry(params: { channelId: string, role: Role }): Promise<void> {
|
|
424
|
-
const connectToSocketServerAction = async () => this.connectToSocketServer(params);
|
|
425
|
-
return retryAsync(connectToSocketServerAction, {
|
|
426
|
-
maxRetries: 15,
|
|
427
|
-
minBackoffDelayMs: 150,
|
|
428
|
-
maxBackoffDelayMs: 5_000,
|
|
429
|
-
actionName: 'connectToSocketServer',
|
|
430
|
-
});
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
private async connectToSocketServer(params: { channelId: string, role: Role }): Promise<void> {
|
|
434
|
-
const { webSocketUrl } = await this.getAvailableNode({
|
|
435
|
-
channelId: params.channelId,
|
|
436
|
-
role: params.role,
|
|
437
|
-
});
|
|
438
|
-
this.network.socket.connect(webSocketUrl);
|
|
439
|
-
|
|
440
|
-
try {
|
|
441
|
-
await this.waitForSocketConnection();
|
|
442
|
-
} catch (error: unknown) {
|
|
443
|
-
this.logger.error('Failed to connect to socket server', {
|
|
444
|
-
error,
|
|
445
|
-
role: params.role,
|
|
446
|
-
channelId: params.channelId,
|
|
447
|
-
});
|
|
448
|
-
|
|
449
|
-
this.network.socket.disconnect();
|
|
450
|
-
throw error;
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
|
|
454
427
|
private async getAvailableNode(params: GetNodeRequest): Promise<{ webSocketUrl: string }> {
|
|
455
428
|
try {
|
|
456
429
|
const response = await this.network.loadBalancerClient.getNode(params);
|
|
@@ -465,17 +438,14 @@ class Engine {
|
|
|
465
438
|
return new Promise((resolve, reject) => {
|
|
466
439
|
const onSocketStateChange = async (data: { state: SocketIOEvents, error?: string }) => {
|
|
467
440
|
const { error, state } = data;
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
if (error || (this.isRoomJoining && isStateNotExpected)) {
|
|
472
|
-
stopListening();
|
|
473
|
-
reject(error || 'Not expected socket state for new connection');
|
|
441
|
+
if (error) {
|
|
442
|
+
this.network.socket.observer.removeListener('state', onSocketStateChange);
|
|
443
|
+
reject(error);
|
|
474
444
|
return;
|
|
475
445
|
}
|
|
476
446
|
|
|
477
|
-
if (this.isRoomJoining &&
|
|
478
|
-
|
|
447
|
+
if (this.isRoomJoining && state === SocketIOEvents.Connected) {
|
|
448
|
+
this.network.socket.observer.removeListener('state', onSocketStateChange);
|
|
479
449
|
resolve();
|
|
480
450
|
}
|
|
481
451
|
};
|
|
@@ -486,7 +456,7 @@ class Engine {
|
|
|
486
456
|
|
|
487
457
|
private async performJoin(params: JoinChannelParams): Promise<void> {
|
|
488
458
|
try {
|
|
489
|
-
await this.
|
|
459
|
+
await this.network.socket.request(CHANNEL_EVENTS.channelJoin, params);
|
|
490
460
|
await this.initialize();
|
|
491
461
|
this.channelEventsHandler.subscribeToEvents();
|
|
492
462
|
this.mediaSoupEventsHandler.subscribeToEvents();
|
|
@@ -500,19 +470,6 @@ class Engine {
|
|
|
500
470
|
}
|
|
501
471
|
}
|
|
502
472
|
|
|
503
|
-
private async sendJoinChannelRequestWithRetry(params: JoinChannelParams): Promise<SocketResponse> {
|
|
504
|
-
const joinChannelAction = async () => this.sendJoinChannelRequest(params);
|
|
505
|
-
return retryAsync(joinChannelAction, {
|
|
506
|
-
maxRetries: 3,
|
|
507
|
-
minBackoffDelayMs: 300,
|
|
508
|
-
actionName: 'sendJoinChannelRequest',
|
|
509
|
-
});
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
private async sendJoinChannelRequest(params: JoinChannelParams): Promise<SocketResponse> {
|
|
513
|
-
return this.network.socket.request(CHANNEL_EVENTS.channelJoin, params);
|
|
514
|
-
}
|
|
515
|
-
|
|
516
473
|
get cahPublish(): boolean {
|
|
517
474
|
return this.peers.find((item) => item.isMe)?.role === 'host';
|
|
518
475
|
}
|
|
@@ -45,7 +45,7 @@ class SocketIO {
|
|
|
45
45
|
: SocketIOEvents.Reconnected;
|
|
46
46
|
|
|
47
47
|
this.isConnected = true;
|
|
48
|
-
this.
|
|
48
|
+
this.reconnectingAttempt = 0;
|
|
49
49
|
|
|
50
50
|
this.logger.debug('connection.on(`connect`)');
|
|
51
51
|
this.observer.safeEmit('state', { state });
|
|
@@ -59,14 +59,14 @@ class SocketIO {
|
|
|
59
59
|
|
|
60
60
|
connection.on('disconnect', ((reason: string) => {
|
|
61
61
|
this.isConnected = false;
|
|
62
|
-
this.
|
|
62
|
+
this.reconnectingAttempt = 0;
|
|
63
63
|
this.disconnectReason = reason;
|
|
64
|
-
this.logger.
|
|
64
|
+
this.logger.error('connection.on(`disconnect`)', reason);
|
|
65
65
|
this.observer.safeEmit('state', { state: SocketIOEvents.Disconnected });
|
|
66
66
|
}));
|
|
67
67
|
|
|
68
68
|
connection.io.on('reconnect_attempt', (attempt: number) => {
|
|
69
|
-
this.
|
|
69
|
+
this.reconnectingAttempt = attempt;
|
|
70
70
|
this.logger.warn('connection.on(`reconnect_attempt`)', attempt);
|
|
71
71
|
this.observer.safeEmit('state', { state: SocketIOEvents.Reconnecting });
|
|
72
72
|
});
|
|
@@ -82,8 +82,6 @@ class SocketIO {
|
|
|
82
82
|
this.connection.offAny();
|
|
83
83
|
this.connection.volatile.offAny();
|
|
84
84
|
this.connection.disconnect();
|
|
85
|
-
// we need to reset this counter in order not to get Reconnected event on retry
|
|
86
|
-
this.setReconnectingAttempt(0);
|
|
87
85
|
}
|
|
88
86
|
}
|
|
89
87
|
|
|
@@ -105,10 +103,6 @@ class SocketIO {
|
|
|
105
103
|
});
|
|
106
104
|
});
|
|
107
105
|
}
|
|
108
|
-
|
|
109
|
-
private setReconnectingAttempt(attemptNo: number): void {
|
|
110
|
-
this.reconnectingAttempt = attemptNo;
|
|
111
|
-
}
|
|
112
106
|
}
|
|
113
107
|
|
|
114
108
|
export default SocketIO;
|
package/dist/helpers/retry.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export declare type RetryOpts = {
|
|
2
|
-
maxRetries?: number;
|
|
3
|
-
minBackoffDelayMs?: number;
|
|
4
|
-
maxBackoffDelayMs?: number;
|
|
5
|
-
actionName?: string;
|
|
6
|
-
};
|
|
7
|
-
declare const retryAsync: <ReturnType_1>(action: () => Promise<ReturnType_1>, opts?: RetryOpts) => Promise<ReturnType_1>;
|
|
8
|
-
declare const retry: <ReturnType_1>(action: () => ReturnType_1, opts?: RetryOpts) => Promise<ReturnType_1>;
|
|
9
|
-
export { retryAsync };
|
|
10
|
-
export default retry;
|
package/src/helpers/datetime.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
class DefaultTimeProvider {
|
|
2
|
-
// eslint-disable-next-line class-methods-use-this
|
|
3
|
-
async sleepMs(ms: number): Promise<void> {
|
|
4
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
// eslint-disable-next-line class-methods-use-this
|
|
8
|
-
now(): Date {
|
|
9
|
-
return new Date(Date.now());
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export default DefaultTimeProvider;
|
package/src/helpers/retry.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import DefaultTimeProvider from './datetime';
|
|
2
|
-
import Logger from '../engine/Logger';
|
|
3
|
-
|
|
4
|
-
export type RetryOpts = {
|
|
5
|
-
maxRetries?: number;
|
|
6
|
-
minBackoffDelayMs?: number;
|
|
7
|
-
maxBackoffDelayMs?: number;
|
|
8
|
-
actionName?: string; // human-readable action name for debug purposes
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
const logger = new Logger('Retry');
|
|
12
|
-
const timeProvider = new DefaultTimeProvider();
|
|
13
|
-
|
|
14
|
-
const retryAsync = async <ReturnType>(
|
|
15
|
-
action: () => Promise<ReturnType>,
|
|
16
|
-
opts: RetryOpts = {},
|
|
17
|
-
): Promise<ReturnType> => {
|
|
18
|
-
const maxRetries = opts.maxRetries || 2;
|
|
19
|
-
const minBackoffDelayMs = opts.minBackoffDelayMs || 50;
|
|
20
|
-
let currentAttempt = 0;
|
|
21
|
-
let lastError;
|
|
22
|
-
|
|
23
|
-
while (currentAttempt < maxRetries) {
|
|
24
|
-
currentAttempt += 1;
|
|
25
|
-
|
|
26
|
-
try {
|
|
27
|
-
// eslint-disable-next-line no-await-in-loop
|
|
28
|
-
return await action();
|
|
29
|
-
} catch (err: unknown) {
|
|
30
|
-
lastError = err;
|
|
31
|
-
logger.warn('Action retry failed', currentAttempt, opts.actionName, err);
|
|
32
|
-
|
|
33
|
-
if (currentAttempt < maxRetries) {
|
|
34
|
-
const delay = 2 ** (currentAttempt - 1) * minBackoffDelayMs;
|
|
35
|
-
// eslint-disable-next-line no-await-in-loop
|
|
36
|
-
await timeProvider.sleepMs(Math.min(delay, opts.maxBackoffDelayMs ?? delay));
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
throw lastError;
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
const retry = async <ReturnType>(
|
|
45
|
-
action: () => ReturnType,
|
|
46
|
-
opts: RetryOpts = {},
|
|
47
|
-
): Promise<ReturnType> => retryAsync(async () => action(), opts);
|
|
48
|
-
|
|
49
|
-
export { retryAsync };
|
|
50
|
-
export default retry;
|