Initial Commit
This commit is contained in:
commit
1d71a02738
237 changed files with 64293 additions and 0 deletions
393
test.js
Normal file
393
test.js
Normal file
|
|
@ -0,0 +1,393 @@
|
|||
import { defineStore } from 'pinia'
|
||||
|
||||
export const useWebSocketStore = defineStore('websocket', () => {
|
||||
let socketTask = null;
|
||||
let reconnectTimer = null;
|
||||
let heartbeatTimer = null;
|
||||
let reconnectAttempts = 0;
|
||||
const MAX_RECONNECT_ATTEMPTS = 5;
|
||||
const HEARTBEAT_INTERVAL = 30000; // 30秒心跳
|
||||
|
||||
// 连接状态
|
||||
const connectionState = ref('disconnected'); // disconnected, connecting, connected, reconnecting
|
||||
|
||||
/**
|
||||
* 建立WebSocket连接
|
||||
* @param {Object} registerInfo - 注册信息
|
||||
* @param {string} registerInfo.device_id - 设备ID
|
||||
* @param {string} registerInfo.token - JWT Token
|
||||
*/
|
||||
const buildWebSocket = async (registerInfo) => {
|
||||
try {
|
||||
// 确保先关闭已有连接
|
||||
if (socketTask) {
|
||||
socketTask.close({ code: 1000, reason: '重新连接' });
|
||||
socketTask = null;
|
||||
}
|
||||
|
||||
// 清除重连定时器
|
||||
if (reconnectTimer) {
|
||||
clearTimeout(reconnectTimer);
|
||||
reconnectTimer = null;
|
||||
}
|
||||
|
||||
connectionState.value = 'connecting';
|
||||
|
||||
// WebSocket地址
|
||||
const wsUrl = `wss://api.faxianwo.me/api/v1/ws?device_id=${registerInfo.device_id}`;
|
||||
|
||||
console.log('开始连接WebSocket:', wsUrl);
|
||||
|
||||
// uniapp WebSocket连接配置
|
||||
socketTask = uni.connectSocket({
|
||||
url: wsUrl,
|
||||
header: {
|
||||
'Authorization': `Bearer ${registerInfo.token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
// 移除protocols参数
|
||||
success: () => {
|
||||
console.log('WebSocket连接请求发送成功');
|
||||
},
|
||||
fail: (error) => {
|
||||
console.error('WebSocket连接请求失败:', error);
|
||||
connectionState.value = 'disconnected';
|
||||
handleConnectionError(error);
|
||||
}
|
||||
});
|
||||
|
||||
// 连接成功事件
|
||||
socketTask.onOpen((response) => {
|
||||
console.log('WebSocket连接成功:', response);
|
||||
connectionState.value = 'connected';
|
||||
reconnectAttempts = 0; // 重置重连次数
|
||||
|
||||
// 发送认证确认消息
|
||||
sendAuthConfirmation();
|
||||
|
||||
// 开始心跳
|
||||
startHeartbeat();
|
||||
|
||||
// 显示连接成功提示
|
||||
uni.showToast({
|
||||
title: '连接成功',
|
||||
icon: 'success',
|
||||
duration: 2000
|
||||
});
|
||||
});
|
||||
|
||||
// 接收消息事件
|
||||
socketTask.onMessage((message) => {
|
||||
try {
|
||||
const data = JSON.parse(message.data);
|
||||
console.log('收到WebSocket消息:', data);
|
||||
handleIncomingMessage(data);
|
||||
} catch (error) {
|
||||
console.error('解析WebSocket消息失败:', error, message.data);
|
||||
}
|
||||
});
|
||||
|
||||
// 连接错误事件
|
||||
socketTask.onError((error) => {
|
||||
console.error('WebSocket连接错误:', error);
|
||||
connectionState.value = 'disconnected';
|
||||
stopHeartbeat();
|
||||
handleConnectionError(error);
|
||||
});
|
||||
|
||||
// 连接关闭事件
|
||||
socketTask.onClose((closeEvent) => {
|
||||
console.log('WebSocket连接关闭:', closeEvent);
|
||||
connectionState.value = 'disconnected';
|
||||
stopHeartbeat();
|
||||
|
||||
// 如果不是主动关闭,尝试重连
|
||||
if (closeEvent.code !== 1000 && reconnectAttempts < MAX_RECONNECT_ATTEMPTS) {
|
||||
attemptReconnect(registerInfo);
|
||||
}
|
||||
});
|
||||
|
||||
return socketTask;
|
||||
|
||||
} catch (error) {
|
||||
console.error('建立WebSocket连接异常:', error);
|
||||
connectionState.value = 'disconnected';
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 发送认证确认消息
|
||||
*/
|
||||
const sendAuthConfirmation = () => {
|
||||
if (!socketTask || connectionState.value !== 'connected') {
|
||||
console.warn('WebSocket未连接,无法发送认证确认');
|
||||
return;
|
||||
}
|
||||
|
||||
const authMessage = {
|
||||
type: 'auth_confirm',
|
||||
id: `auth_${Date.now()}`,
|
||||
data: {
|
||||
timestamp: Date.now()
|
||||
}
|
||||
};
|
||||
|
||||
socketTask.send({
|
||||
data: JSON.stringify(authMessage),
|
||||
success: () => console.log('认证确认发送成功'),
|
||||
fail: (err) => console.error('认证确认发送失败:', err)
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 开始心跳检测
|
||||
*/
|
||||
const startHeartbeat = () => {
|
||||
stopHeartbeat(); // 先清除已有的心跳
|
||||
|
||||
heartbeatTimer = setInterval(() => {
|
||||
if (socketTask && connectionState.value === 'connected') {
|
||||
const heartbeatMessage = {
|
||||
type: 'heartbeat',
|
||||
id: `hb_${Date.now()}`,
|
||||
data: {
|
||||
timestamp: Date.now()
|
||||
}
|
||||
};
|
||||
|
||||
socketTask.send({
|
||||
data: JSON.stringify(heartbeatMessage),
|
||||
success: () => console.log('心跳发送成功'),
|
||||
fail: (err) => {
|
||||
console.error('心跳发送失败:', err);
|
||||
// 心跳失败可能表示连接有问题
|
||||
connectionState.value = 'disconnected';
|
||||
}
|
||||
});
|
||||
}
|
||||
}, HEARTBEAT_INTERVAL);
|
||||
};
|
||||
|
||||
/**
|
||||
* 停止心跳检测
|
||||
*/
|
||||
const stopHeartbeat = () => {
|
||||
if (heartbeatTimer) {
|
||||
clearInterval(heartbeatTimer);
|
||||
heartbeatTimer = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理接收到的消息
|
||||
*/
|
||||
const handleIncomingMessage = (message) => {
|
||||
switch (message.type) {
|
||||
case 'new_message':
|
||||
// 处理新消息
|
||||
console.log('收到新消息:', message.data);
|
||||
break;
|
||||
|
||||
case 'message_read':
|
||||
// 处理已读回执
|
||||
console.log('消息已读:', message.data);
|
||||
break;
|
||||
|
||||
case 'message_recalled':
|
||||
// 处理消息撤回
|
||||
console.log('消息撤回:', message.data);
|
||||
break;
|
||||
|
||||
case 'heartbeat_response':
|
||||
// 心跳响应
|
||||
console.log('收到心跳响应');
|
||||
break;
|
||||
|
||||
default:
|
||||
console.log('收到其他类型消息:', message);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 发送消息的通用方法
|
||||
*/
|
||||
const sendMessage = (messageType, messageData) => {
|
||||
if (!socketTask || connectionState.value !== 'connected') {
|
||||
console.warn('WebSocket未连接,无法发送消息');
|
||||
return false;
|
||||
}
|
||||
|
||||
const message = {
|
||||
type: messageType,
|
||||
id: `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
||||
data: messageData
|
||||
};
|
||||
|
||||
socketTask.send({
|
||||
data: JSON.stringify(message),
|
||||
success: () => console.log(` ${messageType} 发送成功`),
|
||||
fail: (err) => console.error(` ${messageType} 发送失败:`, err)
|
||||
});
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* 发送聊天消息
|
||||
*/
|
||||
const sendChatMessage = (receiverId, content, msgType = 0, chatType = 0) => {
|
||||
return sendMessage('send_message', {
|
||||
receiverId: String(receiverId), // 确保是字符串格式
|
||||
chatType,
|
||||
msgType,
|
||||
content,
|
||||
timestamp: Date.now()
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理连接错误
|
||||
*/
|
||||
const handleConnectionError = (error) => {
|
||||
let errorMessage = '连接错误';
|
||||
|
||||
// 完善的错误码处理
|
||||
switch (error.errCode) {
|
||||
case 1000:
|
||||
errorMessage = '正常关闭';
|
||||
break;
|
||||
case 1001:
|
||||
errorMessage = '连接断开';
|
||||
break;
|
||||
case 1002:
|
||||
errorMessage = '协议错误';
|
||||
break;
|
||||
case 1003:
|
||||
errorMessage = '数据格式错误';
|
||||
break;
|
||||
case 1006:
|
||||
errorMessage = '异常断开';
|
||||
break;
|
||||
case 1011:
|
||||
errorMessage = '服务器错误';
|
||||
break;
|
||||
case 1012:
|
||||
errorMessage = '服务重启';
|
||||
break;
|
||||
default:
|
||||
console.log(`未知错误代码: ${error.errCode}`);
|
||||
errorMessage = `连接错误 (${error.errCode})`;
|
||||
}
|
||||
|
||||
console.error(` ${errorMessage}:`, error);
|
||||
|
||||
// 只有在非正常关闭时才显示错误提示
|
||||
if (error.errCode !== 1000) {
|
||||
uni.showToast({
|
||||
title: errorMessage,
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 重连机制
|
||||
*/
|
||||
const attemptReconnect = (registerInfo) => {
|
||||
if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
|
||||
console.error('已达到最大重连次数,停止重连');
|
||||
uni.showToast({
|
||||
title: '连接失败,请检查网络',
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
reconnectAttempts++;
|
||||
connectionState.value = 'reconnecting';
|
||||
|
||||
// 指数退避策略
|
||||
const delay = Math.min(2000 * Math.pow(1.5, reconnectAttempts), 30000);
|
||||
|
||||
console.log(` 将在 ${delay}ms 后尝试重连 (第${reconnectAttempts}次)`);
|
||||
|
||||
reconnectTimer = setTimeout(async () => {
|
||||
console.log(`开始重连 (第${reconnectAttempts}次)`);
|
||||
|
||||
try {
|
||||
const task = await buildWebSocket(registerInfo);
|
||||
if (task) {
|
||||
console.log('重连成功');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`重连失败 (第${reconnectAttempts}次):`, error);
|
||||
// 继续尝试重连
|
||||
if (reconnectAttempts < MAX_RECONNECT_ATTEMPTS) {
|
||||
attemptReconnect(registerInfo);
|
||||
}
|
||||
}
|
||||
}, delay);
|
||||
};
|
||||
|
||||
/**
|
||||
* 关闭WebSocket连接
|
||||
*/
|
||||
const closeWebSocket = () => {
|
||||
console.log('主动关闭WebSocket连接');
|
||||
|
||||
// 停止心跳
|
||||
stopHeartbeat();
|
||||
|
||||
// 清除重连定时器
|
||||
if (reconnectTimer) {
|
||||
clearTimeout(reconnectTimer);
|
||||
reconnectTimer = null;
|
||||
}
|
||||
|
||||
// 重置重连计数器
|
||||
reconnectAttempts = 0;
|
||||
|
||||
// 关闭连接
|
||||
if (socketTask) {
|
||||
socketTask.close({
|
||||
code: 1000, // 正常关闭
|
||||
reason: '用户主动关闭',
|
||||
success: () => {
|
||||
console.log('WebSocket已关闭');
|
||||
connectionState.value = 'disconnected';
|
||||
},
|
||||
fail: (err) => console.error('关闭WebSocket失败:', err)
|
||||
});
|
||||
|
||||
socketTask = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取连接状态
|
||||
*/
|
||||
const getConnectionState = () => connectionState.value;
|
||||
|
||||
/**
|
||||
* 检查是否已连接
|
||||
*/
|
||||
const isConnected = () => connectionState.value === 'connected';
|
||||
|
||||
return {
|
||||
// 主要方法
|
||||
buildWebSocket,
|
||||
closeWebSocket,
|
||||
sendMessage,
|
||||
sendChatMessage,
|
||||
|
||||
// 状态查询
|
||||
getConnectionState,
|
||||
isConnected,
|
||||
|
||||
// 响应式状态(用于UI绑定)
|
||||
connectionState: readonly(connectionState)
|
||||
};
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue