feat: add web application
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
import { SocketEnum } from '@/enums/socketEnum';
|
||||
import { useUserStoreWidthOut } from '@/store/modules/user';
|
||||
import { isJsonString } from '@/utils/is';
|
||||
import { registerGlobalMessage } from '@/utils/websocket/registerMessage';
|
||||
|
||||
// WebSocket消息格式
|
||||
export interface WebSocketMessage {
|
||||
event: string;
|
||||
data: any;
|
||||
code: number;
|
||||
timestamp: number;
|
||||
}
|
||||
|
||||
let socket: WebSocket;
|
||||
let isActive: boolean;
|
||||
const messageHandler: Map<string, Function> = new Map();
|
||||
|
||||
export default () => {
|
||||
const heartCheck = {
|
||||
timeout: 5000,
|
||||
timeoutObj: setTimeout(() => {}),
|
||||
serverTimeoutObj: setInterval(() => {}),
|
||||
reset: function () {
|
||||
clearTimeout(this.timeoutObj);
|
||||
clearTimeout(this.serverTimeoutObj);
|
||||
return this;
|
||||
},
|
||||
start: function () {
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
const self = this;
|
||||
clearTimeout(this.timeoutObj);
|
||||
clearTimeout(this.serverTimeoutObj);
|
||||
this.timeoutObj = setTimeout(function () {
|
||||
socket.send(
|
||||
JSON.stringify({
|
||||
event: SocketEnum.EventPing,
|
||||
})
|
||||
);
|
||||
self.serverTimeoutObj = setTimeout(function () {
|
||||
console.log('[WebSocket] 关闭服务');
|
||||
socket.close();
|
||||
}, self.timeout);
|
||||
}, this.timeout);
|
||||
},
|
||||
};
|
||||
|
||||
const useUserStore = useUserStoreWidthOut();
|
||||
let lockReconnect = false;
|
||||
let timer: ReturnType<typeof setTimeout>;
|
||||
const createSocket = () => {
|
||||
console.log('[WebSocket] createSocket...');
|
||||
if (useUserStore.token === '' || useUserStore.config?.wsAddr == '') {
|
||||
console.error('[WebSocket] 用户未登录,稍后重试...');
|
||||
resetReconnect();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
socket = new WebSocket(`${useUserStore.config?.wsAddr}?authorization=${useUserStore.token}`);
|
||||
init();
|
||||
if (lockReconnect) {
|
||||
lockReconnect = false;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`[WebSocket] createSocket err: ${e}`);
|
||||
resetReconnect();
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
const resetReconnect = () => {
|
||||
if (lockReconnect) {
|
||||
lockReconnect = false;
|
||||
}
|
||||
reconnect();
|
||||
};
|
||||
|
||||
const reconnect = () => {
|
||||
console.log('[WebSocket] lockReconnect:' + lockReconnect);
|
||||
if (lockReconnect) return;
|
||||
lockReconnect = true;
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(() => {
|
||||
createSocket();
|
||||
}, 1000 * 10);
|
||||
};
|
||||
|
||||
const init = () => {
|
||||
socket.onopen = function (_) {
|
||||
console.log('[WebSocket] 已连接');
|
||||
heartCheck.reset().start();
|
||||
isActive = true;
|
||||
};
|
||||
|
||||
socket.onmessage = function (event) {
|
||||
isActive = true;
|
||||
// console.log('WebSocket:收到一条消息', event.data);
|
||||
|
||||
if (!isJsonString(event.data)) {
|
||||
console.log('[WebSocket] message incorrect format:' + JSON.stringify(event));
|
||||
return;
|
||||
}
|
||||
|
||||
heartCheck.reset().start();
|
||||
|
||||
const message = JSON.parse(event.data) as WebSocketMessage;
|
||||
onMessage(message);
|
||||
};
|
||||
|
||||
socket.onerror = function (_) {
|
||||
console.log('[WebSocket] 发生错误');
|
||||
reconnect();
|
||||
isActive = false;
|
||||
};
|
||||
|
||||
socket.onclose = function (_) {
|
||||
console.log('[WebSocket] 已关闭');
|
||||
heartCheck.reset();
|
||||
reconnect();
|
||||
isActive = false;
|
||||
};
|
||||
|
||||
window.onbeforeunload = function () {
|
||||
socket.close();
|
||||
isActive = false;
|
||||
};
|
||||
};
|
||||
|
||||
createSocket();
|
||||
registerGlobalMessage();
|
||||
};
|
||||
|
||||
function onMessage(message: WebSocketMessage) {
|
||||
let handled = false;
|
||||
messageHandler.forEach((value: Function, key: string) => {
|
||||
if (message.event === key || key === '*') {
|
||||
handled = true;
|
||||
value.call(null, message);
|
||||
}
|
||||
});
|
||||
|
||||
if (!handled) {
|
||||
console.log('[WebSocket] messageHandler not registered. message:' + JSON.stringify(message));
|
||||
}
|
||||
}
|
||||
|
||||
// 发送消息
|
||||
export function sendMsg(event: string, data: any = null, isRetry = true) {
|
||||
if (socket === undefined || !isActive) {
|
||||
if (!isRetry) {
|
||||
console.log('[WebSocket] 连接异常,发送失败!');
|
||||
return;
|
||||
}
|
||||
console.log('[WebSocket] 连接异常,等待重试..');
|
||||
setTimeout(() => {
|
||||
sendMsg(event, data);
|
||||
}, 200);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
socket.send(JSON.stringify({ event, data }));
|
||||
} catch (err: any) {
|
||||
console.log('[WebSocket] 发送消息失败,err:', err.message);
|
||||
if (!isRetry) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('[WebSocket] 等待重试..');
|
||||
setTimeout(() => {
|
||||
sendMsg(event, data);
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
|
||||
// 添加消息处理
|
||||
export function addOnMessage(key: string, value: Function): void {
|
||||
messageHandler.set(key, value);
|
||||
}
|
||||
|
||||
// 移除消息处理
|
||||
export function removeOnMessage(key: string): boolean {
|
||||
return messageHandler.delete(key);
|
||||
}
|
||||
|
||||
// 查看所有消息处理
|
||||
export function getAllOnMessage(): Map<string, Function> {
|
||||
return messageHandler;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { TABS_ROUTES } from '@/store/mutation-types';
|
||||
import { SocketEnum } from '@/enums/socketEnum';
|
||||
import { useUserStoreWidthOut } from '@/store/modules/user';
|
||||
import { notificationStoreWidthOut } from '@/store/modules/notification';
|
||||
import { addOnMessage, WebSocketMessage } from '@/utils/websocket/index';
|
||||
|
||||
// 注册全局消息监听
|
||||
export function registerGlobalMessage() {
|
||||
// 心跳
|
||||
addOnMessage(SocketEnum.EventPing, function (_message: WebSocketMessage) {
|
||||
// console.log('ping..');
|
||||
});
|
||||
|
||||
// 强制退出
|
||||
addOnMessage(SocketEnum.EventKick, function (_message: WebSocketMessage) {
|
||||
const useUserStore = useUserStoreWidthOut();
|
||||
useUserStore.logout().then(() => {
|
||||
// 移除标签页
|
||||
localStorage.removeItem(TABS_ROUTES);
|
||||
location.reload();
|
||||
});
|
||||
});
|
||||
|
||||
// 消息通知
|
||||
addOnMessage(SocketEnum.EventNotice, function (message: WebSocketMessage) {
|
||||
const notificationStore = notificationStoreWidthOut();
|
||||
notificationStore.triggerNewMessages(message.data);
|
||||
});
|
||||
|
||||
// 更多全局消息处理都可以在这里注册
|
||||
// ...
|
||||
}
|
||||
Reference in New Issue
Block a user