langjie-m-play 0.0.21 → 0.0.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,4 +4,5 @@ export interface AtsInfo {
4
4
  atsParams: Record<string, any>;
5
5
  started: boolean;
6
6
  atsFile: string;
7
+ ctrlTag: string;
7
8
  }
@@ -3,4 +3,6 @@ export interface AtsLoadResponse<K extends string, V> {
3
3
  atsParam: Record<K, V>;
4
4
  atsButtonList: string[];
5
5
  atsFile: string;
6
+ ctrlTag: string;
7
+ atsName: string;
6
8
  }
@@ -0,0 +1,46 @@
1
+ export declare const LAUNCH_STEP = 256;
2
+ export declare const LAUNCH_ABORTED = 4096;
3
+ export declare const LAUNCH_OK = 8192;
4
+ export declare const CLOSE_STEP = 16384;
5
+ export declare const CLOSE_OK = 32768;
6
+ export declare const RUN_MSG = 512;
7
+ export declare const RUN_EVENT = 768;
8
+ export declare const RUN_EVENT_TOUCH = 784;
9
+ export declare const RUN_WARNING = 1024;
10
+ export declare const RUN_DEBUG = 1280;
11
+ export declare const ATS_LOADING = 1536;
12
+ export declare const ATS_LOAD_ABORTED = 1552;
13
+ export declare const ATS_LOAD_OK = 1568;
14
+ export declare const ATS_STARTING = 1584;
15
+ export declare const ATS_STARTED = 1616;
16
+ export declare const ATS_BREAK = 1632;
17
+ export declare const ATS_CONTINUE = 1648;
18
+ export declare const ATS_CATCH_CONTROLLER = 1664;
19
+ export declare const ATS_RELEASE_CONTROLLER = 1680;
20
+ export declare const ATS_TERMINATING = 1696;
21
+ export declare const ATS_ACTION = 1792;
22
+ export declare const ATS_ABORTED = 2048;
23
+ export declare const ATS_COMPLETED = 2304;
24
+ export declare const ATS_TRIGGER = 2560;
25
+ export declare const ATS_FINAL_ACTION = 3328;
26
+ export declare const ATS_TEST_STARTED = 3088;
27
+ export declare const ATS_TEST_ENDED = 3104;
28
+ export declare const ATS_TEST_ABORTED = 3120;
29
+ export declare const ATS_ARGUMENT = 3136;
30
+ export declare const ATS_RUNTIME = 3152;
31
+ export declare const TEST_FFP = 2816;
32
+ export declare const TEST_FFMAP = 2832;
33
+ export declare const CALI_PARAM = 2848;
34
+ export declare const CTRL_PARAM = 2864;
35
+ export declare const ACTU_PARAM = 2880;
36
+ export declare const SPECIMEN_CLAMPED = 2944;
37
+ export declare const SPECIMEN_LOADING = 2960;
38
+ export declare const SPECIMEN_BROKEN = 2976;
39
+ export declare const SPECIMEN_RELEASED = 2992;
40
+ export declare const API_DEBUG = 3584;
41
+ export declare const SYNC_ALIGNED = 3840;
42
+ export declare const SYNC_GROUP = 3856;
43
+ export declare const SYNC_READY = 3872;
44
+ export declare const SYNC_GO = 3888;
45
+ export declare const SYNC_OK = 3904;
46
+ export declare const SYNC_ABORTED = 3968;
@@ -0,0 +1,46 @@
1
+ export const LAUNCH_STEP = 0x0100; // 启动,及以下正常步骤
2
+ export const LAUNCH_ABORTED = 0x1000; // 启动异常中止
3
+ export const LAUNCH_OK = 0x2000; // 启动正常完成
4
+ export const CLOSE_STEP = 0x4000; // 关闭,及以下步骤
5
+ export const CLOSE_OK = 0x8000; // 关闭正常完成
6
+ export const RUN_MSG = 0x0200; // 运行时信息
7
+ export const RUN_EVENT = 0x0300; // 运行中发生指定事件
8
+ export const RUN_EVENT_TOUCH = 0x0310; // 运行中的触碰事件
9
+ export const RUN_WARNING = 0x0400; // 运行时警告
10
+ export const RUN_DEBUG = 0x0500; // 运行时跟踪信息
11
+ export const ATS_LOADING = 0x0600; // ATS正在加载+ATS句柄(下同)
12
+ export const ATS_LOAD_ABORTED = 0x0610; // ATS加载不成功
13
+ export const ATS_LOAD_OK = 0x0620; // ATS加载成功
14
+ export const ATS_STARTING = 0x0630; // ATS启动中
15
+ export const ATS_STARTED = 0x0650; // ATS已经启动
16
+ export const ATS_BREAK = 0x0660; // ATS(长时间动作)中断
17
+ export const ATS_CONTINUE = 0x0670; // ATS(中断后)继续
18
+ export const ATS_CATCH_CONTROLLER = 0x0680; // ATS抓住控制器
19
+ export const ATS_RELEASE_CONTROLLER = 0x0690; // ATS释放控制器
20
+ export const ATS_TERMINATING = 0x06A0; // ATS终止中
21
+ export const ATS_ACTION = 0x0700; // ATS执行动作+句柄+轴
22
+ export const ATS_ABORTED = 0x0800; // ATS异常退出
23
+ export const ATS_COMPLETED = 0x0900; // ATS结束
24
+ export const ATS_TRIGGER = 0x0A00; // ATS跳转触发器+句柄+轴
25
+ export const ATS_FINAL_ACTION = 0x0D00; // ATS轴最终动作+句柄+轴
26
+ export const ATS_TEST_STARTED = 0x0C10; // 驻留模式的试验开始+ATS句柄,与时序消息同时发出
27
+ export const ATS_TEST_ENDED = 0x0C20;
28
+ export const ATS_TEST_ABORTED = 0x0C30;
29
+ export const ATS_ARGUMENT = 0x0C40; // 全局参数变化
30
+ export const ATS_RUNTIME = 0x0C50; // 运行参数变化
31
+ export const TEST_FFP = 0x0B00; // 侦测位移前馈比例
32
+ export const TEST_FFMAP = 0x0B10; // 侦测位移前馈表
33
+ export const CALI_PARAM = 0x0B20; // 测量通道的标定参数变化
34
+ export const CTRL_PARAM = 0x0B30; // 闭环反馈通道的控制参数变化
35
+ export const ACTU_PARAM = 0x0B40; // 作动器的参数变化
36
+ export const SPECIMEN_CLAMPED = 0x0B80; // 试件
37
+ export const SPECIMEN_LOADING = 0x0B90;
38
+ export const SPECIMEN_BROKEN = 0x0BA0;
39
+ export const SPECIMEN_RELEASED = 0x0BB0;
40
+ export const API_DEBUG = 0x0E00; // 应用调用接口跟踪
41
+ export const SYNC_ALIGNED = 0x0F00; // 对齐
42
+ export const SYNC_GROUP = 0x0F10; // 成组
43
+ export const SYNC_READY = 0x0F20; // 就绪
44
+ export const SYNC_GO = 0x0F30; // 启动
45
+ export const SYNC_OK = 0x0F40;
46
+ export const SYNC_ABORTED = 0x0F80;
@@ -3,5 +3,6 @@ export interface BaseAtsEvent {
3
3
  dateTime: Date;
4
4
  atsHandle: number;
5
5
  eventId: number;
6
+ actionTag: string;
6
7
  eventTag: string;
7
8
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langjie-m-play",
3
- "version": "0.0.21",
3
+ "version": "0.0.23",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -10,4 +10,4 @@ export declare const RemoteWebService: {
10
10
  usingCheck: (params: PlayUseSubmit) => Promise<boolean>;
11
11
  syncRuntimeInfo: (sn: string) => Promise<RuntimeInfo>;
12
12
  };
13
- export declare const request: (sn: any, pathname: any, params: any, headers?: {}) => Promise<any>;
13
+ export declare const request: (sn: any, pathname: any, params: any, headers?: {}, isGet?: boolean) => Promise<any>;
@@ -37,13 +37,13 @@ export const RemoteWebService = {
37
37
  return yield request(sn, '/play/original/getTestingRuntimeInfo', { accountNo: sn });
38
38
  }),
