Files
webRtc/WebApp/client/public/onebyone/websocket.js
zhangzheng b4c41e42c9 测试
2026-03-10 19:09:41 +08:00

304 lines
8.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* WebSocket管理
* 管理WebSocket连接处理WebSocket事件
*/
import { RenderStreaming } from "../../module/renderstreaming.js"; // WebRTC连接管理
class WebSocketManager {
constructor() {
this.isConnected = false;
}
/**
* 获取默认WebSocket URL
* @returns {string} WebSocket URL
*/
getDefaultWebSocketUrl() {
const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
return `${protocol}//${location.host}`;
}
/**
* 连接WebSocket
*/
init() {
try {
RenderStreaming.onConnect = () => {
console.log('WebSocket connected');
this.isConnected = true;
// // 发送连接消息
// this.sendConnectMessage();
// // 启动心跳
this.startHeartbeat();
// this.emit('connect');
};
RenderStreaming.onDisconnect = () => {
console.log('WebSocket disconnected');
this.isConnected = false;
this.stopHeartbeat();
//this.emit('disconnect');
//this.attemptReconnect();
};
RenderStreaming.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} type - 消息类型
* @param {Object} data - 消息数据
*/
send(type, data) {
if (this.isConnected && this.socket) {
try {
let message;
// 根据消息类型构建不同的消息格式
if (type === 'connect' || type === 'disconnect') {
message = JSON.stringify({ type, connectionId: this.connectionId });
} else if (type === 'offer' || type === 'answer' || type === 'candidate') {
message = JSON.stringify({ type, data });
} else if (type === 'broadcast') {
message = JSON.stringify({ type, message: data.message, targetConnectionId: data.targetConnectionId });
} else if (type === 'ping' || type === 'pong') {
message = JSON.stringify({ type });
} else {
// 兼容旧格式,用于自定义事件
message = JSON.stringify({ event: type, 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) {
if (message.type) {
console.log('Received message:', 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 'call-request':
this.emit('call-request', message.data);
break;
case 'ping':
// 处理心跳请求回复pong
this.send('pong');
break;
case 'pong':
// 处理心跳响应
this.emit('pong');
break;
case 'offer':
this.emit('offer', message.data);
break;
case 'answer':
this.emit('answer', message.data);
break;
case 'candidate':
this.emit('candidate', message.data);
break;
case 'chat-message':
this.emit('chat-message', message.data);
break;
default:
// 处理旧格式消息
if (message.event) {
this.emit(message.event, message.data);
} else {
this.emit('message', message);
}
break;
}
} else if (message.event) {
// 处理旧格式消息
this.emit(message.event, message.data);
} else {
this.emit('message', message);
}
}
/**
* 尝试重连
*/
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');
}
}
/**
* 生成连接ID
* @returns {string} 连接ID
*/
generateConnectionId() {
return 'conn_' + Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
}
/**
* 发送连接消息
*/
sendConnectMessage() {
this.send('connect');
}
/**
* 发送断开连接消息
*/
sendDisconnectMessage() {
this.send('disconnect');
}
/**
* 启动心跳
*/
startHeartbeat() {
this.heartbeatInterval = setInterval(() => {
if (this.isConnected) {
this.send('ping');
}
}, 30000); // 每30秒发送一次心跳
}
/**
* 停止心跳
*/
stopHeartbeat() {
if (this.heartbeatInterval) {
clearInterval(this.heartbeatInterval);
this.heartbeatInterval = null;
}
}
/**
* 获取连接ID
* @returns {string} 连接ID
*/
getConnectionId() {
return this.connectionId;
}
/**
* 订阅事件
* @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;