Spaces:
Configuration error
Configuration error
import { io, Socket } from 'socket.io-client' | |
import { Message, User, Chat } from '../../../shared/types' | |
class SocketService { | |
private socket: Socket | null = null | |
private reconnectAttempts = 0 | |
private maxReconnectAttempts = 5 | |
private reconnectDelay = 1000 | |
connect(token: string): Promise<void> { | |
return new Promise((resolve, reject) => { | |
if (this.socket?.connected) { | |
resolve() | |
return | |
} | |
const socketUrl = import.meta.env.VITE_SOCKET_URL || 'http://localhost:3001' | |
this.socket = io(socketUrl, { | |
auth: { | |
token | |
}, | |
transports: ['websocket', 'polling'], | |
timeout: 10000, | |
}) | |
this.socket.on('connect', () => { | |
console.log('Socket connected') | |
this.reconnectAttempts = 0 | |
resolve() | |
}) | |
this.socket.on('connect_error', (error) => { | |
console.error('Socket connection error:', error) | |
reject(error) | |
}) | |
this.socket.on('disconnect', (reason) => { | |
console.log('Socket disconnected:', reason) | |
if (reason === 'io server disconnect') { | |
// Server disconnected, try to reconnect | |
this.handleReconnect() | |
} | |
}) | |
this.socket.on('error', (error) => { | |
console.error('Socket error:', error) | |
}) | |
// Set up event listeners | |
this.setupEventListeners() | |
}) | |
} | |
disconnect(): void { | |
if (this.socket) { | |
this.socket.disconnect() | |
this.socket = null | |
} | |
} | |
private handleReconnect(): void { | |
if (this.reconnectAttempts < this.maxReconnectAttempts) { | |
this.reconnectAttempts++ | |
const delay = this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1) | |
setTimeout(() => { | |
console.log(`Attempting to reconnect (${this.reconnectAttempts}/${this.maxReconnectAttempts})`) | |
this.socket?.connect() | |
}, delay) | |
} else { | |
console.error('Max reconnection attempts reached') | |
} | |
} | |
private setupEventListeners(): void { | |
if (!this.socket) return | |
// Authentication events | |
this.socket.on('authenticated', (user: User) => { | |
console.log('Socket authenticated for user:', user.username) | |
}) | |
this.socket.on('authentication_error', (error: string) => { | |
console.error('Socket authentication error:', error) | |
}) | |
} | |
// Message events | |
onMessageReceive(callback: (message: Message) => void): void { | |
this.socket?.on('message:receive', callback) | |
} | |
onMessageEdit(callback: (message: Message) => void): void { | |
this.socket?.on('message:edit', callback) | |
} | |
onMessageDelete(callback: (messageId: string) => void): void { | |
this.socket?.on('message:delete', callback) | |
} | |
onMessageReaction(callback: (data: { messageId: string; reactions: any[] }) => void): void { | |
this.socket?.on('message:reaction', callback) | |
} | |
// Typing events | |
onTypingStart(callback: (data: { chatId: string; userId: string; user: User }) => void): void { | |
this.socket?.on('typing:start', callback) | |
} | |
onTypingStop(callback: (data: { chatId: string; userId: string }) => void): void { | |
this.socket?.on('typing:stop', callback) | |
} | |
sendTypingStart(chatId: string): void { | |
this.socket?.emit('typing:start', { chatId }) | |
} | |
sendTypingStop(chatId: string): void { | |
this.socket?.emit('typing:stop', { chatId }) | |
} | |
// User status events | |
onUserOnline(callback: (userId: string) => void): void { | |
this.socket?.on('user:online', callback) | |
} | |
onUserOffline(callback: (userId: string) => void): void { | |
this.socket?.on('user:offline', callback) | |
} | |
onUserStatusUpdate(callback: (data: { userId: string; isOnline: boolean; lastSeen?: Date }) => void): void { | |
this.socket?.on('user:status', callback) | |
} | |
// Chat events | |
onChatUpdate(callback: (chat: Chat) => void): void { | |
this.socket?.on('chat:update', callback) | |
} | |
onChatJoin(callback: (data: { chatId: string; user: User }) => void): void { | |
this.socket?.on('chat:join', callback) | |
} | |
onChatLeave(callback: (data: { chatId: string; userId: string }) => void): void { | |
this.socket?.on('chat:leave', callback) | |
} | |
joinChat(chatId: string): void { | |
this.socket?.emit('chat:join', chatId) | |
} | |
leaveChat(chatId: string): void { | |
this.socket?.emit('chat:leave', chatId) | |
} | |
// Group events | |
onGroupMemberAdd(callback: (data: { groupId: string; user: User; addedBy: User }) => void): void { | |
this.socket?.on('group:member:add', callback) | |
} | |
onGroupMemberRemove(callback: (data: { groupId: string; userId: string; removedBy: User }) => void): void { | |
this.socket?.on('group:member:remove', callback) | |
} | |
onGroupUpdate(callback: (group: any) => void): void { | |
this.socket?.on('group:update', callback) | |
} | |
// Notification events | |
onNotification(callback: (notification: any) => void): void { | |
this.socket?.on('notification', callback) | |
} | |
// Utility methods | |
isConnected(): boolean { | |
return this.socket?.connected || false | |
} | |
emit(event: string, data?: any): void { | |
this.socket?.emit(event, data) | |
} | |
on(event: string, callback: (...args: any[]) => void): void { | |
this.socket?.on(event, callback) | |
} | |
off(event: string, callback?: (...args: any[]) => void): void { | |
this.socket?.off(event, callback) | |
} | |
// Remove all listeners for cleanup | |
removeAllListeners(): void { | |
this.socket?.removeAllListeners() | |
} | |
} | |
export const socketService = new SocketService() | |