You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

246 lines
6.3 KiB

// WebSocket实时通信工具
// 专为小程序设计的WebSocket封装,模拟Socket.IO功能
// 导入配置
const API = require('./api.js');
// WebSocket连接实例
let socket = null;
let isConnecting = false;
let reconnectAttempts = 0;
const maxReconnectAttempts = 5;
const reconnectDelay = 3000; // 重连延迟时间(毫秒)
// 事件监听器存储
const eventListeners = {};
// 存储当前连接的用户信息
let currentUserPhone = null;
let currentChatId = null;
// 获取WebSocket服务器URL
function getSocketUrl() {
// 从API的BASE_URL获取服务器地址
// 注意:小程序中无法直接获取API的BASE_URL,需要根据环境设置
const baseUrl = API.isTestMode() ? API.SERVER_CONFIG.DEFAULT_LOCAL_IP : API.SERVER_CONFIG.PRODUCTION;
// 替换http为ws,https为wss
return baseUrl.replace(/^http/, 'ws');
}
// 初始化WebSocket连接
function initSocket(userPhone, chatId) {
return new Promise((resolve, reject) => {
// 存储当前用户信息
currentUserPhone = userPhone;
currentChatId = chatId;
// 如果已经连接,直接返回
if (socket && socket.connected) {
console.log('WebSocket已经连接');
resolve(socket);
return;
}
// 如果正在连接中,等待连接完成
if (isConnecting) {
console.log('WebSocket正在连接中...');
// 等待连接完成
const checkConnection = setInterval(() => {
if (socket && socket.connected) {
clearInterval(checkConnection);
resolve(socket);
} else if (!isConnecting) {
clearInterval(checkConnection);
reject(new Error('WebSocket连接失败'));
}
}, 100);
return;
}
isConnecting = true;
reconnectAttempts = 0;
try {
const socketUrl = getSocketUrl();
const fullUrl = `${socketUrl}?user_phone=${userPhone}&chat_id=${chatId}`;
console.log('正在连接WebSocket服务器:', fullUrl);
// 创建WebSocket连接
socket = wx.connectSocket({
url: fullUrl,
header: {
'content-type': 'application/json'
},
protocols: ['chat'],
success: () => {
console.log('WebSocket连接创建请求发送成功');
},
fail: (error) => {
console.error('WebSocket连接创建失败:', error);
isConnecting = false;
reject(error);
}
});
// 连接成功事件
socket.onOpen(() => {
console.log('WebSocket连接成功');
socket.connected = true;
isConnecting = false;
reconnectAttempts = 0;
resolve(socket);
});
// 连接错误事件
socket.onError((error) => {
console.error('WebSocket连接错误:', error);
socket.connected = false;
isConnecting = false;
reject(error);
});
// 断开连接事件
socket.onClose((res) => {
console.log('WebSocket断开连接:', res);
socket.connected = false;
isConnecting = false;
// 如果不是手动断开(code !== 1000),尝试重连
if (res.code !== 1000) {
reconnect();
}
});
// 接收消息事件
socket.onMessage((res) => {
console.log('收到WebSocket消息:', res);
try {
const message = JSON.parse(res.data);
// 触发对应类型的事件
if (message.type) {
emitEvent(message.type, message.data);
} else {
// 兼容旧格式消息
emitEvent('message', message);
}
} catch (error) {
console.error('消息解析失败:', error);
}
});
} catch (error) {
console.error('初始化WebSocket失败:', error);
isConnecting = false;
reject(error);
}
});
}
// 重连函数
function reconnect() {
if (reconnectAttempts >= maxReconnectAttempts) {
console.error('WebSocket重连次数超过限制,停止重连');
return;
}
reconnectAttempts++;
console.log(`WebSocket正在重连,尝试次数: ${reconnectAttempts}/${maxReconnectAttempts}`);
// 延迟重连
setTimeout(() => {
if (currentUserPhone && currentChatId) {
initSocket(currentUserPhone, currentChatId)
.then(() => {
console.log('WebSocket重连成功');
})
.catch((error) => {
console.error('WebSocket重连失败:', error);
});
}
}, reconnectDelay);
}
// 发送消息
function sendMessage(messageData) {
return new Promise((resolve, reject) => {
if (!socket || !socket.connected) {
reject(new Error('WebSocket未连接'));
return;
}
try {
// 构造消息格式,模拟Socket.IO的事件机制
const message = {
type: 'chat message',
data: messageData
};
socket.send({
data: JSON.stringify(message),
success: () => {
console.log('WebSocket消息发送成功');
resolve({ success: true });
},
fail: (error) => {
console.error('WebSocket消息发送失败:', error);
reject(error);
}
});
} catch (error) {
console.error('发送WebSocket消息失败:', error);
reject(error);
}
});
}
// 断开连接
function disconnect() {
if (socket) {
console.log('手动断开WebSocket连接');
socket.close(1000, 'normal closure');
socket = null;
}
isConnecting = false;
reconnectAttempts = 0;
}
// 注册事件监听器
function on(eventName, callback) {
if (!eventListeners[eventName]) {
eventListeners[eventName] = [];
}
eventListeners[eventName].push(callback);
}
// 移除事件监听器
function off(eventName, callback) {
if (eventListeners[eventName]) {
if (callback) {
eventListeners[eventName] = eventListeners[eventName].filter(cb => cb !== callback);
} else {
delete eventListeners[eventName];
}
}
}
// 触发事件
function emitEvent(eventName, data) {
if (eventListeners[eventName]) {
eventListeners[eventName].forEach(callback => {
try {
callback(data);
} catch (error) {
console.error('事件监听器执行错误:', error);
}
});
}
}
// 导出WebSocket工具
module.exports = {
initSocket,
sendMessage,
disconnect,
on,
off,
isConnected: () => socket && socket.connected
};