@jellyfish-dev/ts-client-sdk
Version:
Typescript client library for Jellyfish.
99 lines (98 loc) • 3.45 kB
JavaScript
import { isAuthError } from "./auth";
const DISABLED_RECONNECT_CONFIG = {
maxAttempts: 0,
initialDelay: 0,
delay: 0,
addTracksOnReconnect: false,
};
const DEFAULT_RECONNECT_CONFIG = {
maxAttempts: 3,
initialDelay: 500,
delay: 500,
addTracksOnReconnect: true,
};
export class ReconnectManager {
reconnectConfig;
connect;
client;
initialMetadata = undefined;
reconnectAttempt = 0;
reconnectTimeoutId = null;
reconnectFailedNotificationSend = false;
ongoingReconnection = false;
lastLocalEndpoint = null;
constructor(client, connect, config) {
this.client = client;
this.connect = connect;
this.reconnectConfig = createReconnectConfig(config);
this.client.on("socketError", () => {
this.reconnect();
});
this.client.on("socketClose", (event) => {
if (isAuthError(event.reason))
return;
this.reconnect();
});
this.client.on("authSuccess", () => {
this.reset(this.initialMetadata);
});
this.client.on("joined", () => {
this.handleReconnect();
});
}
reset(initialMetadata) {
this.initialMetadata = initialMetadata;
this.reconnectAttempt = 0;
if (this.reconnectTimeoutId)
clearTimeout(this.reconnectTimeoutId);
this.reconnectTimeoutId = null;
}
getLastPeerMetadata() {
return this.lastLocalEndpoint?.metadata;
}
reconnect() {
if (this.reconnectTimeoutId)
return;
if (this.reconnectAttempt >= this.reconnectConfig.maxAttempts) {
if (!this.reconnectFailedNotificationSend) {
this.reconnectFailedNotificationSend = true;
}
return;
}
if (!this.ongoingReconnection) {
this.ongoingReconnection = true;
this.lastLocalEndpoint = this.client.getLocalEndpoint() || null;
}
const timeout = this.reconnectConfig.initialDelay + this.reconnectAttempt * this.reconnectConfig.delay;
this.reconnectAttempt += 1;
this.reconnectTimeoutId = setTimeout(() => {
this.reconnectTimeoutId = null;
this.connect(this.getLastPeerMetadata() ?? this.initialMetadata);
}, timeout);
}
handleReconnect() {
if (!this.ongoingReconnection)
return;
if (this.lastLocalEndpoint && this.reconnectConfig.addTracksOnReconnect) {
this.lastLocalEndpoint.tracks.forEach(async (track) => {
if (!track.track || !track.stream)
return;
await this.client.addTrack(track.track, track.stream, track.rawMetadata, track.simulcastConfig, track.maxBandwidth);
});
}
this.lastLocalEndpoint = null;
this.ongoingReconnection = false;
}
}
export const createReconnectConfig = (config) => {
if (!config)
return DISABLED_RECONNECT_CONFIG;
if (config === true)
return DEFAULT_RECONNECT_CONFIG;
return {
maxAttempts: config?.maxAttempts ?? DEFAULT_RECONNECT_CONFIG.maxAttempts,
initialDelay: config?.initialDelay ?? DEFAULT_RECONNECT_CONFIG.initialDelay,
delay: config?.delay ?? DEFAULT_RECONNECT_CONFIG.delay,
addTracksOnReconnect: config?.addTracksOnReconnect ?? DEFAULT_RECONNECT_CONFIG.addTracksOnReconnect,
};
};