|
|
@@ -7,7 +7,7 @@ export interface SocketTransportOptions {
|
|
|
socketOptions: Partial<ManagerOptions & SocketOptions>
|
|
|
onConnect?: () => void | Promise<void>
|
|
|
onDisconnect?: (reason: string) => void
|
|
|
- onReconnect?: (attemptNumber: number) => void | Promise<void>
|
|
|
+ onReconnect?: () => void | Promise<void>
|
|
|
logger?: {
|
|
|
log: (message: string, ...args: unknown[]) => void
|
|
|
error: (message: string, ...args: unknown[]) => void
|
|
|
@@ -23,7 +23,7 @@ export class SocketTransport {
|
|
|
private socket: Socket | null = null
|
|
|
private connectionState: ConnectionState = ConnectionState.DISCONNECTED
|
|
|
private retryTimeout: NodeJS.Timeout | null = null
|
|
|
- private hasConnectedOnce: boolean = false
|
|
|
+ private isPreviouslyConnected: boolean = false
|
|
|
|
|
|
private readonly retryConfig: RetryConfig = {
|
|
|
maxInitialAttempts: Infinity,
|
|
|
@@ -48,12 +48,12 @@ export class SocketTransport {
|
|
|
// kicks in after a successful initial connection.
|
|
|
public async connect(): Promise<void> {
|
|
|
if (this.connectionState === ConnectionState.CONNECTED) {
|
|
|
- console.log(`[SocketTransport] Already connected`)
|
|
|
+ console.log(`[SocketTransport#connect] Already connected`)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if (this.connectionState === ConnectionState.CONNECTING || this.connectionState === ConnectionState.RETRYING) {
|
|
|
- console.log(`[SocketTransport] Connection attempt already in progress`)
|
|
|
+ console.log(`[SocketTransport#connect] Already in progress`)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
@@ -61,18 +61,11 @@ export class SocketTransport {
|
|
|
let delay = this.retryConfig.initialDelay
|
|
|
|
|
|
while (attempt < this.retryConfig.maxInitialAttempts) {
|
|
|
- console.log(`[SocketTransport] Initial connect attempt ${attempt + 1}`)
|
|
|
+ console.log(`[SocketTransport#connect] attempt = ${attempt + 1}, delay = ${delay}ms`)
|
|
|
this.connectionState = attempt === 0 ? ConnectionState.CONNECTING : ConnectionState.RETRYING
|
|
|
|
|
|
try {
|
|
|
await this._connect()
|
|
|
- console.log(`[SocketTransport] Connected to ${this.options.url}`)
|
|
|
- this.connectionState = ConnectionState.CONNECTED
|
|
|
-
|
|
|
- if (this.options.onConnect) {
|
|
|
- await this.options.onConnect()
|
|
|
- }
|
|
|
-
|
|
|
break
|
|
|
} catch (_error) {
|
|
|
attempt++
|
|
|
@@ -82,8 +75,6 @@ export class SocketTransport {
|
|
|
this.socket = null
|
|
|
}
|
|
|
|
|
|
- console.log(`[SocketTransport] Waiting ${delay}ms before retry...`)
|
|
|
-
|
|
|
const promise = new Promise((resolve) => {
|
|
|
this.retryTimeout = setTimeout(resolve, delay)
|
|
|
})
|
|
|
@@ -99,11 +90,12 @@ export class SocketTransport {
|
|
|
this.retryTimeout = null
|
|
|
}
|
|
|
|
|
|
- if (this.connectionState === ConnectionState.CONNECTED) {
|
|
|
- console.log(`[SocketTransport] Connected to ${this.options.url}`)
|
|
|
+ if (this.socket?.connected) {
|
|
|
+ console.log(`[SocketTransport#connect] connected - ${this.options.url}`)
|
|
|
} else {
|
|
|
+ // Since we have infinite retries this should never happen.
|
|
|
this.connectionState = ConnectionState.FAILED
|
|
|
- console.error(`[SocketTransport] Failed to connect to ${this.options.url}, giving up`)
|
|
|
+ console.error(`[SocketTransport#connect] Giving up`)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -112,7 +104,7 @@ export class SocketTransport {
|
|
|
this.socket = io(this.options.url, this.options.socketOptions)
|
|
|
|
|
|
let connectionTimeout: NodeJS.Timeout | null = setTimeout(() => {
|
|
|
- console.error(`[SocketTransport] failed to connect after ${this.CONNECTION_TIMEOUT}ms`)
|
|
|
+ console.error(`[SocketTransport#_connect] failed to connect after ${this.CONNECTION_TIMEOUT}ms`)
|
|
|
|
|
|
if (this.connectionState !== ConnectionState.CONNECTED) {
|
|
|
this.socket?.disconnect()
|
|
|
@@ -122,22 +114,28 @@ export class SocketTransport {
|
|
|
|
|
|
// https://socket.io/docs/v4/client-api/#event-connect
|
|
|
this.socket.on("connect", async () => {
|
|
|
- console.log(`[SocketTransport] on(connect)`)
|
|
|
+ console.log(
|
|
|
+ `[SocketTransport#_connect] on(connect): isPreviouslyConnected = ${this.isPreviouslyConnected}`,
|
|
|
+ )
|
|
|
|
|
|
if (connectionTimeout) {
|
|
|
clearTimeout(connectionTimeout)
|
|
|
connectionTimeout = null
|
|
|
}
|
|
|
|
|
|
- if (this.hasConnectedOnce) {
|
|
|
- this.connectionState = ConnectionState.CONNECTED
|
|
|
+ this.connectionState = ConnectionState.CONNECTED
|
|
|
|
|
|
+ if (this.isPreviouslyConnected) {
|
|
|
if (this.options.onReconnect) {
|
|
|
- await this.options.onReconnect(0)
|
|
|
+ await this.options.onReconnect()
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (this.options.onConnect) {
|
|
|
+ await this.options.onConnect()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- this.hasConnectedOnce = true
|
|
|
+ this.isPreviouslyConnected = true
|
|
|
resolve()
|
|
|
})
|
|
|
|
|
|
@@ -153,7 +151,9 @@ export class SocketTransport {
|
|
|
|
|
|
// https://socket.io/docs/v4/client-api/#event-disconnect
|
|
|
this.socket.on("disconnect", (reason, details) => {
|
|
|
- console.log(`[SocketTransport] on(disconnect) (reason: ${reason}, details: ${JSON.stringify(details)})`)
|
|
|
+ console.log(
|
|
|
+ `[SocketTransport#_connect] on(disconnect) (reason: ${reason}, details: ${JSON.stringify(details)})`,
|
|
|
+ )
|
|
|
this.connectionState = ConnectionState.DISCONNECTED
|
|
|
|
|
|
if (this.options.onDisconnect) {
|
|
|
@@ -163,12 +163,12 @@ export class SocketTransport {
|
|
|
// Don't attempt to reconnect if we're manually disconnecting.
|
|
|
const isManualDisconnect = reason === "io client disconnect"
|
|
|
|
|
|
- if (!isManualDisconnect && this.hasConnectedOnce) {
|
|
|
+ if (!isManualDisconnect && this.isPreviouslyConnected) {
|
|
|
// After successful initial connection, rely entirely on
|
|
|
// Socket.IO's reconnection logic.
|
|
|
- console.log("[SocketTransport] will attempt to reconnect")
|
|
|
+ console.log("[SocketTransport#_connect] will attempt to reconnect")
|
|
|
} else {
|
|
|
- console.log("[SocketTransport] will *NOT* attempt to reconnect")
|
|
|
+ console.log("[SocketTransport#_connect] will *NOT* attempt to reconnect")
|
|
|
}
|
|
|
})
|
|
|
|
|
|
@@ -177,7 +177,7 @@ export class SocketTransport {
|
|
|
this.socket.io.on("error", (error) => {
|
|
|
// Connection error.
|
|
|
if (connectionTimeout && this.connectionState !== ConnectionState.CONNECTED) {
|
|
|
- console.error(`[SocketTransport] on(error): ${error.message}`)
|
|
|
+ console.error(`[SocketTransport#_connect] on(error): ${error.message}`)
|
|
|
clearTimeout(connectionTimeout)
|
|
|
connectionTimeout = null
|
|
|
reject(error)
|
|
|
@@ -185,45 +185,45 @@ export class SocketTransport {
|
|
|
|
|
|
// Post-connection error.
|
|
|
if (this.connectionState === ConnectionState.CONNECTED) {
|
|
|
- console.error(`[SocketTransport] on(error): ${error.message}`)
|
|
|
+ console.error(`[SocketTransport#_connect] on(error): ${error.message}`)
|
|
|
}
|
|
|
})
|
|
|
|
|
|
// https://socket.io/docs/v4/client-api/#event-reconnect
|
|
|
// Fired upon a successful reconnection.
|
|
|
this.socket.io.on("reconnect", (attempt) => {
|
|
|
- console.log(`[SocketTransport] on(reconnect) - ${attempt}`)
|
|
|
+ console.log(`[SocketTransport#_connect] on(reconnect) - ${attempt}`)
|
|
|
this.connectionState = ConnectionState.CONNECTED
|
|
|
|
|
|
if (this.options.onReconnect) {
|
|
|
- this.options.onReconnect(attempt)
|
|
|
+ this.options.onReconnect()
|
|
|
}
|
|
|
})
|
|
|
|
|
|
// https://socket.io/docs/v4/client-api/#event-reconnect_attempt
|
|
|
// Fired upon an attempt to reconnect.
|
|
|
this.socket.io.on("reconnect_attempt", (attempt) => {
|
|
|
- console.log(`[SocketTransport] on(reconnect_attempt) - ${attempt}`)
|
|
|
+ console.log(`[SocketTransport#_connect] on(reconnect_attempt) - ${attempt}`)
|
|
|
})
|
|
|
|
|
|
// https://socket.io/docs/v4/client-api/#event-reconnect_error
|
|
|
// Fired upon a reconnection attempt error.
|
|
|
this.socket.io.on("reconnect_error", (error) => {
|
|
|
- console.error(`[SocketTransport] on(reconnect_error): ${error.message}`)
|
|
|
+ console.error(`[SocketTransport#_connect] on(reconnect_error): ${error.message}`)
|
|
|
})
|
|
|
|
|
|
// https://socket.io/docs/v4/client-api/#event-reconnect_failed
|
|
|
// Fired when couldn't reconnect within `reconnectionAttempts`.
|
|
|
// Since we use infinite retries, this should never fire.
|
|
|
this.socket.io.on("reconnect_failed", () => {
|
|
|
- console.error(`[SocketTransport] on(reconnect_failed) - giving up`)
|
|
|
+ console.error(`[SocketTransport#_connect] on(reconnect_failed) - giving up`)
|
|
|
this.connectionState = ConnectionState.FAILED
|
|
|
})
|
|
|
|
|
|
// This is a custom event fired by the server.
|
|
|
this.socket.on("auth_error", (error) => {
|
|
|
console.error(
|
|
|
- `[SocketTransport] on(auth_error): ${error instanceof Error ? error.message : String(error)}`,
|
|
|
+ `[SocketTransport#_connect] on(auth_error): ${error instanceof Error ? error.message : String(error)}`,
|
|
|
)
|
|
|
|
|
|
if (connectionTimeout && this.connectionState !== ConnectionState.CONNECTED) {
|
|
|
@@ -236,7 +236,7 @@ export class SocketTransport {
|
|
|
}
|
|
|
|
|
|
public async disconnect(): Promise<void> {
|
|
|
- console.log(`[SocketTransport] Disconnecting...`)
|
|
|
+ console.log(`[SocketTransport#disconnect] Disconnecting...`)
|
|
|
|
|
|
if (this.retryTimeout) {
|
|
|
clearTimeout(this.retryTimeout)
|
|
|
@@ -251,7 +251,7 @@ export class SocketTransport {
|
|
|
}
|
|
|
|
|
|
this.connectionState = ConnectionState.DISCONNECTED
|
|
|
- console.log(`[SocketTransport] Disconnected`)
|
|
|
+ console.log(`[SocketTransport#disconnect] Disconnected`)
|
|
|
}
|
|
|
|
|
|
public getSocket(): Socket | null {
|
|
|
@@ -267,14 +267,14 @@ export class SocketTransport {
|
|
|
}
|
|
|
|
|
|
public async reconnect(): Promise<void> {
|
|
|
- console.log(`[SocketTransport] Manually reconnecting...`)
|
|
|
+ console.log(`[SocketTransport#reconnect] Manually reconnecting...`)
|
|
|
|
|
|
if (this.connectionState === ConnectionState.CONNECTED) {
|
|
|
- console.log(`[SocketTransport] Already connected`)
|
|
|
+ console.log(`[SocketTransport#reconnect] Already connected`)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
- this.hasConnectedOnce = false
|
|
|
+ this.isPreviouslyConnected = false
|
|
|
await this.disconnect()
|
|
|
await this.connect()
|
|
|
}
|