@ray-js/robot-data-stream 0.0.13-beta-7 → 0.0.13-beta-9

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.
Files changed (55) hide show
  1. package/lib/api/index.d.ts +2 -12
  2. package/lib/api/index.js +1 -172
  3. package/lib/api/p2pApi.d.ts +8 -27
  4. package/lib/api/p2pApi.js +271 -169
  5. package/lib/api/sweeperP2p.d.ts +55 -21
  6. package/lib/api/sweeperP2p.js +376 -246
  7. package/lib/constant.d.ts +0 -52
  8. package/lib/constant.js +0 -54
  9. package/lib/index.d.ts +12 -1
  10. package/lib/index.js +187 -2
  11. package/lib/mqtt/createCommonOptions.d.ts +15 -56
  12. package/lib/mqtt/createCommonOptions.js +8 -44
  13. package/lib/mqtt/mqttProvider.d.ts +15 -23
  14. package/lib/mqtt/mqttProvider.js +26 -63
  15. package/lib/mqtt/myError.d.ts +4 -0
  16. package/lib/mqtt/myError.js +6 -0
  17. package/lib/mqtt/promise.js +3 -8
  18. package/lib/mqtt/type/index.d.ts +0 -9
  19. package/lib/mqtt/type/index.js +0 -8
  20. package/lib/mqtt/type/requestType.d.ts +0 -3
  21. package/lib/mqtt/type/requestType.js +0 -4
  22. package/lib/mqtt/useDevInfo.d.ts +7 -2
  23. package/lib/mqtt/useDevInfo.js +9 -25
  24. package/lib/mqtt/useHistoryMap.d.ts +21 -13
  25. package/lib/mqtt/useHistoryMap.js +32 -82
  26. package/lib/mqtt/usePartDivision.d.ts +7 -5
  27. package/lib/mqtt/usePartDivision.js +16 -41
  28. package/lib/mqtt/usePartMerge.d.ts +7 -5
  29. package/lib/mqtt/usePartMerge.js +18 -36
  30. package/lib/mqtt/usePassword.js +28 -59
  31. package/lib/mqtt/useQuiteHours.d.ts +24 -9
  32. package/lib/mqtt/useQuiteHours.js +52 -95
  33. package/lib/mqtt/useResetMap.d.ts +7 -10
  34. package/lib/mqtt/useResetMap.js +11 -40
  35. package/lib/mqtt/useRoomProperty.js +16 -23
  36. package/lib/mqtt/useSchedule.d.ts +4 -17
  37. package/lib/mqtt/useSchedule.js +49 -101
  38. package/lib/mqtt/useSelectRoomClean.d.ts +16 -20
  39. package/lib/mqtt/useSelectRoomClean.js +49 -145
  40. package/lib/mqtt/useSpotClean.d.ts +3 -3
  41. package/lib/mqtt/useSpotClean.js +51 -71
  42. package/lib/mqtt/useVirtualArea.d.ts +9 -6
  43. package/lib/mqtt/useVirtualArea.js +42 -112
  44. package/lib/mqtt/useVirtualWall.d.ts +10 -13
  45. package/lib/mqtt/useVirtualWall.js +34 -97
  46. package/lib/mqtt/useVoice.d.ts +6 -3
  47. package/lib/mqtt/useVoice.js +33 -73
  48. package/lib/mqtt/useWifiMap.js +18 -34
  49. package/lib/mqtt/useZoneClean.d.ts +13 -13
  50. package/lib/mqtt/useZoneClean.js +76 -149
  51. package/lib/utils/index.d.ts +7 -18
  52. package/lib/utils/index.js +13 -15
  53. package/package.json +1 -1
  54. package/lib/ttt/index.d.ts +0 -153
  55. package/lib/ttt/index.js +0 -458
@@ -1,32 +1,56 @@
1
1
  import "core-js/modules/esnext.iterator.constructor.js";
2
- import "core-js/modules/esnext.iterator.filter.js";
3
2
  import "core-js/modules/esnext.iterator.for-each.js";
4
3
  import "core-js/modules/esnext.iterator.map.js";
4
+ /* eslint-disable no-shadow */
5
5
  import Base64 from 'base64-js';
6
- import { join, map, once, padStart } from 'lodash-es';
7
- import { FILE_NAME_MAP, FileNameEnum } from '../constant';
6
+ import { join, map, padStart, once } from 'lodash-es';
8
7
  import { trace } from '../trace';
9
- import { checkIfDirIsExist, createFilePath } from '../ttt';
8
+ import { logger, logP2PDataIfEnabled } from '../utils';
10
9
  import P2pApi from './p2pApi';
11
- /**
12
- * 基于P2p工具类的扫地机扩展实现
13
- */
14
-
15
- // 需要初始化的文件名列表(不包括 wifi_map)
16
- const FILE_NAMES_TO_INIT = [FileNameEnum.map, FileNameEnum.mapStructured, FileNameEnum.cleanPath, FileNameEnum.ai, FileNameEnum.aiHD, FileNameEnum.mapStream, FileNameEnum.mapStructuredStream, FileNameEnum.cleanPathStream, FileNameEnum.aiStream, FileNameEnum.aiHDStream];
17
10
 
18
11
  /**
19
- * 创建初始化的 Map,所有键值都设置为初始值
12
+ * 基于P2p工具类的扫地机扩展实现
20
13
  */
21
- const createInitializedMap = initialValue => {
22
- return new Map(FILE_NAMES_TO_INIT.map(key => [key, initialValue]));
23
- };
24
14
 
