207 lines
5.7 KiB
JavaScript
207 lines
5.7 KiB
JavaScript
|
|
/**
|
|||
|
|
* WebSocket管理
|
|||
|
|
* 管理WebSocket连接,处理WebSocket事件
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
class WebSocketManager {
|
|||
|
|
constructor(url = null) {
|
|||
|
|
this.url = url || this.getDefaultWebSocketUrl();
|
|||
|
|
this.socket = null;
|
|||
|
|
this.isConnected = false;
|
|||
|
|
this.listeners = new Map();
|
|||
|
|
this.reconnectAttempts = 0;
|
|||
|
|
this.maxReconnectAttempts = 5;
|
|||
|
|
this.reconnectDelay = 1000;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取默认WebSocket URL
|
|||
|
|
* @returns {string} WebSocket URL
|
|||
|
|
*/
|
|||
|
|
getDefaultWebSocketUrl() {
|
|||
|
|
const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|||
|
|
return `${protocol}//${location.host}`;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 连接WebSocket
|
|||
|
|
*/
|
|||
|
|
connect() {
|
|||
|
|
try {
|
|||
|
|
this.socket = new WebSocket(this.url);
|
|||
|
|
|
|||
|
|
this.socket.onopen = () => {
|
|||
|
|
console.log('WebSocket connected');
|
|||
|
|
this.isConnected = true;
|
|||
|
|
this.reconnectAttempts = 0;
|
|||
|
|
this.emit('connect');
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
this.socket.onclose = () => {
|
|||
|
|
console.log('WebSocket disconnected');
|
|||
|
|
this.isConnected = false;
|
|||
|
|
this.emit('disconnect');
|
|||
|
|
this.attemptReconnect();
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
this.socket.onmessage = (event) => {
|
|||
|
|
try {
|
|||
|
|
const message = JSON.parse(event.data);
|
|||
|
|
this.handleMessage(message);
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('Error parsing WebSocket message:', error);
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
this.socket.onerror = (error) => {
|
|||
|
|
console.error('WebSocket error:', error);
|
|||
|
|
this.emit('error', error);
|
|||
|
|
};
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('Error connecting to WebSocket:', error);
|
|||
|
|
this.emit('error', error);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 断开WebSocket连接
|
|||
|
|
*/
|
|||
|
|
disconnect() {
|
|||
|
|
if (this.socket) {
|
|||
|
|
this.socket.close();
|
|||
|
|
this.socket = null;
|
|||
|
|
this.isConnected = false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 发送消息
|
|||
|
|
* @param {string} event - 事件名称
|
|||
|
|
* @param {Object} data - 消息数据
|
|||
|
|
*/
|
|||
|
|
send(event, data) {
|
|||
|
|
if (this.isConnected && this.socket) {
|
|||
|
|
try {
|
|||
|
|
const message = JSON.stringify({ event, data });
|
|||
|
|
this.socket.send(message);
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('Error sending WebSocket message:', error);
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
console.warn('WebSocket not connected, cannot send message');
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 处理接收到的消息
|
|||
|
|
* @param {Object} message - 消息对象
|
|||
|
|
*/
|
|||
|
|
handleMessage(message) {
|
|||
|
|
switch (message.type) {
|
|||
|
|
case 'user-joined':
|
|||
|
|
this.emit('user-joined', message.data);
|
|||
|
|
break;
|
|||
|
|
case 'user-left':
|
|||
|
|
this.emit('user-left', message.data);
|
|||
|
|
break;
|
|||
|
|
case 'media-state-changed':
|
|||
|
|
this.emit('media-state-changed', message.data);
|
|||
|
|
break;
|
|||
|
|
case 'message-received':
|
|||
|
|
this.emit('message-received', message.data);
|
|||
|
|
break;
|
|||
|
|
case 'network-quality':
|
|||
|
|
this.emit('network-quality', message.data);
|
|||
|
|
break;
|
|||
|
|
case 'call-ended':
|
|||
|
|
this.emit('call-ended', message.data);
|
|||
|
|
break;
|
|||
|
|
case 'ping':
|
|||
|
|
// 处理心跳请求,回复pong
|
|||
|
|
this.send('pong', {});
|
|||
|
|
break;
|
|||
|
|
case 'pong':
|
|||
|
|
// 处理心跳响应
|
|||
|
|
this.emit('pong');
|
|||
|
|
break;
|
|||
|
|
default:
|
|||
|
|
this.emit('message', message);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 尝试重连
|
|||
|
|
*/
|
|||
|
|
attemptReconnect() {
|
|||
|
|
if (this.reconnectAttempts < this.maxReconnectAttempts) {
|
|||
|
|
this.reconnectAttempts++;
|
|||
|
|
const delay = this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1);
|
|||
|
|
|
|||
|
|
console.log(`Attempting to reconnect in ${delay}ms...`);
|
|||
|
|
|
|||
|
|
setTimeout(() => {
|
|||
|
|
console.log(`Reconnect attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts}`);
|
|||
|
|
this.connect();
|
|||
|
|
}, delay);
|
|||
|
|
} else {
|
|||
|
|
console.error('Max reconnect attempts reached');
|
|||
|
|
this.emit('reconnect-failed');
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 订阅事件
|
|||
|
|
* @param {string} event - 事件名称
|
|||
|
|
* @param {Function} callback - 回调函数
|
|||
|
|
*/
|
|||
|
|
on(event, callback) {
|
|||
|
|
if (!this.listeners.has(event)) {
|
|||
|
|
this.listeners.set(event, []);
|
|||
|
|
}
|
|||
|
|
this.listeners.get(event).push(callback);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 取消订阅事件
|
|||
|
|
* @param {string} event - 事件名称
|
|||
|
|
* @param {Function} callback - 回调函数
|
|||
|
|
*/
|
|||
|
|
off(event, callback) {
|
|||
|
|
if (this.listeners.has(event)) {
|
|||
|
|
const callbacks = this.listeners.get(event);
|
|||
|
|
this.listeners.set(event, callbacks.filter(cb => cb !== callback));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 触发事件
|
|||
|
|
* @param {string} event - 事件名称
|
|||
|
|
* @param {*} data - 事件数据
|
|||
|
|
*/
|
|||
|
|
emit(event, data) {
|
|||
|
|
if (this.listeners.has(event)) {
|
|||
|
|
this.listeners.get(event).forEach(callback => {
|
|||
|
|
try {
|
|||
|
|
callback(data);
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error(`Error in event listener for ${event}:`, error);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 检查连接状态
|
|||
|
|
* @returns {boolean} 是否连接
|
|||
|
|
*/
|
|||
|
|
getIsConnected() {
|
|||
|
|
return this.isConnected;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 创建单例实例
|
|||
|
|
const wsManager = new WebSocketManager();
|
|||
|
|
|
|||
|
|
export default wsManager;
|