Зачаток мобилки
This commit is contained in:
97
client-mobile/src/core/infrastructure/socket.ts
Normal file
97
client-mobile/src/core/infrastructure/socket.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user