4 changed files with 416 additions and 6 deletions
@ -0,0 +1,246 @@ |
|||||
|
// 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 |
||||
|
}; |
||||
Loading…
Reference in new issue