39
39
  };
40
- export const request = (sn_1, pathname_1, params_1, ...args_1) => __awaiter(void 0, [sn_1, pathname_1, params_1, ...args_1], void 0, function* (sn, pathname, params, headers = {}) {
40
+ export const request = (sn_1, pathname_1, params_1, ...args_1) => __awaiter(void 0, [sn_1, pathname_1, params_1, ...args_1], void 0, function* (sn, pathname, params, headers = {}, isGet = false) {
41
41
  let result;
42
42
  const { isHttps, httpUrl } = ServerConfigUtil.getRequestTargetInfo();
43
43
  if (isHttps) {
44
44
  // 走公网代理
45
45
  result = (yield axios({
46
- method: 'post',
46
+ method: isGet ? 'get' : 'post',
47
47
  url: `${httpUrl}/cloudCustomerService/actionStation/request/proxy`,
48
48
  data: {
49
49
  serialNo: sn,
@@ -63,7 +63,7 @@ export const request = (sn_1, pathname_1, params_1, ...args_1) => __awaiter(void
63
63
  }
64
64
  // 走本地环境
65
65
  result = (yield axios({
66
- method: 'post',
66
+ method: isGet ? 'get' : 'post',
67
67
  url: `${httpUrl}:${port}${pathname}`,
68
68
  data: params,
69
69
  headers,
@@ -3,7 +3,6 @@ import { JsonRpcRequest } from "../domain/JsonRpcRequest";
3
3
  import { JsonRpcResponse } from "../domain/JsonRpcResponse";
4
4
  import { OutMsg } from "../domain/OutMsg";
5
5
  import { GtcCallBackMsg } from "../domain/GtcCallBackMsg";
6
- import { ReadDataDO } from "../domain/ReadDataDO";
7
6
  /**
8
7
  * 远程gtc服务socketIO实现
9
8
  */
@@ -11,12 +10,17 @@ declare class GtcServiceSocketIOImpl implements IGtcService {
11
10
  private socket;
12
11
  private connectStatus;
13
12
  private callbackMap;
13
+ private threadPool;
14
14
  constructor();
15
15
  init(url: string, connectCallback: () => void, disconnectCallback: () => void): Promise<boolean>;
16
16
  disconnect(): Promise<void>;
17
17
  call(request: JsonRpcRequest<any>): Promise<any>;
18
18
  reply(response: JsonRpcResponse<any, any>): void;
19
19
  event(response: JsonRpcResponse<OutMsg<GtcCallBackMsg>, any>): void;
20
- dataGram(response: JsonRpcResponse<OutMsg<ReadDataDO>, any>): void;
20
+ /**
21
+ * 将数据加入处理队列(多线程模式)
22
+ * 使用 Web Worker 执行耗时计算,避免阻塞 UI 线程
23
+ */
24
+ dataGram<T>(rsp: T): void;
21
25
  }
22
26
  export default GtcServiceSocketIOImpl;
@@ -14,6 +14,7 @@ class GtcServiceSocketIOImpl {
14
14
  this.connectStatus = ConnectStatusEnum.DISCONNECT;
15
15
  // Call Reply回调函数映射
16
16
  this.callbackMap = {};
17
+ // this.threadPool = new ThreadPoolUtil();
17
18
  }
18
19
  init(url, connectCallback, disconnectCallback) {
19
20
  return new Promise((resolve, reject) => {
@@ -112,9 +113,29 @@ class GtcServiceSocketIOImpl {
112
113
  PubSubUtil.publish(response.slaveInstId + ":" + SubKeyEnum.GTC_EVENT_KEY + ":" + response.result.serviceType + ":" + response.result.ctrlIndex, response.result.data);
113
114
  }
114
115
  }
115
- dataGram(response) {
116
- // 处理数据流
117
- PubSubUtil.publish(response.slaveInstId + ":" + SubKeyEnum.GTC_DATA_GRAM_KEY + ":" + response.result.serviceType + ":" + response.result.ctrlIndex, response.result);
116
+ /**
117
+ * 将数据加入处理队列(多线程模式)
118
+ * 使用 Web Worker 执行耗时计算,避免阻塞 UI 线程
119
+ */
120
+ dataGram(rsp) {
121
+ const response = rsp;
122
+ const publishKey = response.slaveInstId + ":" + SubKeyEnum.GTC_DATA_GRAM_KEY + ":" +
123
+ response.result.serviceType + ":" + response.result.ctrlIndex;
124
+ // this.threadPool.pushTask({
125
+ // compute: data => {
126
+ // const timeStamp = Date.now();
127
+ // while (Date.now() - timeStamp < 50) {
128
+ //
129
+ // }
130
+ // return { result: data.response.result };
131
+ // },
132
+ // // 传递给计算函数的数据
133
+ // computeData: { response },
134
+ // // 在主线程执行
135
+ // callback: (response) => {
136
+ PubSubUtil.publish(publishKey, response.result);
137
+ // }
138
+ // });
118
139
  }
119
140
  }
120
141
  export default GtcServiceSocketIOImpl;
@@ -3,7 +3,6 @@ import { JsonRpcRequest } from "../domain/JsonRpcRequest";
3
3
  import { JsonRpcResponse } from "../domain/JsonRpcResponse";
4
4
  import { OutMsg } from "../domain/OutMsg";
5
5
  import { GtcCallBackMsg } from "../domain/GtcCallBackMsg";
6
- import { ReadDataDO } from "../domain/ReadDataDO";
7
6
  /**
8
7
  * 远程gtc服务WebSocket实现
9
8
  */
@@ -20,6 +19,7 @@ declare class GtcServiceWebSocketImpl implements IGtcService {
20
19
  private m_reconnectAttempts;
21
20
  private m_isNormalClose;
22
21
  constructor();
22
+ buffer2GramJson(buffer: Uint8Array): void;
23
23
  init(url: string, connectCallback: () => void, disconnectCallback: () => void): Promise<boolean>;
24
24
  _initWebSocket(): Promise<boolean>;
25
25
  _reconnect(): void;
@@ -27,6 +27,6 @@ declare class GtcServiceWebSocketImpl implements IGtcService {
27
27
  call(request: JsonRpcRequest<any>): Promise<any>;
28
28
  reply(response: JsonRpcResponse<any, any>): void;
29
29
  event(response: JsonRpcResponse<OutMsg<GtcCallBackMsg>, any>): void;
30
- dataGram(response: JsonRpcResponse<OutMsg<ReadDataDO>, any>): void;
30
+ dataGram<T>(rsp: T): void;
31
31
  }
32
32
  export default GtcServiceWebSocketImpl;
@@ -14,6 +14,8 @@ import { PubSubUtil } from "../utils/PubSubUtil";
14
14
  import { SubKeyEnum } from "../utils/enums/SubKeyEnum";
15
15
  // @ts-ignore
16
16
  import { MsgEventTypeEnum } from "../domain/enums/MsgEventTypeEnum";
17
+ import Dvb from "../utils/Dvb";
18
+ import { DataGramUtil } from "../utils/DataGramUtil";
17
19
  /**
18
20
  * 远程gtc服务WebSocket实现
19
21
  */
@@ -33,6 +35,53 @@ class GtcServiceWebSocketImpl {
33
35
  //是否正常关闭,正常关闭不重连
34
36
  this.m_isNormalClose = false;
35
37
  }
38
+ buffer2GramJson(buffer) {
39
+ const retGramJson = {
40
+ "error": null,
41
+ "event": "R_GRAM_LIST",
42
+ "id": null,
43
+ "method": null,
44
+ "result": {
45
+ "ctrlIndex": 0,
46
+ "data": {
47
+ "DataGramList": []
48
+ },
49
+ "msgEventType": 1,
50
+ "serviceType": 2
51
+ },
52
+ "slaveInstId": null,
53
+ "timestamp": 0
54
+ };
55
+ const tagLength = DataGramUtil.tagLength();
56
+ if (buffer.length % (tagLength * 4) != 0) {
57
+ console.error("length is err", tagLength, buffer.length);
58
+ return;
59
+ }
60
+ const dataView = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
61
+ const dataGramList = [];
62
+ // 单行长度 = 标签个数 × 4字节(uint32_t占4字节)
63
+ const singleLineLength = tagLength * 4;
64
+ for (let lineOffset = 0; lineOffset < buffer.length; lineOffset += singleLineLength) {
65
+ // 单个数据项的uint32数组(对应原line)
66
+ const singleLineItemList = [];
67
+ // 遍历当前数据项的所有标签,拼接4字节为uint32
68
+ for (let tagIdx = 0; tagIdx < tagLength; tagIdx++) {
69
+ // 计算当前标签在DataView中的字节偏移(行偏移 + 标签偏移×4字节)
70
+ const byteOffset = lineOffset + (tagIdx * 4);
71
+ const uint32Value = dataView.getUint32(byteOffset, true);
72
+ if (DataGramUtil.isDVB(tagIdx)) {
73
+ const strValue = Dvb.Dvb2String(uint32Value);
74
+ singleLineItemList.push(strValue);
75
+ }
76
+ else {
77
+ singleLineItemList.push(uint32Value.toString(10));
78
+ }
79
+ }
80
+ dataGramList.push(singleLineItemList);
81
+ }
82
+ retGramJson.result.data.DataGramList = dataGramList;
83
+ this.dataGram(retGramJson);
84
+ }
36
85
  init(url, connectCallback, disconnectCallback) {
37
86
  this.m_connectCallback = connectCallback;
38
87
  this.m_disconnectCallback = disconnectCallback;
@@ -43,20 +92,39 @@ class GtcServiceWebSocketImpl {
43
92
  _initWebSocket() {
44
93
  const that = this;
45
94
  return new Promise((resolve, reject) => {
46
- setTimeout(() => reject("服务器连接失败"), 2000);
95
+ const timeoutTimer = setTimeout(() => reject("服务器连接失败"), 2000);
47
96
  // 判断是否已经连接
48
97
  if (that.socket && (that.socket.readyState == WebSocket.OPEN || that.socket.readyState == WebSocket.CONNECTING)) {
49
98
  resolve(true);
50
99
  return;
51
100
  }
101
+ if (that.socket) {
102
+ that.socket.onopen = null;
103
+ that.socket.onmessage = null;
104
+ that.socket.onclose = null;
105
+ that.socket.onerror = null;
106
+ that.socket = null;
107
+ }
52
108
  that.socket = new WebSocket(that.m_url);
53
109
  that.socket.id = 0;
54
110
  that.socket.onopen = function () {
55
111
  console.log("open success");
112
+ clearTimeout(timeoutTimer);
56
113
  };
57
114
  that.socket.onmessage = function (e) {
115
+ if (e.data instanceof Blob) {
116
+ let blob = e.data;
117
+ const reader = new FileReader();
118
+ reader.onload = function (e) {
119
+ let arrayBuffer = e.target.result;
120
+ // @ts-ignore
121
+ let bs = new Uint8Array(arrayBuffer);
122
+ that.buffer2GramJson(bs);
123
+ };
124
+ reader.readAsArrayBuffer(blob);
125
+ return;
126
+ }
58
127
  let response = JSON.parse(e.data);
59
- PubSubUtil.publish("", response);
60
128
  switch (response.event) {
61
129
  case JsonRpcEventEnum.REPLY:
62
130
  that.reply(response);
@@ -81,7 +149,8 @@ class GtcServiceWebSocketImpl {
81
149
  }
82
150
  break;
83
151
  }
84
- default: break;
152
+ default:
153
+ break;
85
154
  }
86
155
  };
87
156
  that.socket.onclose = function () {
@@ -163,7 +232,8 @@ class GtcServiceWebSocketImpl {
163
232
  PubSubUtil.publish(response.slaveInstId + ":" + SubKeyEnum.GTC_EVENT_KEY + ":" + response.result.serviceType + ":" + response.result.ctrlIndex, response.result.data);
164
233
  }
165
234
  }
166
- dataGram(response) {
235
+ dataGram(rsp) {
236
+ const response = rsp;
167
237
  // 处理数据流
168
238
  PubSubUtil.publish(response.slaveInstId + ":" + SubKeyEnum.GTC_DATA_GRAM_KEY + ":" + response.result.serviceType + ":" + response.result.ctrlIndex, response.result);
169
239
  }
@@ -1,7 +1,6 @@
1
1
  import { JsonRpcRequest } from "../domain/JsonRpcRequest";
2
2
  import { JsonRpcResponse } from "../domain/JsonRpcResponse";
3
3
  import { OutMsg } from "../domain/OutMsg";
4
- import { ReadDataDO } from "../domain/ReadDataDO";
5
4
  import { GtcCallBackMsg } from "../domain/GtcCallBackMsg";
6
5
  /**
7
6
  * 远程gtc服务接口
@@ -12,6 +11,6 @@ interface IGtcService {
12
11
  call(request: JsonRpcRequest<any>): Promise<any>;
13
12
  reply(response: JsonRpcResponse<any, any>): any;
14
13
  event(response: JsonRpcResponse<OutMsg<GtcCallBackMsg>, any>): any;
15
- dataGram(response: JsonRpcResponse<OutMsg<ReadDataDO>, any>): any;
14
+ dataGram<T>(response: T): any;
16
15
  }
17
16
  export default IGtcService;
@@ -22,6 +22,7 @@ export declare class MPlay {
22
22
  private ctrlRuntimeInfo;
23
23
  private ctrlMsgCallback;
24
24
  private channelHandleMap;
25
+ private static decodeId;
25
26
  /**
26
27
  * Connect to the MPlay server.
27
28
  * Direct Connection Mode.
package/service/MPlay.js CHANGED
@@ -17,7 +17,17 @@ import { RemoteWebService } from "../server/RemoteWebService";
17
17
  import GtcServiceFactory from "./GtcServiceFactory";
18
18
  import { CommunicationTypeEnum } from "../domain/enums/CommunicationTypeEnum";
19
19
  import { ServerConfigUtil } from "../utils/ServerConfigUtil";
20
+ import { DataGramUtil } from "../utils/DataGramUtil";
21
+ import { ATS_ABORTED, ATS_ACTION, ATS_COMPLETED, ATS_STARTED } from "../domain/VtcMsgTypeConstant";
20
22
  export class MPlay {
23
+ static decodeId(msgCode) {
24
+ let id = (msgCode & 0x000F);
25
+ if (msgCode & 0x4000) {
26
+ id |= 0x0010;
27
+ }
28
+ let codeType = (msgCode & 0x3FF0);
29
+ return [codeType, id];
30
+ }
21
31
  /**
22
32
  * Connect to the MPlay server.
23
33
  * Direct Connection Mode.
@@ -90,35 +100,20 @@ export class MPlay {
90
100
  if (this.ctrlMsgCallback) {
91
101
  this.ctrlMsgCallback(msg);
92
102
  }
93
- // console.log(msg);
94
- // console.log(ctrlIndex + "<<>>" + msg.msgId.toString(16));
95
- if (msg.msgId === 0x2000) {
96
- // PubSubUtil.publish(SubKeyEnum.LAUNCH_OK, { instId, ctrlIndex });
97
- }
98
- else if (msg.msgId >= 0x0620 && msg.msgId < 0x0630) {
99
- // ats加载成功
100
- // PubSubUtil.publish(SubKeyEnum.ATS_LOAD_OK, { instId, ctrlIndex });
101
- }
102
- else if (msg.msgId >= 0x0650 && msg.msgId < 0x0660) {
103
- // ats启动成功
103
+ const msgDecodeResult = MPlay.decodeId(msg.msgId);
104
+ if (msgDecodeResult[0] === ATS_STARTED) {
104
105
  PubSubUtil.publish(SubKeyEnum.ATS_START_OK, { instId, ctrlIndex });
105
106
  }
106
- else if (msg.msgId >= 0x0700 && msg.msgId < 0x0800) {
107
- // ats跳转到指定步骤
108
- const hAts = msg.msgId & 0x00F0 >> 4;
109
- PubSubUtil.publish(SubKeyEnum.ATS_JUMP_ACTION, { instId, ctrlIndex, hAts, step: msg.msg });
107
+ else if (msgDecodeResult[0] === ATS_ACTION) {
108
+ PubSubUtil.publish(SubKeyEnum.ATS_JUMP_ACTION, { instId, ctrlIndex, hAts: msgDecodeResult[1], step: msg.msg });
110
109
  }
111
- else if (msg.msgId >= 0x0800 && msg.msgId < 0x0900) {
112
- // ats异常停止
110
+ else if (msgDecodeResult[0] === ATS_ABORTED) {
113
111
  PubSubUtil.publish(SubKeyEnum.ATS_TERMINATE_ABNORMAL, { instId, ctrlIndex });
114
- const hAts = msg.msgId & 0x00F0 >> 4;
115
- delete this.atsHandleNameMap[hAts];
112
+ delete this.atsHandleNameMap[msgDecodeResult[1]];
116
113
  }
117
- else if (msg.msgId >= 0x0900 && msg.msgId < 0x0910) {
118
- // ats正常停止
114
+ else if (msgDecodeResult[0] === ATS_COMPLETED) {
119
115
  PubSubUtil.publish(SubKeyEnum.ATS_TERMINATE, { instId, ctrlIndex });
120
- const hAts = msg.msgId & 0x00F0 >> 4;
121
- delete this.atsHandleNameMap[hAts];
116
+ delete this.atsHandleNameMap[msgDecodeResult[1]];
122
117
  }
123
118
  });
124
119
  GtcClient.listenAtsEventMsg(this.instId, this.serviceType, this.ctrlIndex, (msgList) => {
@@ -238,7 +233,7 @@ export class MPlay {
238
233
  this.ctrlRuntimeInfo = runtimeInfo;
239
234
  if (runtimeInfo && runtimeInfo.atsInfoList && runtimeInfo.atsInfoList.length > 0) {
240
235
  runtimeInfo.atsInfoList.forEach(atsInfo => {
241
- this.atsHandleNameMap[atsInfo.handle] = atsInfo.atsName;
236
+ this.atsHandleNameMap[atsInfo.handle] = atsInfo.ctrlTag + '-' + atsInfo.atsName;
242
237
  if (atsInfo.started) {
243
238
  this.atsStartedMark[atsInfo.handle] = true;
244
239
  }
@@ -256,6 +251,7 @@ export class MPlay {
256
251
  subscribeForDatagram(tags, fn) {
257
252
  return __awaiter(this, void 0, void 0, function* () {
258
253
  this.dataGramCallBack = fn;
254
+ DataGramUtil.registerTag(tags);
259
255
  const result = yield GtcClient.subscribeForDatagram(this.instId, this.serviceType, tags);
260
256
  result.forEach(item => {
261
257
  this.channelHandleMap[item.tag] = item.handle;
@@ -291,7 +287,7 @@ export class MPlay {
291
287
  load(atsScriptName, actualCtrlTag, fn) {
292
288
  return __awaiter(this, void 0, void 0, function* () {
293
289
  for (const atsHandle in this.atsHandleNameMap) {
294
- if (this.atsHandleNameMap[atsHandle] !== atsScriptName) {
290
+ if (this.atsHandleNameMap[atsHandle] !== actualCtrlTag + '-' + atsScriptName) {
295
291
  continue;
296
292
  }
297
293
  const atsInfo = this.ctrlRuntimeInfo.atsInfoList.filter(atsInfo => atsInfo.handle === Number(atsHandle))[0];
@@ -302,6 +298,8 @@ export class MPlay {
302
298
  atsParam: atsInfo.atsParams,
303
299
  atsButtonList: [],
304
300
  atsFile: atsInfo.atsFile,
301
+ ctrlTag: atsInfo.ctrlTag,
302
+ atsName: atsInfo.atsName,
305
303
  };
306
304
  }
307
305
  }
@@ -311,7 +309,7 @@ export class MPlay {
311
309
  throw new Error("Failed to load ATS script");
312
310
  }
313
311
  this.atsStartedMark[atsHandle] = false;
314
- this.atsHandleNameMap[atsHandle] = atsScriptName;
312
+ this.atsHandleNameMap[atsHandle] = actualCtrlTag + '-' + atsScriptName;
315
313
  this.atsEventCallbackMap[atsHandle] = fn;
316
314
  // @ts-ignore
317
315
  return atsLoadResponse;
@@ -327,7 +325,7 @@ export class MPlay {
327
325
  const atsStartSynchronizer = new TaskSynchronizer();
328
326
  PubSubUtil.subscribe(SubKeyEnum.ATS_START_OK, atsHandle.toString(), (eventMsg) => __awaiter(this, void 0, void 0, function* () { return atsStartSynchronizer.finishTaskKey(atsHandle.toString()); }));
329
327
  atsStartSynchronizer.addTaskKey(atsHandle.toString());
330
- yield GtcClient.atsStart(this.instId, this.serviceType, this.ctrlIndex, atsHandle, this.atsHandleNameMap[atsHandle]);
328
+ yield GtcClient.atsStart(this.instId, this.serviceType, this.ctrlIndex, atsHandle, this.atsHandleNameMap[atsHandle].split('-')[1]);
331
329
  yield atsStartSynchronizer.waitAll();
332
330
  PubSubUtil.unsubscribe(SubKeyEnum.ATS_START_OK, atsHandle.toString());
333
331
  this.atsStartedMark[atsHandle] = true;
@@ -0,0 +1,17 @@
1
+ export declare class DataGramUtil {
2
+ private static TAG_LIST;
3
+ private static FLAG_TAG_LIST;
4
+ /**
5
+ * 注册订阅串
6
+ *
7
+ * @param tags 订阅串
8
+ */
9
+ static registerTag(tags: string): void;
10
+ /**
11
+ * 根据索引判断是否DVB码
12
+ *
13
+ * @param index
14
+ */
15
+ static isDVB(index: number): boolean;
16
+ static tagLength(): number;
17
+ }
@@ -0,0 +1,29 @@
1
+ export class DataGramUtil {
2
+ /**
3
+ * 注册订阅串
4
+ *
5
+ * @param tags 订阅串
6
+ */
7
+ static registerTag(tags) {
8
+ DataGramUtil.TAG_LIST = tags.split(',');
9
+ }
10
+ /**
11
+ * 根据索引判断是否DVB码
12
+ *
13
+ * @param index
14
+ */
15
+ static isDVB(index) {
16
+ const tag = DataGramUtil.TAG_LIST[index];
17
+ for (let i = 0; i < DataGramUtil.FLAG_TAG_LIST.length; i++) {
18
+ if (tag.endsWith(DataGramUtil.FLAG_TAG_LIST[i])) {
19
+ return false;
20
+ }
21
+ }
22
+ return true;
23
+ }
24
+ static tagLength() {
25
+ return DataGramUtil.TAG_LIST.length;
26
+ }
27
+ }
28
+ DataGramUtil.TAG_LIST = [];
29
+ DataGramUtil.FLAG_TAG_LIST = ['Time', 'Event', 'Intent'];
package/utils/Dvb.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ declare class Dvb {
2
+ static DvbIsPositive(dv: number): boolean;
3
+ static DvbIsInteger(dv: number): boolean;
4
+ static DotOfDvb(dv: number): number;
5
+ static Dvb2Float(dv: number): number;
6
+ static Dvb2Int(dvb: number): number;
7
+ static Float2Dvb(fv: number, dot: number): number;
8
+ static Round2Int(f: number): number;
9
+ static Int2Dvb(iv: number): number;
10
+ static Dvb2String(dv: any): number;
11
+ static String2Dvb(str: string): number;
12
+ }
13
+ export default Dvb;
package/utils/Dvb.js ADDED
@@ -0,0 +1,174 @@
1
+ const FMULTI = [1.0, 0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001];
2
+ const MULTI = [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000];
3
+ const DECIMUL = [1, 10, 100, 1000, 10000, 100000, 1000000];
4
+ const NEGABIT = 0x80000000;
5
+ class Dvb {
6
+ static DvbIsPositive(dv) {
7
+ return ((dv & NEGABIT) == 0);
8
+ }
9
+ static DvbIsInteger(dv) {
10
+ return ((dv & 0x70000000) == 0);
11
+ }
12
+ static DotOfDvb(dv) {
13
+ return ((dv & 0x70000000) >> 28);
14
+ }
15
+ static Dvb2Float(dv) {
16
+ let dot = ((dv & 0x70000000) >> 28);
17
+ let iv = Dvb.Dvb2Int(dv & 0x8FFFFFFF);
18
+ let v = iv * FMULTI[dot];
19
+ return (v);
20
+ }
21
+ static Dvb2Int(dvb) {
22
+ let dot = Dvb.DotOfDvb(dvb);
23
+ if (dot != 0) {
24
+ dvb >>= (dot * 4);
25
+ }
26
+ let iv = 0;
27
+ for (let i = 0; i < (7 - dot); i++) {
28
+ iv += (dvb & 0x0000000f) * DECIMUL[i];
29
+ dvb >>= 4;
30
+ }
31
+ return ((dvb & 0x00000008) > 0 ? -iv : iv);
32
+ }
33
+ static Float2Dvb(fv, dot) {
34
+ dot = Math.max(0, dot);
35
+ dot = Math.min(7, dot);
36
+ let mf = fv * MULTI[dot];
37
+ mf = Math.max(-9999999.0, mf);
38
+ mf = Math.min(9999999.0, mf);
39
+ let dvb = Dvb.Int2Dvb(Dvb.Round2Int(mf));
40
+ return (dvb | (dot << 28));
41
+ }
42
+ static Round2Int(f) {
43
+ if (f >= 0.0) {
44
+ return (Number.parseInt(String(f + 0.4)));
45
+ }
46
+ else {
47
+ return (Number.parseInt(String(f - 0.4)));
48
+ }
49
+ }
50
+ static Int2Dvb(iv) {
51
+ let isNega = (iv < 0);
52
+ if (isNega) {
53
+ iv = -iv;
54
+ }
55
+ let shift = 0;
56
+ let dvb = 0;
57
+ for (let i = 0; i < 7; i++) {
58
+ let deci = iv % 10;
59
+ if (deci != 0) {
60
+ dvb |= (deci << shift);
61
+ }
62
+ iv /= 10;
63
+ shift += 4;
64
+ }
65
+ if (isNega) {
66
+ dvb |= NEGABIT;
67
+ }
68
+ return (dvb);
69
+ }
70
+ static Dvb2String(dv) {
71
+ let negative = !Dvb.DvbIsPositive(dv);
72
+ let dot = Dvb.DotOfDvb(dv);
73
+ let dwidth = 7;
74
+ let mask = 0x0f000000;
75
+ let i = 0;
76
+ let strBuf = [];
77
+ for (i = 0; i < 7; i++) { // 确定有效数字宽度
78
+ if (mask & dv) {
79
+ break;
80
+ }
81
+ dwidth--;
82
+ mask >>= 4;
83
+ }
84
+ if (dwidth == 0) { // 特例全0
85
+ let p = 0;
86
+ // @ts-ignore
87
+ strBuf[p++] = '0'.charCodeAt();
88
+ if (dot >= 1) {
89
+ // @ts-ignore
90
+ strBuf[p++] = '.'.charCodeAt();
91
+ for (let i = 0; i < dot; i++) {
92
+ // @ts-ignore
93
+ strBuf[p++] = "0".charCodeAt();
94
+ }
95
+ }
96
+ strBuf[p++] = 0;
97
+ return String.fromCharCode.apply(String, strBuf).replaceAll("\0", "");
98
+ }
99
+ let stringLen;
100
+ if (dot == 0) {
101
+ stringLen = dwidth;
102
+ }
103
+ else {
104
+ stringLen = Math.max(dwidth + 1, dot + 2);
105
+ }
106
+ if (negative) {
107
+ stringLen++;
108
+ }
109
+ strBuf[stringLen] = 0; // 从末尾开始形成字符串
110
+ let dcount = 0;
111
+ let needDot = (dot != 0);
112
+ for (i = stringLen - 1; i >= 0; i--) {
113
+ if (needDot && dcount == dot) {
114
+ needDot = false;
115
+ // @ts-ignore
116
+ strBuf[i] = ".".charCodeAt();
117
+ }
118
+ else if (dcount < dwidth) {
119
+ let d = (dv & 0x0000000f);
120
+ if (d < 10) {
121
+ // @ts-ignore
122
+ strBuf[i] = d + "0".charCodeAt();
123
+ }
124
+ else {
125
+ // @ts-ignore
126
+ strBuf[i] = (d - 10 + "A".charCodeAt());
127
+ }
128
+ dv >>= 4;
129
+ dcount++;
130
+ }
131
+ else if (i == 0 && negative) {
132
+ // @ts-ignore
133
+ strBuf[i] = '-'.charCodeAt();
134
+ }
135
+ else {
136
+ // @ts-ignore
137
+ strBuf[i] = '0'.charCodeAt();
138
+ dcount++;
139
+ }
140
+ }
141
+ return String.fromCharCode.apply(String, strBuf).replaceAll("\0", "");
142
+ }
143
+ // 隐含条件:str是一个格式良好的字符串,没有非法字符,顶多有一个小数点,负号一定在首位,有效数字不超过7个
144
+ static String2Dvb(str) {
145
+ let rightIndex = str.length - 1; // 字符串数字右端位置
146
+ let negative = (str[0] == '-') ? 1 : 0;
147
+ let leftIndex = negative ? 1 : 0; // 字符串数字左端位置
148
+ let dvb = 0x00000000;
149
+ let dotFound = 0;
150
+ let dot = 0;
151
+ for (let i = leftIndex; i <= rightIndex; i++) { // 从左端高位开始转换,方便移位
152
+ let c = str[i];
153
+ if (c == '.') { // 遇到小数点
154
+ dotFound = 1;
155
+ }
156
+ else { // 遇到数字
157
+ dvb <<= 4;
158
+ // @ts-ignore
159
+ dvb |= (c - '0');
160
+ if (dotFound) {
161
+ dot++;
162
+ }
163
+ }
164
+ }
165
+ if (negative) {
166
+ dvb |= NEGABIT;
167
+ }
168
+ if (dot > 0) {
169
+ dvb |= (dot << 28);
170
+ }
171
+ return (dvb);
172
+ }
173
+ }
174
+ export default Dvb;
@@ -0,0 +1,48 @@
1
+ export interface WorkerTask {
2
+ compute?: (data?: any) => any;
3
+ computeData?: any;
4
+ callback?: (result?: any) => void;
5
+ }
6
+ export declare class ThreadPoolUtil {
7
+ private dataGramQueue;
8
+ private workerPool;
9
+ private readonly maxWorkers;
10
+ private taskIdCounter;
11
+ private pendingTasks;
12
+ private workerIndex;
13
+ private useWorker;
14
+ constructor();
15
+ /**
16
+ * 添加待执行任务
17
+ */
18
+ pushTask(task: WorkerTask): void;
19
+ /**
20
+ * 处理下一个任务
21
+ */
22
+ private processNextTask;
23
+ /**
24
+ * 在主线程执行任务(兼容旧接口)
25
+ */
26
+ private executeOnMainThread;
27
+ /**
28
+ * 使用 Web Worker 执行任务
29
+ */
30
+ private executeWithWorker;
31
+ /**
32
+ * 获取可用的 Worker(轮询方式)
33
+ */
34
+ private getAvailableWorker;
35
+ /**
36
+ * 启动工作池,创建多个 Web Worker
37
+ */
38
+ private startWorkerPool;
39
+ /**
40
+ * 创建内联 Worker(通过 Blob URL)
41
+ * 这是一个备选方案,当无法加载外部 Worker 文件时使用
42
+ */
43
+ private createInlineWorker;
44
+ /**
45
+ * 销毁 Worker 池
46
+ */
47
+ destroy(): void;
48
+ }
@@ -0,0 +1,299 @@
1
+ export class ThreadPoolUtil {
2
+ constructor() {
3
+ // 数据流处理队列和工作池
4
+ this.dataGramQueue = [];
5
+ this.workerPool = [];
6
+ this.maxWorkers = 1; // 最大并发工作线程数
7
+ this.taskIdCounter = 0;
8
+ this.pendingTasks = new Map();
9
+ this.workerIndex = 0;
10
+ this.useWorker = true; // 是否使用 Worker
11
+ // 初始化工作池
12
+ this.startWorkerPool();
13
+ }
14
+ /**
15
+ * 添加待执行任务
16
+ */
17
+ pushTask(task) {
18
+ this.dataGramQueue.push(task);
19
+ this.processNextTask();
20
+ }
21
+ /**
22
+ * 处理下一个任务
23
+ */
24
+ processNextTask() {
25
+ if (this.dataGramQueue.length === 0) {
26
+ return;
27
+ }
28
+ const task = this.dataGramQueue.shift();
29
+ if (!task) {
30
+ return;
31
+ }
32
+ // 检查是否是新接口(有 compute 函数)且 Worker 可用
33
+ if (this.useWorker && 'compute' in task && task.compute) {
34
+ // 使用 Web Worker 执行计算部分
35
+ this.executeWithWorker(task);
36
+ }
37
+ else {
38
+ // 兼容旧接口:在主线程执行,或者 Worker 不可用时回退
39
+ this.executeOnMainThread(task);
40
+ }
41
+ }
42
+ /**
43
+ * 在主线程执行任务(兼容旧接口)
44
+ */
45
+ executeOnMainThread(task) {
46
+ try {
47
+ let result;
48
+ if (task.compute) {
49
+ result = task.compute();
50
+ }
51
+ if (task.callback) {
52
+ task.callback(result);
53
+ }
54
+ }
55
+ catch (error) {
56
+ console.error('主线程执行任务时出错:', error);
57
+ }
58
+ // 继续处理下一个任务
59
+ this.processNextTask();
60
+ }
61
+ /**
62
+ * 使用 Web Worker 执行任务
63
+ */
64
+ executeWithWorker(task) {
65
+ const taskId = `task_${this.taskIdCounter++}`;
66
+ const worker = this.getAvailableWorker();
67
+ // 保存任务信息
68
+ this.pendingTasks.set(taskId, { task });
69
+ // 将计算函数序列化为字符串
70
+ let computeFnString = '';
71
+ if (task.compute) {
72
+ // 获取函数体
73
+ const fnString = task.compute.toString();
74
+ // 提取函数体部分(去掉 function 声明)
75
+ if (fnString.startsWith('function')) {
76
+ // function name(data) { ... }
77
+ const bodyMatch = fnString.match(/\{([\s\S]*)\}$/);
78
+ if (bodyMatch) {
79
+ computeFnString = bodyMatch[1];
80
+ }
81
+ }
82
+ else if (fnString.includes('=>')) {
83
+ // 箭头函数: (data) => { ... } 或 (data) => ...
84
+ // 更精确的匹配:找到 => 后面的部分
85
+ const arrowIndex = fnString.indexOf('=>');
86
+ if (arrowIndex !== -1) {
87
+ let bodyPart = fnString.substring(arrowIndex + 2).trim();
88
+ // 如果函数体用 {} 包裹,提取内容
89
+ if (bodyPart.startsWith('{')) {
90
+ // 找到匹配的 }
91
+ let braceCount = 0;
92
+ let endIndex = -1;
93
+ for (let i = 0; i < bodyPart.length; i++) {
94
+ if (bodyPart[i] === '{')
95
+ braceCount++;
96
+ if (bodyPart[i] === '}')
97
+ braceCount--;
98
+ if (braceCount === 0 && bodyPart[i] === '}') {
99
+ endIndex = i;
100
+ break;
101
+ }
102
+ }
103
+ if (endIndex !== -1) {
104
+ computeFnString = bodyPart.substring(1, endIndex).trim();
105
+ }
106
+ else {
107
+ // 如果找不到匹配的 },使用整个 bodyPart(去掉开头的 {)
108
+ computeFnString = bodyPart.substring(1).trim();
109
+ }
110
+ }
111
+ else {
112
+ // 单行表达式,添加 return
113
+ computeFnString = `return ${bodyPart}`;
114
+ }
115
+ }
116
+ }
117
+ else {
118
+ computeFnString = fnString;
119
+ }
120
+ }
121
+ // 验证 Worker 对象
122
+ if (!worker) {
123
+ console.error('Worker 对象为空,无法发送消息');
124
+ this.executeOnMainThread(task);
125
+ return;
126
+ }
127
+ // 发送任务到 Worker
128
+ const message = {
129
+ type: 'TASK',
130
+ task: {
131
+ id: taskId,
132
+ computeFn: computeFnString,
133
+ data: task.computeData
134
+ }
135
+ };
136
+ try {
137
+ worker.postMessage(message);
138
+ }
139
+ catch (e) {
140
+ console.error('发送消息到 Worker 失败:', e);
141
+ // 如果发送失败,回退到主线程执行
142
+ this.executeOnMainThread(task);
143
+ }
144
+ // 设置 Worker 消息监听(一次性)
145
+ const messageHandler = (e) => {
146
+ const message = e.data;
147
+ if (message.taskId === taskId) {
148
+ worker.removeEventListener('message', messageHandler);
149
+ const pendingTask = this.pendingTasks.get(taskId);
150
+ if (pendingTask) {
151
+ this.pendingTasks.delete(taskId);
152
+ if (message.type === 'RESULT') {
153
+ // 计算完成,在主线程执行回调
154
+ try {
155
+ if ('callback' in pendingTask.task && pendingTask.task.callback) {
156
+ pendingTask.task.callback(message.result);
157
+ }
158
+ }
159
+ catch (error) {
160
+ console.error('执行回调函数时出错:', error);
161
+ }
162
+ }
163
+ else if (message.type === 'ERROR') {
164
+ console.error(`Worker 执行任务 ${taskId} 时出错:`, message.error);
165
+ }
166
+ }
167
+ // 继续处理下一个任务
168
+ this.processNextTask();
169
+ }
170
+ };
171
+ worker.addEventListener('message', messageHandler);
172
+ // 错误处理
173
+ const errorHandler = (error) => {
174
+ worker.removeEventListener('error', errorHandler);
175
+ console.error(`Worker 错误:`, error);
176
+ const pendingTask = this.pendingTasks.get(taskId);
177
+ if (pendingTask) {
178
+ this.pendingTasks.delete(taskId);
179
+ }
180
+ this.processNextTask();
181
+ };
182
+ worker.addEventListener('error', errorHandler);
183
+ }
184
+ /**
185
+ * 获取可用的 Worker(轮询方式)
186
+ */
187
+ getAvailableWorker() {
188
+ const worker = this.workerPool[this.workerIndex];
189
+ this.workerIndex = (this.workerIndex + 1) % this.workerPool.length;
190
+ return worker;
191
+ }
192
+ /**
193
+ * 启动工作池,创建多个 Web Worker
194
+ */
195
+ startWorkerPool() {
196
+ try {
197
+ for (let i = 0; i < this.maxWorkers; i++) {
198
+ let worker;
199
+ let workerType = '';
200
+ // 优先使用内联 Worker(更可靠,不依赖外部文件)
201
+ try {
202
+ worker = this.createInlineWorker();
203
+ workerType = 'inline (Blob URL)';
204
+ }
205
+ catch (e) {
206
+ throw e;
207
+ }
208
+ // 验证 Worker 对象
209
+ if (!worker) {
210
+ throw new Error(`Worker ${i} 对象为空`);
211
+ }
212
+ // 添加 Worker 错误监听
213
+ worker.addEventListener('error', (error) => {
214
+ console.error(`Worker ${i} 错误:`, error);
215
+ console.error('错误详情:', error.message, error.filename, error.lineno);
216
+ });
217
+ this.workerPool.push(worker);
218
+ }
219
+ }
220
+ catch (error) {
221
+ console.warn('无法创建 Web Worker,将回退到主线程执行:', error);
222
+ // 如果 Worker 创建失败,标记为不使用 Worker,所有任务将在主线程执行
223
+ this.useWorker = false;
224
+ }
225
+ }
226
+ /**
227
+ * 创建内联 Worker(通过 Blob URL)
228
+ * 这是一个备选方案,当无法加载外部 Worker 文件时使用
229
+ */
230
+ createInlineWorker() {
231
+ // Worker 代码(从 worker.ts 复制,但需要是纯 JavaScript)
232
+ const workerCode = `
233
+ self.onmessage = function(e) {
234
+ const message = e.data;
235
+
236
+ if (message.type === 'TERMINATE') {
237
+ self.close();
238
+ return;
239
+ }
240
+
241
+ if (message.type === 'TASK' && message.task) {
242
+ try {
243
+ const task = message.task;
244
+ const startTime = Date.now();
245
+
246
+ if (task.computeFn) {
247
+ try {
248
+ const computeFunction = new Function('data', task.computeFn);
249
+ const result = computeFunction(task.data);
250
+
251
+ const endTime = Date.now();
252
+
253
+ self.postMessage({
254
+ type: 'RESULT',
255
+ taskId: task.id,
256
+ result: result,
257
+ duration: endTime - startTime
258
+ });
259
+ } catch (fnError) {
260
+ console.error('内联 Worker 函数执行错误:', fnError);
261
+ throw fnError;
262
+ }
263
+ } else {
264
+ self.postMessage({
265
+ type: 'RESULT',
266
+ taskId: task.id,
267
+ result: null,
268
+ duration: Date.now() - startTime
269
+ });
270
+ }
271
+ } catch (error) {
272
+ console.error('内联 Worker 捕获到错误:', error);
273
+ self.postMessage({
274
+ type: 'ERROR',
275
+ taskId: message.task?.id || '',
276
+ error: error instanceof Error ? error.message : String(error)
277
+ });
278
+ }
279
+ }
280
+ };
281
+ `;
282
+ const blob = new Blob([workerCode], { type: 'application/javascript' });
283
+ const workerUrl = URL.createObjectURL(blob);
284
+ return new Worker(workerUrl);
285
+ }
286
+ /**
287
+ * 销毁 Worker 池
288
+ */
289
+ destroy() {
290
+ // 终止所有 Worker
291
+ this.workerPool.forEach(worker => {
292
+ worker.postMessage({ type: 'TERMINATE' });
293
+ worker.terminate();
294
+ });
295
+ this.workerPool = [];
296
+ this.pendingTasks.clear();
297
+ this.dataGramQueue = [];
298
+ }
299
+ }
File without changes
@@ -0,0 +1,99 @@
1
+ // // Web Worker 文件 - 在后台线程中执行耗时计算任务
2
+ //
3
+ // interface WorkerTask {
4
+ // id: string;
5
+ // computeFn: string; // 序列化的计算函数代码
6
+ // data?: any; // 传递给计算函数的数据
7
+ // }
8
+ //
9
+ // interface WorkerMessage {
10
+ // type: 'TASK' | 'TERMINATE';
11
+ // task?: WorkerTask;
12
+ // }
13
+ //
14
+ // interface WorkerResponse {
15
+ // type: 'RESULT' | 'ERROR';
16
+ // taskId: string;
17
+ // result?: any;
18
+ // error?: string;
19
+ // duration?: number;
20
+ // errorStack?: string;
21
+ // }
22
+ //
23
+ // // Worker 初始化日志
24
+ // console.log('外部 Worker 初始化完成');
25
+ //
26
+ // // Worker 接收消息
27
+ // self.onmessage = function(e: MessageEvent<WorkerMessage>) {
28
+ // console.log(3333, '外部 Worker 收到消息:', e.data);
29
+ // const message = e.data;
30
+ //
31
+ // // 处理测试消息
32
+ // if ((message as any).type === 'TEST') {
33
+ // console.log('外部 Worker 收到测试消息');
34
+ // self.postMessage({ type: 'TEST_RESPONSE', received: true });
35
+ // return;
36
+ // }
37
+ //
38
+ // if (message.type === 'TERMINATE') {
39
+ // self.close();
40
+ // return;
41
+ // }
42
+ //
43
+ // if (message.type === 'TASK' && message.task) {
44
+ // try {
45
+ // const task = message.task;
46
+ // const startTime = Date.now();
47
+ //
48
+ // // 执行计算任务
49
+ // // 由于函数无法直接序列化,我们使用 Function 构造函数来执行
50
+ // // 注意:这里只执行纯计算,不访问 DOM 或主线程 API
51
+ // if (task.computeFn) {
52
+ // // 使用 Function 构造函数创建函数
53
+ // // 注意:这需要函数体是自包含的,不能访问外部变量
54
+ // console.log('Worker 准备执行函数,函数体:', task.computeFn);
55
+ // console.log('Worker 准备执行函数,数据:', task.data);
56
+ // try {
57
+ // const computeFunction = new Function('data', task.computeFn);
58
+ // const result = computeFunction(task.data);
59
+ // console.log('Worker 函数执行成功,结果:', result);
60
+ //
61
+ // const endTime = Date.now();
62
+ //
63
+ // // 发送结果回主线程
64
+ // const response: WorkerResponse = {
65
+ // type: 'RESULT',
66
+ // taskId: task.id,
67
+ // result: result,
68
+ // duration: endTime - startTime
69
+ // };
70
+ // self.postMessage(response);
71
+ // } catch (fnError) {
72
+ // console.error('Worker 函数执行错误:', fnError);
73
+ // throw fnError;
74
+ // }
75
+ // } else {
76
+ // // 如果没有计算函数,只是通知任务完成
77
+ // const response: WorkerResponse = {
78
+ // type: 'RESULT',
79
+ // taskId: task.id,
80
+ // result: null,
81
+ // duration: Date.now() - startTime
82
+ // };
83
+ // self.postMessage(response);
84
+ // }
85
+ // } catch (error) {
86
+ // // 发送错误回主线程
87
+ // console.error('Worker 捕获到错误:', error);
88
+ // const response: WorkerResponse = {
89
+ // type: 'ERROR',
90
+ // taskId: message.task?.id || '',
91
+ // error: error instanceof Error ? error.message : String(error),
92
+ // // 添加更多错误信息
93
+ // errorStack: error instanceof Error ? error.stack : undefined
94
+ // };
95
+ // self.postMessage(response);
96
+ // }
97
+ // }
98
+ // };
99
+ //