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.
247 lines
6.3 KiB
247 lines
6.3 KiB
|
2 months ago
|
// 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
|
||
|
|
};
|