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