25
- /**
26
- * 创建初始化的 Map,值为新的 Map 实例
27
- */
28
- const createMapOfMaps = () => {
29
- return new Map(FILE_NAMES_TO_INIT.map(key => [key, new Map()]));
15
+ const FILE_NAME_MAP = {
16
+ // raw类型地图点数据
17
+ 'map.bin': {
18
+ type: 0
19
+ },
20
+ // 结构化点数据
21
+ 'map_structured.bin': {
22
+ type: 6
23
+ },
24
+ 'cleanPath.bin': {
25
+ type: 1
26
+ },
27
+ 'map.bin.stream': {
28
+ type: 0
29
+ },
30
+ 'map_structured.bin.stream': {
31
+ type: 6
32
+ },
33
+ 'cleanPath.bin.stream': {
34
+ type: 1
35
+ },
36
+ 'ai.bin': {
37
+ type: 4
38
+ },
39
+ 'ai.bin.stream': {
40
+ type: 4
41
+ },
42
+ 'aiHD_XXXX_YYYY.bin': {
43
+ type: 5
44
+ },
45
+ 'aiHD_XXXX_YYYY.bin.stream': {
46
+ type: 5
47
+ },
48
+ 'wifi_map.bin': {
49
+ type: 7
50
+ },
51
+ 'wifi_map.bin.stream': {
52
+ type: 7
53
+ }
30
54
  };
31
55
 
32
56
  // 走p2p流传输(新) or 读取bin文件(旧)
@@ -44,11 +68,11 @@ export class SweeperP2p extends P2pApi {
44
68
  this.cacheData = {};
45
69
  this.exitFiles = [];
46
70
  this.firstPackageTime = Date.now();
47
- // 使用辅助函数初始化 Map,减少重复代码
48
- this.packetTotalMap = createInitializedMap(-1);
49
- this.packetSerialNumberCacheMap = createInitializedMap(-1);
50
- this.fileLengthCacheMap = createInitializedMap(-1);
51
- this.packetDataCacheMap = createMapOfMaps();
71
+ this.enableCustomLog = false;
72
+ this.packetTotalMap = new Map([['map.bin', -1], ['map_structured.bin', -1], ['cleanPath.bin', -1], ['ai.bin', -1], ['aiHD_XXXX_YYYY.bin', -1], ['map.bin.stream', -1], ['map_structured.bin.stream', -1], ['cleanPath.bin.stream', -1], ['ai.bin.stream', -1], ['aiHD_XXXX_YYYY.bin.stream', -1]]);
73
+ this.packetSerialNumberCacheMap = new Map([['map.bin', -1], ['map_structured.bin', -1], ['cleanPath.bin', -1], ['ai.bin', -1], ['aiHD_XXXX_YYYY.bin', -1], ['map.bin.stream', -1], ['map_structured.bin.stream', -1], ['cleanPath.bin.stream', -1], ['ai.bin.stream', -1], ['aiHD_XXXX_YYYY.bin.stream', -1]]);
74
+ this.fileLengthCacheMap = new Map([['map.bin', -1], ['map_structured.bin', -1], ['cleanPath.bin', -1], ['ai.bin', -1], ['aiHD_XXXX_YYYY.bin', -1], ['map.bin.stream', -1], ['map_structured.bin.stream', -1], ['cleanPath.bin.stream', -1], ['ai.bin.stream', -1], ['aiHD_XXXX_YYYY.bin.stream', -1]]);
75
+ this.packetDataCacheMap = new Map([['map.bin', new Map()], ['map_structured.bin', new Map()], ['cleanPath.bin', new Map()], ['ai.bin', new Map()], ['aiHD_XXXX_YYYY.bin', new Map()], ['map.bin.stream', new Map()], ['map_structured.bin.stream', new Map()], ['cleanPath.bin.stream', new Map()], ['ai.bin.stream', new Map()], ['aiHD_XXXX_YYYY.bin.stream', new Map()]]);
52
76
  }
53
77
  setStreamFilePath = () => {
54
78
  // this.streamFilePath = this.cacheDir + `/${this.albumName}/${devId}/stream`;
@@ -65,7 +89,7 @@ export class SweeperP2p extends P2pApi {
65
89
  if (/usr/.test(this.cacheDir)) {
66
90
  this.dataFilePath = this.cacheDir;
67
91
  } else {
68
- this.dataFilePath = this.cacheDir + 'usr';
92
+ this.streamFilePath = this.cacheDir + 'usr';
69
93
  }
70
94
  // 检查存储文件目录是否存在
71
95
  // this.initFilePath(this.dataFilePath);
@@ -89,17 +113,70 @@ export class SweeperP2p extends P2pApi {
89
113
  return this.dataFilePath + '/' + fileName;
90
114
  };
91
115
 
116
+ /**
117
+ * 创建文件路径文件夹
118
+ * @param filePath
119
+ * @returns
120
+ */
121
+ createFilePath = filePath => {
122
+ try {
123
+ ty.getFileSystemManager().mkdirSync({
124
+ dirPath: filePath,
125
+ recursive: true
126
+ });
127
+ logger('info', {
128
+ msg: 'mkdirSync success: filePath ==>',
129
+ filePath
130
+ }, this.onLogger);
131
+ return true;
132
+ } catch (e) {
133
+ logger('error', {
134
+ msg: 'mkdirSync error ==>',
135
+ e
136
+ }, this.onLogger);
137
+ return false;
138
+ }
139
+ };
140
+
141
+ /**
142
+ * 检查当前文件目录是否存在
143
+ * @param filePath
144
+ * @returns
145
+ */
146
+ checkIfDirIsExist = filePath => {
147
+ return new Promise(resolve => {
148
+ ty.getFileSystemManager().access({
149
+ path: filePath,
150
+ success(params) {
151
+ logger('info', {
152
+ msg: 'file access success ==>',
153
+ params
154
+ }, this.onLogger);
155
+ resolve(true);
156
+ },
157
+ fail(params) {
158
+ logger('warn', {
159
+ msg: 'file access fail ==>',
160
+ params
161
+ }, this.onLogger);
162
+ resolve(false);
163
+ }
164
+ });
165
+ });
166
+ };
167
+
92
168
  /**
93
169
  * 初始化文件目录
94
170
  * @param filePath
95
171
  * @returns
96
172
  */
97
173
  initFilePath = async filePath => {
98
- const isDir = await checkIfDirIsExist(filePath);
174
+ const isDir = await this.checkIfDirIsExist(filePath);
99
175
  if (!isDir) {
100
- return await createFilePath(filePath, this.onLogger);
176
+ const result = this.createFilePath(filePath);
177
+ return result;
101
178
  }
102
- return true;
179
+ return isDir;
103
180
  };
104
181
 
105
182
  /**
@@ -107,183 +184,77 @@ export class SweeperP2p extends P2pApi {
107
184
  * @param filename
108
185
  */
109
186
  getFileType = filename => {
110
- // 首先尝试精确匹配 FILE_NAME_MAP 中的键
111
- if (filename in FILE_NAME_MAP) {
112
- return FILE_NAME_MAP[filename].type;
187
+ if (filename.indexOf('map_structured') !== -1) {
188
+ return 6;
113
189
  }
114
-
115
- // 处理 aiHD_XXXX_YYYY.bin 模式(XXXX_YYYY 会被替换为实际值)
116
-
117
- if (/^aiHD.*\.bin(\.stream)?$/.test(filename)) {
118
- return FILE_NAME_MAP[FileNameEnum.aiHD].type;
190
+ if (filename.indexOf('map.') !== -1) {
191
+ return 0;
119
192
  }
120
-
121
- // 按优先级顺序匹配文件名(更具体的模式优先)
122
- // 注意:map_structured 必须在 map 之前匹配
123
- const matchOrder = [{
124
- pattern: /map_structured/,
125
- enumKey: FileNameEnum.mapStructured
126
- }, {
127
- pattern: /^map\./,
128
- enumKey: FileNameEnum.map
129
- }, {
130
- pattern: /cleanPath/,
131
- enumKey: FileNameEnum.cleanPath
132
- }, {
133
- pattern: /^ai\./,
134
- enumKey: FileNameEnum.ai
135
- }, {
136
- pattern: /wifi_map/,
137
- enumKey: FileNameEnum.wifiMap
138
- }];
139
- for (const {
140
- pattern,
141
- enumKey
142
- } of matchOrder) {
143
- if (pattern.test(filename)) {
144
- return FILE_NAME_MAP[enumKey].type;
145
- }
193
+ if (filename.indexOf('cleanPath') !== -1) {
194
+ return 1;
195
+ }
196
+ if (filename.indexOf('ai.') !== -1) {
197
+ return 4;
198
+ }
199
+ if (filename.indexOf('aiHD') !== -1) {
200
+ return 5;
201
+ }
202
+ if (filename.indexOf('wifi_map') !== -1) {
203
+ return 7;
146
204
  }
147
-
148
- // 默认返回 2
149
205
  return 2;
150
206
  };
151
207
 
152
- /**
153
- * 根据文件类型处理数据并调用相应的回调函数
154
- */
155
- handleDataByType = (() => {
156
- var _this = this;
157
- return function (type, hexValue) {
158
- let shouldCache = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
159
- if (_this.cacheData[type] === hexValue) {
160
- return;
161
- }
162
- switch (type) {
163
- case 0:
164
- case 6:
165
- _this.onReceiveMapData(hexValue);
166
- if (shouldCache) {
167
- _this.cacheData[type] = hexValue;
168
- }
169
- break;
170
- case 1:
171
- _this.log.info({
172
- msg: 'push new path data'
173
- });
174
- _this.onReceivePathData(hexValue);
175
- if (shouldCache) {
176
- _this.cacheData[type] = hexValue;
177
- }
178
- break;
179
- case 4:
180
- _this.onReceiveAIPicData(hexValue);
181
- break;
182
- case 5:
183
- _this.onReceiveAIPicHDData(hexValue);
184
- break;
185
- case 7:
186
- _this.onReceiveWifiMapData(hexValue);
187
- break;
188
- default:
189
- break;
190
- }
191
- };
192
- })();
193
-
194
208
  /**
195
209
  * 设备连接状态发生改变
196
210
  * @param data
197
211
  */
198
212
  sessionStatusCallback = data => {
199
- this.log.info({
213
+ logger('info', {
200
214
  msg: 'sessionStatusCallback ==>',
201
215
  data
202
- });
216
+ }, this.onLogger);
203
217
  if (data) {
204
218
  const {
205
219
  status
206
220
  } = data;
207
221
  if (status < 0) {
208
- this.log.info({
222
+ logger('info', {
209
223
  msg: 'receive disconnect notice ==>',
210
224
  status
211
- });
225
+ }, this.onLogger);
226
+ logP2PDataIfEnabled(this.enableCustomLog, this.devId, 'session_status_disconnect', `Session disconnected, status: ${status}`);
212
227
  this.isConnected = false;
213
228
  if (!this.isConnecting) {
229
+ logP2PDataIfEnabled(this.enableCustomLog, this.devId, 'session_reconnect_start', 'Starting reconnect after session disconnect');
214
230
  this.reconnectP2p(() => {
231
+ logP2PDataIfEnabled(this.enableCustomLog, this.devId, 'session_reconnect_success', 'Reconnected successfully, restarting data observer');
215
232
  // 重连之后重新开启文件下载, 这里的成功不需要注册断开事件
216
233
  this.startObserverSweeperDataByP2P(this.downloadType, this.devId, this.onReceiveMapData, this.onReceivePathData, this.onReceiveAIPicData, this.onReceiveAIPicHDData, this.onReceiveWifiMapData);
217
234
  }, '');
218
235
  } else {
219
- this.log.warn({
236
+ logger('warn', {
220
237
  msg: 'receive disconnect notice, but connectDevice is connecting'
221
- });
238
+ }, this.onLogger);
239
+ logP2PDataIfEnabled(this.enableCustomLog, this.devId, 'session_disconnect_ignored', 'Disconnect notice ignored, device is already connecting');
222
240
  }
223
241
  }
224
242
  }
225
243
  };
226
244
 
227
- /**
228
- * 创建下载失败时的重连回调函数
229
- */
230
- createReconnectCallback = () => {
231
- return () => {
232
- this.log.error({
233
- msg: `${this.downloadType} p2p downloadStream failed and try reConnect Device===>`
234
- });
235
- this.removeP2pDownloadEvent();
236
- this.disconnectDevice().then(() => {
237
- this.isConnected = false;
238
- this.isConnecting = false;
239
- this.connectDevice(() => {
240
- // 重连之后重新开启文件下载, 这里的成功不需要注册断开事件
241
- this.startObserverSweeperDataByP2P(this.downloadType, this.devId, this.onReceiveMapData, this.onReceivePathData, this.onReceiveAIPicData, this.onReceiveAIPicHDData, this.onReceiveWifiMapData);
242
- });
243
- });
244
- };
245
- };
246
-
247
- /**
248
- * 执行文件下载逻辑
249
- */
250
- async executeDownload(exitFiles, filePath) {
251
- if (exitFiles.length === 0) {
252
- return;
253
- }
254
- if (shouldDownloadStream) {
255
- // 开启p2p流传输
256
- await this.downloadStream({
257
- files: exitFiles
258
- }, this.albumName, () => {
259
- this.log.info({
260
- msg: `${this.downloadType} p2p downloadStream success===>`
261
- });
262
- }, this.createReconnectCallback());
263
- } else if (await this.initFilePath(filePath)) {
264
- // 每次要下载前都需要先检查文件目录是否存在 防止中间过程被删除掉文件目录
265
- await this.downloadFile({
266
- files: exitFiles
267
- }, this.albumName, filePath);
268
- }
269
- this.firstPackageTime = Date.now();
270
- }
271
-
272
245
  /**
273
246
  * 开始进行文件下载
274
247
  * @param downloadType
275
248
  * 0: 下载断开 1: 持续下载
276
249
  */
277
250
  startObserverSweeperDataByP2P = async (downloadType, devId, onReceiveMapData, onReceivePathData, onReceiveAIPicData, onReceiveAIPicHDData, onReceiveWifiMapData, onDefineStructuredMode) => {
278
- var _this$file;
279
- if (![0, 1].includes(downloadType)) {
280
- this.log.warn({
251
+ var _this$file$items;
252
+ if (![0, 1].some(item => item === downloadType)) {
253
+ logger('warn', {
281
254
  msg: 'download type must be 0 or 1'
282
- });
255
+ }, this.onLogger);
283
256
  return;
284
257
  }
285
-
286
- // 初始化回调函数
287
258
  this.onReceiveMapData = onReceiveMapData;
288
259
  this.onReceivePathData = onReceivePathData;
289
260
  this.onReceiveWifiMapData = onReceiveWifiMapData;
@@ -294,9 +265,10 @@ export class SweeperP2p extends P2pApi {
294
265
  this.onReceiveAIPicHDData = onReceiveAIPicHDData || (() => {
295
266
  // do nothing
296
267
  });
297
- this.log.info({
268
+ logger('info', {
298
269
  msg: 'startObserverSweeperDataByP2P ==>'
299
- });
270
+ }, this.onLogger);
271
+ logP2PDataIfEnabled(this.enableCustomLog, devId, 'start_observer_sweeper_data', `Starting observer, downloadType: ${downloadType}`);
300
272
  trace.pointFn({
301
273
  devId,
302
274
  eventName: 'startObserverSweeperDataByP2P'
@@ -304,27 +276,105 @@ export class SweeperP2p extends P2pApi {
304
276
  this.downloadType = downloadType;
305
277
  this.setDataFilePath(devId);
306
278
  this.setStreamFilePath(devId);
307
-
308
279
  // 先移除监听,再重新注册
309
280
  this.removeP2pDownloadEvent();
310
281
  this.registerP2pDownloadEvent();
311
-
312
- // 查询文件列表
313
282
  if (!this.file) {
283
+ var _this$file;
314
284
  // @ts-ignore
315
285
  this.file = await this.queryAlbumFileIndexs(this.albumName);
286
+ logP2PDataIfEnabled(this.enableCustomLog, devId, 'query_album_files', `Query album files completed, file count: ${((_this$file = this.file) === null || _this$file === void 0 || (_this$file = _this$file.items) === null || _this$file === void 0 ? void 0 : _this$file.length) || 0}`);
287
+ }
288
+ if (this.file && ((_this$file$items = this.file.items) === null || _this$file$items === void 0 ? void 0 : _this$file$items.length) > 0) {
289
+ if (this.downloadType === 0) {
290
+ const exitFiles = this.queryNeedFiles(this.file.items);
291
+ // 赋值
292
+ this.exitFiles = exitFiles;
293
+ if (exitFiles.length > 0) {
294
+ logP2PDataIfEnabled(this.enableCustomLog, devId, 'download_files_start', `Starting download, files: ${exitFiles.join(',')}, downloadType: ${downloadType}`);
295
+ if (shouldDownloadStream) {
296
+ // 开启p2p流传输
297
+ logP2PDataIfEnabled(this.enableCustomLog, devId, 'download_stream_start', `Starting stream download, files count: ${exitFiles.length}`);
298
+ await this.downloadStream({
299
+ files: exitFiles
300
+ }, this.albumName, () => {
301
+ logger('info', {
302
+ msg: `${downloadType} p2p downloadStream success===>`
303
+ }, this.onLogger);
304
+ logP2PDataIfEnabled(this.enableCustomLog, devId, 'download_stream_success', `Stream download success, downloadType: ${downloadType}`);
305
+ }, () => {
306
+ logger('error', {
307
+ msg: `${downloadType} p2p downloadStream failed and try reConnect Device===>`
308
+ }, this.onLogger);
309
+ logP2PDataIfEnabled(this.enableCustomLog, devId, 'download_stream_fail', `Stream download failed, attempting reconnect, downloadType: ${downloadType}`);
310
+ this.removeP2pDownloadEvent();
311
+ this.disconnectDevice().then(() => {
312
+ this.isConnected = false;
313
+ this.isConnecting = false;
314
+ logP2PDataIfEnabled(this.enableCustomLog, devId, 'download_stream_reconnect', 'Reconnecting device after stream download failure');
315
+ this.connectDevice(() => {
316
+ // 重连之后重新开启文件下载, 这里的成功不需要注册断开事件
317
+ this.startObserverSweeperDataByP2P(this.downloadType, this.devId, this.onReceiveMapData, this.onReceivePathData, this.onReceiveAIPicData, this.onReceiveAIPicHDData, this.onReceiveWifiMapData);
318
+ });
319
+ });
320
+ });
321
+ } else if (await this.initFilePath(this.dataFilePath)) {
322
+ logP2PDataIfEnabled(this.enableCustomLog, devId, 'download_file_start', `Starting file download, files count: ${exitFiles.length}`);
323
+ await this.downloadFile({
324
+ files: exitFiles
325
+ }, this.albumName, this.dataFilePath);
326
+ logP2PDataIfEnabled(this.enableCustomLog, devId, 'download_file_complete', `File download completed, files count: ${exitFiles.length}`);
327
+ }
328
+ this.firstPackageTime = Date.now();
329
+ } else {
330
+ logP2PDataIfEnabled(this.enableCustomLog, devId, 'no_files_to_download', 'No files found to download');
331
+ }
332
+ } else if (this.downloadType === 1) {
333
+ const exitFiles = this.queryNeedFiles(this.file.items);
334
+ // 赋值
335
+ this.exitFiles = exitFiles;
336
+ if (exitFiles.length > 0) {
337
+ logP2PDataIfEnabled(this.enableCustomLog, devId, 'download_files_start', `Starting download, files: ${exitFiles.join(',')}, downloadType: ${downloadType}`);
338
+ if (shouldDownloadStream) {
339
+ // 开启p2p流传输
340
+ logP2PDataIfEnabled(this.enableCustomLog, devId, 'download_stream_start', `Starting stream download, files count: ${exitFiles.length}`);
341
+ await this.downloadStream({
342
+ files: exitFiles
343
+ }, this.albumName, () => {
344
+ logger('info', {
345
+ msg: `${downloadType} p2p downloadStream success===>`
346
+ }, this.onLogger);
347
+ logP2PDataIfEnabled(this.enableCustomLog, devId, 'download_stream_success', `Stream download success, downloadType: ${downloadType}`);
348
+ }, () => {
349
+ logger('error', {
350
+ msg: `${downloadType} p2p downloadStream failed and try reConnect Device===>`
351
+ }, this.onLogger);
352
+ logP2PDataIfEnabled(this.enableCustomLog, devId, 'download_stream_fail', `Stream download failed, attempting reconnect, downloadType: ${downloadType}`);
353
+ this.removeP2pDownloadEvent();
354
+ this.disconnectDevice().then(() => {
355
+ this.isConnected = false;
356
+ this.isConnecting = false;
357
+ logP2PDataIfEnabled(this.enableCustomLog, devId, 'download_stream_reconnect', 'Reconnecting device after stream download failure');
358
+ this.connectDevice(() => {
359
+ // 重连之后重新开启文件下载, 这里的成功不需要注册断开事件
360
+ this.startObserverSweeperDataByP2P(this.downloadType, this.devId, this.onReceiveMapData, this.onReceivePathData, this.onReceiveAIPicData, this.onReceiveAIPicHDData, this.onReceiveWifiMapData);
361
+ });
362
+ });
363
+ });
364
+ } else if (await this.initFilePath(this.streamFilePath)) {
365
+ // 每次要下载前都需要先检查文件目录是否存在 防止中间过程被删除掉文件目录
366
+ logP2PDataIfEnabled(this.enableCustomLog, devId, 'download_file_start', `Starting file download, files count: ${exitFiles.length}`);
367
+ await this.downloadFile({
368
+ files: exitFiles
369
+ }, this.albumName, this.streamFilePath);
370
+ logP2PDataIfEnabled(this.enableCustomLog, devId, 'download_file_complete', `File download completed, files count: ${exitFiles.length}`);
371
+ }
372
+ this.firstPackageTime = Date.now();
373
+ } else {
374
+ logP2PDataIfEnabled(this.enableCustomLog, devId, 'no_files_to_download', 'No files found to download');
375
+ }
376
+ }
316
377
  }
317
- if (!((_this$file = this.file) !== null && _this$file !== void 0 && (_this$file = _this$file.items) !== null && _this$file !== void 0 && _this$file.length)) {
318
- return;
319
- }
320
-
321
- // 根据 downloadType 选择文件路径
322
- const filePath = downloadType === 0 ? this.dataFilePath : this.streamFilePath;
323
- const exitFiles = this.queryNeedFiles(this.file.items);
324
- this.exitFiles = exitFiles;
325
-
326
- // 执行下载
327
- await this.executeDownload(exitFiles, filePath);
328
378
  };
329
379
 
330
380
  /**
@@ -335,6 +385,7 @@ export class SweeperP2p extends P2pApi {
335
385
  * @returns
336
386
  */
337
387
  appendDownloadStreamDuringTask = (files, successCb, failCb) => {
388
+ logP2PDataIfEnabled(this.enableCustomLog, this.devId, 'append_download_stream', `Appending files to download stream, files: ${files.join(',')}`);
338
389
  return this.appendDownloadStream({
339
390
  files: [...this.exitFiles, ...files]
340
391
  }, this.albumName, successCb, failCb);
@@ -344,9 +395,10 @@ export class SweeperP2p extends P2pApi {
344
395
  * 注册下载有关的监听
345
396
  */
346
397
  registerP2pDownloadEvent = () => {
347
- this.log.info({
398
+ logger('info', {
348
399
  msg: 'registerP2pDownloadEvent ==>'
349
- });
400
+ }, this.onLogger);
401
+ logP2PDataIfEnabled(this.enableCustomLog, this.devId, 'register_download_event', `Registering download events, shouldDownloadStream: ${shouldDownloadStream}`);
350
402
  if (shouldDownloadStream) {
351
403
  // p2p数据流监听
352
404
  this.offP2pStreamPacketReceive = this.onP2pStreamPacketReceive(this.p2pStreamPacketReceiveCallback);
@@ -367,25 +419,30 @@ export class SweeperP2p extends P2pApi {
367
419
  * 移除下载有关的监听
368
420
  */
369
421
  removeP2pDownloadEvent = () => {
370
- var _this$offFileDownload, _this$offP2pStreamPac;
371
- this.log.info({
422
+ logger('info', {
372
423
  msg: 'removeP2pDownloadEvent ==>'
373
- });
424
+ }, this.onLogger);
425
+ logP2PDataIfEnabled(this.enableCustomLog, this.devId, 'remove_download_event', 'Removing download events');
374
426
  if (shouldDownloadStream) {
375
- // 重置所有 Map 的值为初始状态
376
- FILE_NAMES_TO_INIT.forEach(key => {
427
+ [...this.packetSerialNumberCacheMap.keys()].forEach(key => {
377
428
  this.packetSerialNumberCacheMap.set(key, -1);
429
+ });
430
+ [...this.fileLengthCacheMap.keys()].forEach(key => {
378
431
  this.fileLengthCacheMap.set(key, -1);
432
+ });
433
+ [...this.packetTotalMap.keys()].forEach(key => {
379
434
  this.packetTotalMap.set(key, -1);
435
+ });
436
+ [...this.packetDataCacheMap.keys()].forEach(key => {
380
437
  this.packetDataCacheMap.set(key, new Map());
381
438
  });
382
439
  }
383
440
  this.cacheData = {};
384
- (_this$offFileDownload = this.offFileDownloadComplete) === null || _this$offFileDownload === void 0 || _this$offFileDownload.call(this);
385
- (_this$offP2pStreamPac = this.offP2pStreamPacketReceive) === null || _this$offP2pStreamPac === void 0 || _this$offP2pStreamPac.call(this);
441
+ this.offFileDownloadComplete && this.offFileDownloadComplete();
442
+ this.offP2pStreamPacketReceive && this.offP2pStreamPacketReceive();
386
443
 
387
- // this.offDownLoadProgressUpdate?.();
388
- // this.offTotalDownLoadProgressUpdate?.();
444
+ // this.offDownLoadProgressUpdate && this.offDownLoadProgressUpdate();
445
+ // this.offTotalDownLoadProgressUpdate && this.offTotalDownLoadProgressUpdate();
389
446
  };
390
447
 
391
448
  /**
@@ -399,6 +456,7 @@ export class SweeperP2p extends P2pApi {
399
456
  index
400
457
  } = data;
401
458
  if (fileName) {
459
+ logP2PDataIfEnabled(this.enableCustomLog, this.devId, 'file_download_complete', `File download completed, fileName: ${fileName}, index: ${index}`);
402
460
  this.fileIndex = index;
403
461
  const path = this.downloadType === 0 ? this.getDataFilePath(fileName) : this.getStreamFilePath(fileName);
404
462
  this.readFileFromPath(fileName, path);
@@ -431,18 +489,24 @@ export class SweeperP2p extends P2pApi {
431
489
  this.initStructuredMode(((_FILE_NAME_MAP$fileNa = FILE_NAME_MAP[fileName]) === null || _FILE_NAME_MAP$fileNa === void 0 ? void 0 : _FILE_NAME_MAP$fileNa.type) === 6);
432
490
  }
433
491
 
492
+ // 记录第一个包和最后一个包的接收
493
+ if (packetType === 1 || packetType === 3) {
494
+ logP2PDataIfEnabled(this.enableCustomLog, this.devId, 'packet_first_received', `First packet received, fileName: ${fileName}, fileSerialNumber: ${fileSerialNumber}, packetIndex: ${packetIndex}`);
495
+ }
496
+
434
497
  // 因为XXXX_YYYYY会被替换为坐标值,所以这里需要替换一下
435
498
 
436
499
  if (/^aiHD.*\.bin$/.test(fileName)) {
437
- fileName = FileNameEnum.aiHD;
500
+ fileName = 'aiHD_XXXX_YYYY.bin';
438
501
  } else if (/^aiHD.*\.bin.stream$/.test(fileName)) {
439
- fileName = FileNameEnum.aiHDStream;
502
+ fileName = 'aiHD_XXXX_YYYY.bin.stream';
440
503
  }
441
504
  const cachePacketMap = this.packetDataCacheMap.get(fileName);
442
505
  if (!cachePacketMap) {
443
- this.log.warn({
506
+ logger('warn', {
444
507
  msg: `p2pStreamPacketReceiveCallback: fileName : ${fileName} is not support`
445
- });
508
+ }, this.onLogger);
509
+ logP2PDataIfEnabled(this.enableCustomLog, this.devId, 'packet_unsupported_file', `Unsupported file name: ${fileName}`);
446
510
  return;
447
511
  }
448
512
  const cacheSerialNumber = this.packetSerialNumberCacheMap.get(fileName);
@@ -476,16 +540,18 @@ export class SweeperP2p extends P2pApi {
476
540
  }).join('');
477
541
  const cacheFileLength = this.fileLengthCacheMap.get(fileName);
478
542
  if (cacheFileLength > 0 && hexValue.length !== cacheFileLength * 2) {
479
- this.log.warn({
543
+ logger('warn', {
480
544
  msg: `p2pStreamPacketReceiveCallback: fileName : ${fileName} length mismatch, expected: ${cacheFileLength * 2}, received: ${hexValue.length}`
481
- });
545
+ }, this.onLogger);
546
+ logP2PDataIfEnabled(this.enableCustomLog, this.devId, 'packet_length_mismatch', `Packet length mismatch, fileName: ${fileName}, expected: ${cacheFileLength * 2}, received: ${hexValue.length}`);
482
547
  return;
483
548
  }
484
549
  if (this.firstPackageTime > 0 && fileName.indexOf('map') !== -1) {
485
550
  const packageTime = Date.now() - this.firstPackageTime;
486
- this.log.info({
551
+ logger('info', {
487
552
  msg: `receive first full package, cost time: ${packageTime} ms, fileName: ${fileName}`
488
- });
553
+ }, this.onLogger);
554
+ logP2PDataIfEnabled(this.enableCustomLog, this.devId, 'first_full_package_received', `First full package received, fileName: ${fileName}, costTime: ${packageTime}ms`);
489
555
  trace.pointFn({
490
556
  devId: this.devId,
491
557
  eventName: 'receiveFirstFullPackage'
@@ -495,7 +561,29 @@ export class SweeperP2p extends P2pApi {
495
561
  const {
496
562
  type
497
563
  } = FILE_NAME_MAP[fileName];
498
- this.handleDataByType(type, hexValue);
564
+ if (this.cacheData[type] !== hexValue) {
565
+ logP2PDataIfEnabled(this.enableCustomLog, this.devId, 'data_received', `Data received and processed, fileName: ${fileName}, type: ${type}, dataLength: ${hexValue.length}`);
566
+ if (type === 0 || type === 6) {
567
+ this.onReceiveMapData(hexValue);
568
+ this.cacheData[type] = hexValue;
569
+ }
570
+ if (type === 1) {
571
+ logger('info', {
572
+ msg: `push new path data`
573
+ }, this.onLogger);
574
+ this.onReceivePathData(hexValue);
575
+ this.cacheData[type] = hexValue;
576
+ }
577
+ if (type === 4) {
578
+ this.onReceiveAIPicData(hexValue);
579
+ }
580
+ if (type === 5) {
581
+ this.onReceiveAIPicHDData(hexValue);
582
+ }
583
+ if (type === 7) {
584
+ this.onReceiveWifiMapData(hexValue);
585
+ }
586
+ }
499
587
  }
500
588
  }
501
589
  };
@@ -507,6 +595,7 @@ export class SweeperP2p extends P2pApi {
507
595
  */
508
596
  readFileFromPath = (fileName, filePath) => {
509
597
  if (!this.setReading(fileName)) return;
598
+ logP2PDataIfEnabled(this.enableCustomLog, this.devId, 'read_file_start', `Starting to read file, fileName: ${fileName}`);
510
599
  try {
511
600
  ty.getFileSystemManager().readFile({
512
601
  filePath,
@@ -517,65 +606,92 @@ export class SweeperP2p extends P2pApi {
517
606
  const bytes = Base64.toByteArray(params.data);
518
607
  const hexValue = join(map(bytes, d => padStart(d.toString(16), 2, '0')), '');
519
608
  const type = this.getFileType(fileName);
520
- if (hexValue.length === 0) {
521
- this.log.warn({
522
- msg: 'receive empty data'
523
- });
524
- return;
609
+ if (this.cacheData[type] !== hexValue) {
610
+ if (hexValue.length === 0) {
611
+ logger('warn', {
612
+ msg: 'receive empty data'
613
+ }, this.onLogger);
614
+ logP2PDataIfEnabled(this.enableCustomLog, this.devId, 'read_file_empty', `Read file returned empty data, fileName: ${fileName}`);
615
+ return;
616
+ }
617
+ if (type === 0 || type === 6) {
618
+ this.onReceiveMapData(hexValue);
619
+ }
620
+ if (type === 1) {
621
+ this.onReceivePathData(hexValue);
622
+ }
623
+ if (type === 4) {
624
+ this.onReceiveAIPicData(hexValue);
625
+ }
626
+ if (type === 5) {
627
+ this.onReceiveAIPicHDData(hexValue);
628
+ }
629
+ if (type === 7) {
630
+ this.onReceiveWifiMapData(hexValue);
631
+ }
632
+ this.cacheData[type] = hexValue;
633
+ logP2PDataIfEnabled(this.enableCustomLog, this.devId, 'read_file_success', `File read and processed successfully, fileName: ${fileName}, type: ${type}`);
525
634
  }
526
- this.handleDataByType(type, hexValue);
527
635
  },
528
636
  fail: e => {
529
- this.log.warn({
637
+ logger('warn', {
530
638
  msg: 'readFileFromPath failed ==>',
531
639
  e
532
- });
640
+ }, this.onLogger);
641
+ const errorMsg = (e === null || e === void 0 ? void 0 : e.errorMsg) || (e === null || e === void 0 ? void 0 : e.errorCode) || JSON.stringify(e) || 'unknown';
642
+ logP2PDataIfEnabled(this.enableCustomLog, this.devId, 'read_file_fail', `File read failed, fileName: ${fileName}, error: ${errorMsg}`);
533
643
  this.resetReading(fileName);
534
644
  }
535
645
  });
536
646
  } catch (e) {
537
647
  this.resetReading(fileName);
538
- this.log.error({
648
+ logger('error', {
539
649
  msg: 'readFileFromPath ==>',
540
650
  e
541
- });
651
+ }, this.onLogger);
652
+ const errorMsg = (e === null || e === void 0 ? void 0 : e.errorMsg) || (e === null || e === void 0 ? void 0 : e.errorCode) || JSON.stringify(e) || 'unknown';
653
+ logP2PDataIfEnabled(this.enableCustomLog, this.devId, 'read_file_error', `File read error, fileName: ${fileName}, error: ${errorMsg}`);
542
654
  }
543
655
  };
544
-
545
- /**
546
- * 根据文件名获取对应的 reading 状态标志
547
- */
548
- getReadingFlag = fileName => {
549
- if (fileName.includes('map_structured') || fileName.includes('map.')) {
550
- return 'readingMap';
551
- }
552
- if (fileName.includes('cleanPath')) {
553
- return 'readingClean';
656
+ setReading = fileName => {
657
+ if (fileName.indexOf('map_structured') !== -1) {
658
+ if (this.readingMap === true) return false;
659
+ this.readingMap = true;
660
+ return true;
554
661
  }
555
- if (fileName.includes('ai.') && !fileName.includes('aiHD')) {
556
- return 'readingAI';
662
+ if (fileName.indexOf('map.') !== -1) {
663
+ if (this.readingMap === true) return false;
664
+ this.readingMap = true;
665
+ return true;
557
666
  }
558
- if (fileName.includes('aiHD')) {
559
- return 'readingHD';
667
+ if (fileName.indexOf('cleanPath') !== -1) {
668
+ if (this.readingClean === true) return false;
669
+ this.readingClean = true;
670
+ return true;
560
671
  }
561
- return null;
562
- };
563
- setReading = fileName => {
564
- const flag = this.getReadingFlag(fileName);
565
- if (!flag) {
672
+ if (fileName.indexOf('ai.') !== -1) {
673
+ if (this.readingAI === true) return false;
674
+ this.readingAI = true;
566
675
  return true;
567
676
  }
568
- const readingState = this[flag];
569
- if (readingState) {
570
- return false;
677
+ if (fileName.indexOf('aiHD') !== -1) {
678
+ if (this.readingHD === true) return false;
679
+ this.readingHD = true;
680
+ return true;
571
681
  }
572
- this[flag] = true;
573
682
  return true;
574
683
  };
575
684
  resetReading = fileName => {
576
- const flag = this.getReadingFlag(fileName);
577
- if (flag) {
578
- this[flag] = false;
685
+ if (fileName.indexOf('map_structured') !== -1) {
686
+ this.readingMap = false;
687
+ } else if (fileName.indexOf('map.') !== -1) {
688
+ this.readingMap = false;
689
+ } else if (fileName.indexOf('cleanPath') !== -1) {
690
+ this.readingClean = false;
691
+ } else if (fileName.indexOf('ai.') !== -1) {
692
+ this.readingAI = false;
693
+ } else if (fileName.indexOf('aiHD') !== -1) {
694
+ this.readingHD = false;
579
695
  }
580
696
  };
581
697
 
@@ -584,11 +700,21 @@ export class SweeperP2p extends P2pApi {
584
700
  * @param fileList
585
701
  */
586
702
  queryNeedFiles = fileList => {
587
- if (!(fileList !== null && fileList !== void 0 && fileList.length)) {
588
- return [];
589
- }
590
- const pattern = this.downloadType === 0 ? /\.bin$/ : /\.bin\.stream$/;
591
- return fileList.filter(item => pattern.test(item.filename)).map(item => item.filename);
703
+ const exitFiles = [];
704
+ const streamPattern = /bin.stream$/;
705
+ const dataPattern = /bin$/;
706
+ fileList && fileList.forEach(item => {
707
+ if (this.downloadType === 0) {
708
+ if (dataPattern.test(item.filename)) {
709
+ exitFiles.push(item.filename);
710
+ }
711
+ } else if (this.downloadType === 1) {
712
+ if (streamPattern.test(item.filename)) {
713
+ exitFiles.push(item.filename);
714
+ }
715
+ }
716
+ });
717
+ return exitFiles;
592
718
  };
593
719
 
594
720
  /**
@@ -597,13 +723,15 @@ export class SweeperP2p extends P2pApi {
597
723
  // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, consistent-return
598
724
  stopObserverSweeperDataByP2P = () => {
599
725
  try {
600
- this.log.info({
726
+ logger('info', {
601
727
  msg: `isConnected: ${this.isConnected}, devId: ${this.devId}`
602
- });
728
+ }, this.onLogger);
729
+ logP2PDataIfEnabled(this.enableCustomLog, this.devId, 'stop_observer_start', `Stopping observer, isConnected: ${this.isConnected}`);
603
730
  if (this.isConnected) {
604
- this.log.info({
731
+ logger('info', {
605
732
  msg: `try disconnect device, devId: ${this.devId}`
606
- });
733
+ }, this.onLogger);
734
+ logP2PDataIfEnabled(this.enableCustomLog, this.devId, 'stop_observer_disconnect', 'Disconnecting device');
607
735
  this.disconnectDevice();
608
736
  }
609
737
  this.removeP2pDownloadEvent();
@@ -612,12 +740,14 @@ export class SweeperP2p extends P2pApi {
612
740
 
613
741
  // 先销毁断开监听
614
742
  typeof this.offSessionStatusChange === 'function' && this.offSessionStatusChange();
743
+ logP2PDataIfEnabled(this.enableCustomLog, this.devId, 'stop_observer_complete', 'Observer stopped successfully');
615
744
  // 销毁初始化时,先进行断连操作
616
745
  } catch (e) {
617
- this.log.error({
746
+ logger('error', {
618
747
  msg: 'stopObserverSweeperDataByP2P occur error ==>',
619
748
  e
620
- });
749
+ }, this.onLogger);
750
+ logP2PDataIfEnabled(this.enableCustomLog, this.devId, 'stop_observer_error', `Error stopping observer: ${(e === null || e === void 0 ? void 0 : e.message) || 'unknown'}`);
621
751
  return false;
622
752
  }
623
753
  };