Files
forkmessager/client-mobile/src/core/infrastructure/socket.ts
Халимов Рустам abc491c042 Зачаток мобилки
2026-04-07 17:27:52 +03:00

98 lines
2.9 KiB
TypeScript

import { HubConnection, HubConnectionBuilder, LogLevel, HttpTransportType } from '@microsoft/signalr';
import { AppState, AppStateStatus } from 'react-native';
import { SOCKET_URL } from './config';
export interface SocketClient {
on(event: string, callback: (...args: any[]) => void): void;
off(event: string, callback?: (...args: any[]) => void): void;
emit(event: string, ...args: any[]): void;
disconnect(): void;
status: string;
}
let connection: HubConnection | null = null;
let socketClient: SocketClient | null = null;
let appStateListener: any = null;
export function connectSocket(token: string): SocketClient {
if (connection && (connection.state === 'Connected' || connection.state === 'Connecting')) {
return socketClient!;
}
connection = new HubConnectionBuilder()
.withUrl(SOCKET_URL, {
accessTokenFactory: () => token,
transport: HttpTransportType.WebSockets | HttpTransportType.LongPolling,
skipNegotiation: false,
})
.withAutomaticReconnect({
nextRetryDelayInMilliseconds: retryContext => {
if (retryContext.elapsedMilliseconds < 10000) return 2000;
if (retryContext.elapsedMilliseconds < 30000) return 10000;
return 30000;
}
})
.configureLogging(LogLevel.Information)
.build();
socketClient = {
on: (event: string, callback: (...args: any[]) => void) => {
connection?.on(event, callback);
},
off: (event: string, callback?: (...args: any[]) => void) => {
if (callback) {
connection?.off(event, callback);
} else {
connection?.off(event);
}
},
emit: (event: string, ...args: any[]) => {
if (connection?.state === 'Connected') {
connection.invoke(event, ...args).catch(err => {
console.error(`SignalR emit error (${event}):`, err);
});
} else {
console.warn(`SignalR emit skipped (${event}): not connected`);
}
},
disconnect: () => {
if (appStateListener) {
appStateListener.remove();
appStateListener = null;
}
connection?.stop();
},
get status() {
return connection?.state || 'Disconnected';
}
};
// Lifecycle handling (AppState)
appStateListener = AppState.addEventListener('change', (nextAppState: AppStateStatus) => {
if (nextAppState === 'active') {
if (connection?.state === 'Disconnected') {
console.log('SignalR: Re-connecting on App Foreground...');
connection.start().catch(e => console.error('SignalR start error (background to foreground):', e));
}
}
});
connection.start()
.then(() => console.log('SignalR: Connected!'))
.catch(err => console.error('SignalR: Initial connection error:', err));
return socketClient;
}
export function getSocket(): SocketClient | null {
return socketClient;
}
export function disconnectSocket() {
if (socketClient) {
socketClient.disconnect();
socketClient = null;
connection = null;
}
}