Browse Source

fix: ZMQ 多个消息订阅统一个主题时回调函数被覆盖问题

main
betaqi 1 day ago
parent
commit
f886d20924
  1. 46
      src/composables/useZMQJsonWorker.ts
  2. 2
      src/utils/zmqJsonWorker.ts

46
src/composables/useZMQJsonWorker.ts

@ -1,4 +1,3 @@
import { WorkerCMD, ZmqCMD, } from '@/utils/zmq'
import type { import type {
ManualAction, ManualAction,
PublishMsg, PublishMsg,
@ -7,8 +6,8 @@ import type {
TimeoutMsg, TimeoutMsg,
ZmqMessage ZmqMessage
} from '@/utils/zmq' } from '@/utils/zmq'
import { WorkerCMD, ZmqCMD, } from '@/utils/zmq'
import webWorker from '@/utils/zmqJsonWorker?worker' import webWorker from '@/utils/zmqJsonWorker?worker'
import dayjs from "dayjs";
const env = import.meta.env const env = import.meta.env
let defaultHost = env.VITE_ZMQ_BASE_URL let defaultHost = env.VITE_ZMQ_BASE_URL
@ -16,10 +15,14 @@ if (env.VITE_APP_ENV === 'local') {
defaultHost = window.location.hostname === 'localhost' ? env.VITE_ZMQ_BASE_URL : window.location.hostname defaultHost = window.location.hostname === 'localhost' ? env.VITE_ZMQ_BASE_URL : window.location.hostname
} }
const SUBDEFAULTKEY = 'default'
type Handler = (msg: SubMsgData | PubMsgData) => void
class ZMQJsonWorker { class ZMQJsonWorker {
private static instance: ZMQJsonWorker | null = null; // ➤ 单例实例 private static instance: ZMQJsonWorker | null = null; // ➤ 单例实例
private worker: Worker; private worker: Worker;
private scribeHandlers: Map<string, (msg: SubMsgData | PubMsgData) => void> = new Map(); private scribeHandlers: Map<string, Map<string, Handler>> = new Map();
private pubTimeoutHandlers: Map<string, (msg: TimeoutMsg) => void> = new Map(); private pubTimeoutHandlers: Map<string, (msg: TimeoutMsg) => void> = new Map();
private readonly host: string; private readonly host: string;
private statusCallback: ((status: string) => void) | null = null; private statusCallback: ((status: string) => void) | null = null;
@ -49,20 +52,33 @@ class ZMQJsonWorker {
} }
subscribe(topic: string, handler: (msg: any) => void, id?: string) { subscribe(topic: string, handler: (msg: any) => void, id?: string) {
this.scribeHandlers.set(`${topic}${id ? `-${id}` : ''}`, handler); const key = id ?? SUBDEFAULTKEY;
this.worker.postMessage({ cmd: WorkerCMD.SUBSCRIBE, topic }); let topicMap = this.scribeHandlers.get(topic);
if (!topicMap) {
topicMap = new Map<string, Handler>();
this.scribeHandlers.set(topic, topicMap);
} }
unsubscribe(topic: string) { // 添加 handler,不会覆盖其他 id 的 handler
// 遍历所有订阅消息,删除包含该主题的订阅 topicMap.set(key, handler);
for (const key in this.scribeHandlers) { this.worker.postMessage({ cmd: WorkerCMD.SUBSCRIBE, topic });
if (key.startsWith(topic)) {
this.scribeHandlers.delete(key);
} }
unsubscribe(topic: string, id?: string) {
const topicMap = this.scribeHandlers.get(topic);
if (!topicMap) return;
if (id) {
topicMap.delete(id);
} else {
topicMap.delete(SUBDEFAULTKEY);
} }
if (topicMap.size === 0) {
this.scribeHandlers.delete(topic);
this.worker.postMessage({ cmd: WorkerCMD.UNSUBSCRIBE, topic }); this.worker.postMessage({ cmd: WorkerCMD.UNSUBSCRIBE, topic });
} }
}
publish<T extends ManualAction>(topic: string, msg: PublishMsg<T>, isTimeout: boolean = false, handler?: (msg: TimeoutMsg) => void, isAlwaysListen: boolean = false) { publish<T extends ManualAction>(topic: string, msg: PublishMsg<T>, isTimeout: boolean = false, handler?: (msg: TimeoutMsg) => void, isAlwaysListen: boolean = false) {
if (isTimeout) { if (isTimeout) {
@ -90,14 +106,16 @@ class ZMQJsonWorker {
} }
private handleSubscribeMessage(topic: string, json: PubMsgData & SubMsgData) { private handleSubscribeMessage(topic: string, json: PubMsgData & SubMsgData) {
const handler = this.scribeHandlers.get(topic); const topicMap = this.scribeHandlers.get(topic);
if (handler) { if (!topicMap) return;
topicMap.forEach((handler, id) => {
try { try {
handler(json); handler(json);
} catch (error) { } catch (error) {
console.error(`主题: ${topic} 处理失败:`, error); console.error(`主题: ${topic} 的 handler ${id} 执行失败:`, error);
}
} }
});
} }
private handleTimeoutMessage(timeoutTopic: string, timeoutId: string) { private handleTimeoutMessage(timeoutTopic: string, timeoutId: string) {

2
src/utils/zmqJsonWorker.ts

@ -1,5 +1,5 @@
import ZmqClient from '@/lib/zmq/zmqClient' import ZmqClient from '@/lib/zmq/zmqClient'
import { WorkerCMD, ZmqCMD, type PublishMsg, type PubMsgData, } from './zmq' import { type PublishMsg, type PubMsgData, WorkerCMD, ZmqCMD, } from './zmq'
const HEARTBEAT_TOPIC = 'HEARTBEAT' const HEARTBEAT_TOPIC = 'HEARTBEAT'

Loading…
Cancel
Save