agora-foundation 3.10.0-alpha → 3.10.0-beta

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.
@@ -11,9 +11,6 @@ require("core-js/modules/es.array.concat.js");
11
11
  require("core-js/modules/es.array.for-each.js");
12
12
  require("core-js/modules/es.function.name.js");
13
13
  require("core-js/modules/es.object.to-string.js");
14
- require("core-js/modules/esnext.iterator.constructor.js");
15
- require("core-js/modules/esnext.iterator.for-each.js");
16
- require("core-js/modules/web.dom-collections.for-each.js");
17
14
  function validateParams(handlerError) {
18
15
  return function () {
19
16
  for (var _len = arguments.length, schemas = new Array(_len), _key = 0; _key < _len; _key++) {
@@ -32,7 +32,7 @@ var LoggerImpl = exports.LoggerImpl = /*#__PURE__*/function () {
32
32
  var path = window.require('path');
33
33
  var _window$require = window.require('@electron/remote'),
34
34
  app = _window$require.app;
35
- var logFolderPath = path.resolve(app.getPath('logs'), 'logs');
35
+ var logFolderPath = path.resolve(app.getPath('logs'), 'logs', this._label);
36
36
  var maxFiles = _opts.maxFiles || 5;
37
37
  var maxSize = _opts.maxSize || 512;
38
38
  _logWorkerInteractor.addFsLogger(_label, logFolderPath, maxFiles, maxSize);
@@ -22,7 +22,7 @@ export declare const uint8ArrayToImageData: (target: {
22
22
  buffer?: Uint8Array;
23
23
  width?: number;
24
24
  height?: number;
25
- isWindows: boolean;
25
+ needsColorSwap: boolean;
26
26
  }) => string;
27
27
  export declare const renderMeetingId: (meetingId: string | undefined, roomId: string) => string;
28
28
  export {};
@@ -117,14 +117,17 @@ var uint8ArrayToImageData = exports.uint8ArrayToImageData = function uint8ArrayT
117
117
  var srow = row;
118
118
  var imageData = ctx.createImageData(width, 1);
119
119
  var start = srow * width * 4;
120
- if (target.isWindows) {
120
+ if (target.needsColorSwap) {
121
+ // BGRA -> RGBA 转换:交换 B 和 R 通道
122
+ // Windows 和 Linux 平台的 buffer 格式是 BGRA,需要转换为 RGBA
121
123
  for (var i = 0; i < rowBytes; i += 4) {
122
- imageData.data[i] = target.buffer[start + i + 2];
123
- imageData.data[i + 1] = target.buffer[start + i + 1];
124
- imageData.data[i + 2] = target.buffer[start + i];
125
- imageData.data[i + 3] = target.buffer[start + i + 3];
124
+ imageData.data[i] = target.buffer[start + i + 2]; // R
125
+ imageData.data[i + 1] = target.buffer[start + i + 1]; // G
126
+ imageData.data[i + 2] = target.buffer[start + i]; // B
127
+ imageData.data[i + 3] = target.buffer[start + i + 3]; // A
126
128
  }
127
129
  } else {
130
+ // Mac 平台直接复制(已经是 RGBA 格式)
128
131
  for (var _i = 0; _i < rowBytes; ++_i) {
129
132
  imageData.data[_i] = target.buffer[start + _i];
130
133
  }
@@ -3,16 +3,20 @@ export declare const zipDir: (dirPath: string, options?: {
3
3
  filePattern?: RegExp;
4
4
  dirPattern?: RegExp;
5
5
  clean?: boolean;
6
+ fileExtensionPattern?: RegExp;
7
+ zipFileName?: string;
6
8
  }) => Promise<File | null>;
7
9
  /**
8
10
  * 删除目录中不符合规则的旧文件和目录
9
11
  * @param dirPath 目录路径
10
12
  * @param options.filePattern 文件名匹配规则(不符合的删除)
11
13
  * @param options.dirPattern 目录名匹配规则(不符合的删除)
14
+ * @param options.fileExtensionPattern 文件扩展名匹配规则(如 /\.(log|txt)$/),不传则不过滤
12
15
  */
13
16
  export declare const cleanDir: (dirPath: string, options?: {
14
17
  filePattern?: RegExp;
15
18
  dirPattern?: RegExp;
19
+ fileExtensionPattern?: RegExp;
16
20
  }) => Promise<void>;
17
21
  export declare const createMultiEntryZip: () => {
18
22
  addFile: (fileName: string, content: string) => void;
@@ -42,7 +42,7 @@ var COMPRESSION_LEVEL = 9;
42
42
  var zipDir = exports.zipDir = function zipDir(dirPath, options) {
43
43
  return new Promise(/*#__PURE__*/function () {
44
44
  var _ref = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee2(resolve) {
45
- var fs, recursive, files, zip, _iterator, _step, _step$value, relativePath, absolutePath, logsStr, blob, buffer, now, datefmt, file, _t2;
45
+ var fs, recursive, files, zip, _iterator, _step, _step$value, relativePath, absolutePath, logsStr, blob, buffer, now, datefmt, fileName, file, _t2;
46
46
  return _regenerator["default"].wrap(function (_context2) {
47
47
  while (1) switch (_context2.prev = _context2.next) {
48
48
  case 0:
@@ -57,7 +57,8 @@ var zipDir = exports.zipDir = function zipDir(dirPath, options) {
57
57
  _context2.next = 1;
58
58
  return cleanDir(dirPath, {
59
59
  filePattern: options.filePattern,
60
- dirPattern: options.dirPattern
60
+ dirPattern: options.dirPattern,
61
+ fileExtensionPattern: options.fileExtensionPattern
61
62
  });
62
63
  case 1:
63
64
  if (!recursive) {
@@ -67,7 +68,8 @@ var zipDir = exports.zipDir = function zipDir(dirPath, options) {
67
68
  _context2.next = 2;
68
69
  return _collectFiles(dirPath, {
69
70
  filePattern: options === null || options === void 0 ? void 0 : options.filePattern,
70
- dirPattern: options === null || options === void 0 ? void 0 : options.dirPattern
71
+ dirPattern: options === null || options === void 0 ? void 0 : options.dirPattern,
72
+ fileExtensionPattern: options === null || options === void 0 ? void 0 : options.fileExtensionPattern
71
73
  });
72
74
  case 2:
73
75
  files = _context2.sent;
@@ -107,7 +109,8 @@ var zipDir = exports.zipDir = function zipDir(dirPath, options) {
107
109
  buffer = _context2.sent;
108
110
  now = new Date();
109
111
  datefmt = now.toISOString().replace(/\.\d{3}Z$/, 'Z') + 'Z';
110
- file = new File([buffer], "logs-".concat(datefmt, ".zip"), {
112
+ fileName = (options === null || options === void 0 ? void 0 : options.zipFileName) || "logs-".concat(datefmt);
113
+ file = new File([buffer], "".concat(fileName, ".zip"), {
111
114
  type: 'application/zip'
112
115
  });
113
116
  resolve(file);
@@ -117,7 +120,7 @@ var zipDir = exports.zipDir = function zipDir(dirPath, options) {
117
120
  // 原有逻辑:只处理顶层文件
118
121
  fs.readdir(dirPath, /*#__PURE__*/function () {
119
122
  var _ref2 = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee(err, files) {
120
- var zip, _iterator2, _step2, _file, filePath, _logsStr, blob, buffer, now, datefmt, file, _t;
123
+ var zip, _iterator2, _step2, _file, filePath, _logsStr, blob, buffer, now, datefmt, fileName, file, _t;
121
124
  return _regenerator["default"].wrap(function (_context) {
122
125
  while (1) switch (_context.prev = _context.next) {
123
126
  case 0:
@@ -142,42 +145,48 @@ var zipDir = exports.zipDir = function zipDir(dirPath, options) {
142
145
  _iterator2.s();
143
146
  case 4:
144
147
  if ((_step2 = _iterator2.n()).done) {
145
- _context.next = 8;
148
+ _context.next = 9;
146
149
  break;
147
150
  }
148
151
  _file = _step2.value;
149
- if (!(options !== null && options !== void 0 && options.filePattern && !options.filePattern.test(_file))) {
152
+ if (!(options !== null && options !== void 0 && options.fileExtensionPattern && !options.fileExtensionPattern.test(_file))) {
150
153
  _context.next = 5;
151
154
  break;
152
155
  }
153
- return _context.abrupt("continue", 7);
156
+ return _context.abrupt("continue", 8);
154
157
  case 5:
158
+ if (!(options !== null && options !== void 0 && options.filePattern && !options.filePattern.test(_file))) {
159
+ _context.next = 6;
160
+ break;
161
+ }
162
+ return _context.abrupt("continue", 8);
163
+ case 6:
155
164
  filePath = "".concat(dirPath, "/").concat(_file);
156
- _context.next = 6;
165
+ _context.next = 7;
157
166
  return isFile(filePath);
158
- case 6:
167
+ case 7:
159
168
  if (!_context.sent) {
160
- _context.next = 7;
169
+ _context.next = 8;
161
170
  break;
162
171
  }
163
172
  _logsStr = fs.readFileSync(filePath, 'utf8');
164
173
  zip.file(_file, _logsStr);
165
- case 7:
166
- _context.next = 4;
167
- break;
168
174
  case 8:
169
- _context.next = 10;
175
+ _context.next = 4;
170
176
  break;
171
177
  case 9:
172
- _context.prev = 9;
173
- _t = _context["catch"](3);
174
- _iterator2.e(_t);
178
+ _context.next = 11;
179
+ break;
175
180
  case 10:
176
181
  _context.prev = 10;
177
- _iterator2.f();
178
- return _context.finish(10);
182
+ _t = _context["catch"](3);
183
+ _iterator2.e(_t);
179
184
  case 11:
180
- _context.next = 12;
185
+ _context.prev = 11;
186
+ _iterator2.f();
187
+ return _context.finish(11);
188
+ case 12:
189
+ _context.next = 13;
181
190
  return zip.generateAsync({
182
191
  type: 'blob',
183
192
  compression: 'DEFLATE',
@@ -185,23 +194,24 @@ var zipDir = exports.zipDir = function zipDir(dirPath, options) {
185
194
  level: COMPRESSION_LEVEL
186
195
  }
187
196
  });
188
- case 12:
197
+ case 13:
189
198
  blob = _context.sent;
190
- _context.next = 13;
199
+ _context.next = 14;
191
200
  return blob.arrayBuffer();
192
- case 13:
201
+ case 14:
193
202
  buffer = _context.sent;
194
203
  now = new Date();
195
204
  datefmt = now.toISOString().replace(/\.\d{3}Z$/, 'Z') + 'Z';
196
- file = new File([buffer], "logs-".concat(datefmt, ".zip"), {
205
+ fileName = (options === null || options === void 0 ? void 0 : options.zipFileName) || "logs-".concat(datefmt);
206
+ file = new File([buffer], "".concat(fileName, ".zip"), {
197
207
  type: 'application/zip'
198
208
  });
199
209
  resolve(file);
200
- case 14:
210
+ case 15:
201
211
  case "end":
202
212
  return _context.stop();
203
213
  }
204
- }, _callee, null, [[3, 9, 10, 11]]);
214
+ }, _callee, null, [[3, 10, 11, 12]]);
205
215
  }));
206
216
  return function (_x2, _x3) {
207
217
  return _ref2.apply(this, arguments);
@@ -286,6 +296,7 @@ var isDirectory = /*#__PURE__*/function () {
286
296
  * @param dirPath 目录路径
287
297
  * @param options.filePattern 文件名匹配规则(不符合的删除)
288
298
  * @param options.dirPattern 目录名匹配规则(不符合的删除)
299
+ * @param options.fileExtensionPattern 文件扩展名匹配规则(如 /\.(log|txt)$/),不传则不过滤
289
300
  */
290
301
  var cleanDir = exports.cleanDir = function cleanDir(dirPath, options) {
291
302
  return new Promise(function (resolve) {
@@ -295,7 +306,7 @@ var cleanDir = exports.cleanDir = function cleanDir(dirPath, options) {
295
306
  withFileTypes: true
296
307
  }, /*#__PURE__*/function () {
297
308
  var _ref5 = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee5(err, items) {
298
- var _iterator3, _step3, item, itemPath, dirMatches, _t3;
309
+ var _iterator3, _step3, item, itemPath, matchesExtension, matchesPattern, keep, dirMatches, _t3;
299
310
  return _regenerator["default"].wrap(function (_context5) {
300
311
  while (1) switch (_context5.prev = _context5.next) {
301
312
  case 0:
@@ -328,8 +339,11 @@ var cleanDir = exports.cleanDir = function cleanDir(dirPath, options) {
328
339
  _context5.next = 5;
329
340
  break;
330
341
  }
331
- // 文件:检查 filePattern
332
- if (options !== null && options !== void 0 && options.filePattern && !options.filePattern.test(item.name)) {
342
+ // 文件:检查扩展名和 filePattern
343
+ matchesExtension = options !== null && options !== void 0 && options.fileExtensionPattern ? options.fileExtensionPattern.test(item.name) : true;
344
+ matchesPattern = options !== null && options !== void 0 && options.filePattern ? options.filePattern.test(item.name) : true;
345
+ keep = matchesExtension && matchesPattern;
346
+ if (!keep) {
333
347
  fs.unlinkSync(itemPath);
334
348
  console.log("[cleanDir] deleted file: ".concat(itemPath));
335
349
  }
@@ -469,7 +483,12 @@ var _cleanDirRecursively = /*#__PURE__*/function () {
469
483
 
470
484
  /**
471
485
  * 递归遍历目录并收集所有文件
472
- * filePattern 只对顶层目录的文件生效,匹配 dirPattern 的子目录会收集所有文件
486
+ * @param dirPath 目录路径
487
+ * @param fileExtensionPattern 文件扩展名匹配规则(对所有目录生效)
488
+ * @param options.filePattern 文件名匹配规则(只对顶层目录生效)
489
+ * @param options.dirPattern 目录名匹配规则
490
+ * @param baseDir 基础目录路径
491
+ * @param skipFileFilter 是否跳过 filePattern 验证(子目录中使用)
473
492
  */
474
493
  var _collectFiles = /*#__PURE__*/function () {
475
494
  var _ref7 = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee7(dirPath, options) {
@@ -481,6 +500,8 @@ var _collectFiles = /*#__PURE__*/function () {
481
500
  _iterator5,
482
501
  _step5,
483
502
  entry,
503
+ patternFail,
504
+ extFail,
484
505
  relativePath,
485
506
  subFiles,
486
507
  _args7 = arguments,
@@ -527,7 +548,13 @@ var _collectFiles = /*#__PURE__*/function () {
527
548
  _context7.next = 6;
528
549
  break;
529
550
  }
530
- if (!(!skipFileFilter && options !== null && options !== void 0 && options.filePattern && !options.filePattern.test(entry.name))) {
551
+ if (skipFileFilter) {
552
+ _context7.next = 5;
553
+ break;
554
+ }
555
+ patternFail = (options === null || options === void 0 ? void 0 : options.filePattern) && !options.filePattern.test(entry.name);
556
+ extFail = (options === null || options === void 0 ? void 0 : options.fileExtensionPattern) && !options.fileExtensionPattern.test(entry.name);
557
+ if (!(patternFail || extFail)) {
531
558
  _context7.next = 5;
532
559
  break;
533
560
  }
@@ -555,7 +582,9 @@ var _collectFiles = /*#__PURE__*/function () {
555
582
  return _context7.abrupt("continue", 10);
556
583
  case 8:
557
584
  _context7.next = 9;
558
- return _collectFiles(entry.path, options, baseDir, true);
585
+ return _collectFiles(entry.path, {
586
+ fileExtensionPattern: options === null || options === void 0 ? void 0 : options.fileExtensionPattern
587
+ }, baseDir, false);
559
588
  case 9:
560
589
  subFiles = _context7.sent;
561
590
  result.push.apply(result, (0, _toConsumableArray2["default"])(subFiles));
@@ -25,6 +25,7 @@ Object.defineProperty(exports, "__esModule", {
25
25
  exports.collectLogsOnFs = exports.clearTempLogs = void 0;
26
26
  var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
27
27
  require("core-js/modules/es.array.concat.js");
28
+ require("core-js/modules/es.string.ends-with.js");
28
29
  var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
29
30
  var _jszip = _interopRequireDefault(require("jszip"));
30
31
  var _constants = require("../constants");
@@ -43,7 +44,7 @@ var collectLogsOnFs = exports.collectLogsOnFs = /*#__PURE__*/function () {
43
44
  fs = window.require('fs');
44
45
  fs.readdir(logDirPath, /*#__PURE__*/function () {
45
46
  var _ref2 = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee(err, files) {
46
- var zip, _iterator, _step, file, filePath, logFileData, blob, buffer;
47
+ var zip, _iterator, _step, file, filePath, logFileData, blob, buffer, _t;
47
48
  return _regenerator["default"].wrap(function (_context) {
48
49
  while (1) switch (_context.prev = _context.next) {
49
50
  case 0:
@@ -55,7 +56,7 @@ var collectLogsOnFs = exports.collectLogsOnFs = /*#__PURE__*/function () {
55
56
  (0, _reply.reply)(self, callId, _constants.WorkerDirectives.COLLECT_LOGS_ON_FS, {
56
57
  isSuccess: false
57
58
  });
58
- _context.next = 5;
59
+ _context.next = 13;
59
60
  break;
60
61
  case 1:
61
62
  if (!(files.length === 0)) {
@@ -66,42 +67,62 @@ var collectLogsOnFs = exports.collectLogsOnFs = /*#__PURE__*/function () {
66
67
  isSuccess: true,
67
68
  buffer: null
68
69
  });
69
- _context.next = 5;
70
+ _context.next = 13;
70
71
  break;
71
72
  case 2:
72
73
  zip = new _jszip["default"]();
73
74
  _iterator = _createForOfIteratorHelper(files);
74
- try {
75
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
76
- file = _step.value;
77
- filePath = "".concat(logDirPath, "/").concat(file);
78
- logFileData = fs.readFileSync(filePath);
79
- zip.file(file, logFileData);
80
- }
81
- } catch (err) {
82
- _iterator.e(err);
83
- } finally {
84
- _iterator.f();
75
+ _context.prev = 3;
76
+ _iterator.s();
77
+ case 4:
78
+ if ((_step = _iterator.n()).done) {
79
+ _context.next = 7;
80
+ break;
81
+ }
82
+ file = _step.value;
83
+ if (file.endsWith('.log')) {
84
+ _context.next = 5;
85
+ break;
85
86
  }
86
- _context.next = 3;
87
+ return _context.abrupt("continue", 6);
88
+ case 5:
89
+ filePath = "".concat(logDirPath, "/").concat(file);
90
+ logFileData = fs.readFileSync(filePath);
91
+ zip.file(file, logFileData);
92
+ case 6:
93
+ _context.next = 4;
94
+ break;
95
+ case 7:
96
+ _context.next = 9;
97
+ break;
98
+ case 8:
99
+ _context.prev = 8;
100
+ _t = _context["catch"](3);
101
+ _iterator.e(_t);
102
+ case 9:
103
+ _context.prev = 9;
104
+ _iterator.f();
105
+ return _context.finish(9);
106
+ case 10:
107
+ _context.next = 11;
87
108
  return zip.generateAsync({
88
109
  type: 'blob'
89
110
  });
90
- case 3:
111
+ case 11:
91
112
  blob = _context.sent;
92
- _context.next = 4;
113
+ _context.next = 12;
93
114
  return blob.arrayBuffer();
94
- case 4:
115
+ case 12:
95
116
  buffer = _context.sent;
96
117
  (0, _reply.reply)(self, callId, _constants.WorkerDirectives.COLLECT_LOGS_ON_FS, {
97
118
  isSuccess: true,
98
119
  buffer: buffer
99
120
  });
100
- case 5:
121
+ case 13:
101
122
  case "end":
102
123
  return _context.stop();
103
124
  }
104
- }, _callee);
125
+ }, _callee, null, [[3, 8, 9, 10]]);
105
126
  }));
106
127
  return function (_x4, _x5) {
107
128
  return _ref2.apply(this, arguments);
@@ -109,7 +130,7 @@ var collectLogsOnFs = exports.collectLogsOnFs = /*#__PURE__*/function () {
109
130
  }());
110
131
  } catch (e) {
111
132
  console.error("[logger] failed to get buffer.", e);
112
- (0, _reply.reply)(self, callId, _constants.WorkerDirectives.GET_BUFFER, {
133
+ (0, _reply.reply)(self, callId, _constants.WorkerDirectives.COLLECT_LOGS_ON_FS, {
113
134
  isSuccess: false
114
135
  });
115
136
  }
@@ -125,7 +146,7 @@ var collectLogsOnFs = exports.collectLogsOnFs = /*#__PURE__*/function () {
125
146
  }();
126
147
  var clearTempLogs = exports.clearTempLogs = /*#__PURE__*/function () {
127
148
  var _ref3 = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee3(self, callId) {
128
- var _t;
149
+ var _t2;
129
150
  return _regenerator["default"].wrap(function (_context3) {
130
151
  while (1) switch (_context3.prev = _context3.next) {
131
152
  case 0:
@@ -140,8 +161,8 @@ var clearTempLogs = exports.clearTempLogs = /*#__PURE__*/function () {
140
161
  break;
141
162
  case 2:
142
163
  _context3.prev = 2;
143
- _t = _context3["catch"](0);
144
- console.error("[logger] failed to clear temp logs.", _t);
164
+ _t2 = _context3["catch"](0);
165
+ console.error("[logger] failed to clear temp logs.", _t2);
145
166
  (0, _reply.reply)(self, callId, _constants.WorkerDirectives.CLEAR_TEMP_LOGS, {
146
167
  isSuccess: false
147
168
  });
@@ -21,6 +21,7 @@ require("core-js/modules/es.array.map.js");
21
21
  require("core-js/modules/es.array.push.js");
22
22
  require("core-js/modules/es.array.slice.js");
23
23
  require("core-js/modules/es.array.sort.js");
24
+ require("core-js/modules/es.array.splice.js");
24
25
  require("core-js/modules/es.date.to-string.js");
25
26
  require("core-js/modules/es.object.to-string.js");
26
27
  require("core-js/modules/es.string.ends-with.js");
@@ -70,10 +71,6 @@ var createRotateTransport = exports.createRotateTransport = function createRotat
70
71
  _this.path = require('path');
71
72
  return _this;
72
73
  }
73
-
74
- /**
75
- * 生成唯一的日志文件名,避免同一秒多次轮转导致的覆盖
76
- */
77
74
  (0, _inherits2["default"])(CustomRotateTransport, _WinstonTransport);
78
75
  return (0, _createClass2["default"])(CustomRotateTransport, [{
79
76
  key: "generateLogFilename",
@@ -87,10 +84,6 @@ var createRotateTransport = exports.createRotateTransport = function createRotat
87
84
  }
88
85
  return this.rotateIndex === 0 ? "".concat(this.filenamePrefix, "-").concat(timestamp, ".log") : "".concat(this.filenamePrefix, "-").concat(timestamp, "-").concat(this.rotateIndex, ".log");
89
86
  }
90
-
91
- /**
92
- * 创建新日志文件,并清理旧文件
93
- */
94
87
  }, {
95
88
  key: "createNewLogFile",
96
89
  value: function createNewLogFile() {
@@ -98,7 +91,7 @@ var createRotateTransport = exports.createRotateTransport = function createRotat
98
91
  this.currentStream.end();
99
92
  }
100
93
  var filename = this.generateLogFilename();
101
- this.currentFile = this.path.join(this.logFolderPath, this.filenamePrefix, filename);
94
+ this.currentFile = this.path.join(this.logFolderPath, filename);
102
95
  console.log("[CustomRotateTransport] Creating new log file: ".concat(this.currentFile));
103
96
  var dirPath = this.path.dirname(this.currentFile);
104
97
  if (!this.fs.existsSync(dirPath)) {
@@ -109,12 +102,15 @@ var createRotateTransport = exports.createRotateTransport = function createRotat
109
102
  this.currentStream = this.fs.createWriteStream(this.currentFile, {
110
103
  flags: 'a'
111
104
  });
112
- this.currentSize = this.fs.existsSync(this.currentFile) ? this.fs.statSync(this.currentFile).size : 0;
113
- this.cleanupOldFiles();
105
+ // 新文件必然从 0 开始,用内存计数器替代 statSync
106
+ this.currentSize = 0;
107
+ this.cleanupOldFiles(this.maxFiles - 1);
114
108
  }
115
109
 
116
110
  /**
117
- * 只允许每个 buffer 触发一次轮转,避免多余文件
111
+ * 与老版本结构完全一致,只做一处改动:
112
+ * 原来在写入回调里用 statSync 读磁盘更新 currentSize,
113
+ * 改为用内存计数器 currentSize += buffer.length,消除每条日志的磁盘读操作。
118
114
  */
119
115
  }, {
120
116
  key: "processQueue",
@@ -126,16 +122,12 @@ var createRotateTransport = exports.createRotateTransport = function createRotat
126
122
  buffer = _ref.buffer,
127
123
  callback = _ref.callback;
128
124
 
129
- // 1. 单条日志大于 maxSize,直接新建新文件并写入,不要理会 currentStream
125
+ // 1. 单条日志大于 maxSize,直接新建新文件并写入
130
126
  if (buffer.length > this.maxSize) {
131
127
  this.createNewLogFile();
132
128
  console.log("[CustomRotateTransport] buffer.length (".concat(buffer.length, ") > maxSize (").concat(this.maxSize, "), force rotate."));
133
129
  this.currentStream.write(buffer, function () {
134
- try {
135
- _this2.currentSize = _this2.fs.statSync(_this2.currentFile).size;
136
- } catch (_unused) {
137
- _this2.currentSize += buffer.length;
138
- }
130
+ _this2.currentSize += buffer.length; // ← 替代 statSync
139
131
  callback();
140
132
  _this2.writing = false;
141
133
  _this2.processQueue();
@@ -143,30 +135,17 @@ var createRotateTransport = exports.createRotateTransport = function createRotat
143
135
  return;
144
136
  }
145
137
 
146
- // 2. buffer.length <= maxSize,才需要判断 currentStream 是否为空
138
+ // 2. buffer.length <= maxSize,判断 currentStream 是否为空
147
139
  if (!this.currentStream) {
148
140
  this.createNewLogFile();
149
141
  }
150
- var actualSize = 0;
151
- try {
152
- actualSize = this.fs.existsSync(this.currentFile) ? this.fs.statSync(this.currentFile).size : 0;
153
- } catch (_unused2) {
154
- actualSize = this.currentSize;
155
- }
156
- if (actualSize + buffer.length > this.maxSize) {
157
- console.log("[CustomRotateTransport] actualSize (".concat(actualSize, ") + buffer.length (").concat(buffer.length, ") > maxSize (").concat(this.maxSize, "), rotate."));
142
+
143
+ // 用内存计数器替代 existsSync + statSync 判断是否需要轮转
144
+ if (this.currentSize + buffer.length > this.maxSize) {
158
145
  this.createNewLogFile();
159
- // 强制清理,确保文件数量不超过限制
160
- setImmediate(function () {
161
- return _this2.cleanupOldFiles();
162
- });
163
146
  }
164
147
  this.currentStream.write(buffer, function () {
165
- try {
166
- _this2.currentSize = _this2.fs.statSync(_this2.currentFile).size;
167
- } catch (_unused3) {
168
- _this2.currentSize += buffer.length;
169
- }
148
+ _this2.currentSize += buffer.length;
170
149
  callback();
171
150
  _this2.writing = false;
172
151
  _this2.processQueue();
@@ -174,40 +153,60 @@ var createRotateTransport = exports.createRotateTransport = function createRotat
174
153
  }
175
154
 
176
155
  /**
177
- * 清理旧日志文件,只保留 maxFiles
156
+ * 只把同步 I/O(readdirSync / statSync / unlinkSync)改为异步回调,
157
+ * 避免阻塞 Worker 线程导致写入队列积压。
178
158
  */
179
159
  }, {
180
160
  key: "cleanupOldFiles",
181
161
  value: function cleanupOldFiles() {
182
162
  var _this3 = this;
183
- try {
184
- var files = this.fs.readdirSync(this.logFolderPath).filter(function (file) {
185
- return file.startsWith(_this3.filenamePrefix) && file.endsWith('.log');
186
- }).map(function (file) {
187
- return {
188
- name: file,
189
- path: _this3.path.join(_this3.logFolderPath, file),
190
- stat: _this3.fs.statSync(_this3.path.join(_this3.logFolderPath, file))
191
- };
192
- }).sort(function (a, b) {
193
- return b.stat.mtime.getTime() - a.stat.mtime.getTime();
163
+ var keepFiles = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.maxFiles;
164
+ var prefix = this.filenamePrefix;
165
+ var logDir = this.logFolderPath;
166
+ console.log("[CustomRotateTransport] cleanupOldFiles: ".concat(logDir));
167
+ this.fs.readdir(logDir, function (err, entries) {
168
+ if (err) {
169
+ console.warn('[CustomRotateTransport] Error reading log folder:', err);
170
+ return;
171
+ }
172
+ var files = entries.filter(function (file) {
173
+ return file.startsWith(prefix) && file.endsWith('.log');
194
174
  });
195
- console.log("[CustomRotateTransport] Found ".concat(files.length, " log files, maxFiles: ").concat(this.maxFiles));
196
- if (files.length > this.maxFiles) {
197
- var filesToDelete = files.slice(this.maxFiles);
198
- console.log("[CustomRotateTransport] Will delete ".concat(filesToDelete.length, " old files"));
199
- filesToDelete.forEach(function (file) {
200
- try {
201
- _this3.fs.unlinkSync(file.path);
202
- console.log("[CustomRotateTransport] Deleted old log file: ".concat(file.path));
203
- } catch (err) {
204
- console.warn("[CustomRotateTransport] Failed to delete log file: ".concat(file.path), err);
175
+ console.log("[CustomRotateTransport] Found ".concat(files.length, " log files, maxKeepFiles: ").concat(keepFiles));
176
+ if (files.length <= keepFiles) return;
177
+
178
+ // 并行 stat mtime,全部完成后按时间排序删除最旧的
179
+ var pending = files.length;
180
+ var fileInfos = [];
181
+ files.forEach(function (file) {
182
+ var filePath = _this3.path.join(logDir, file);
183
+ _this3.fs.stat(filePath, function (statErr, stat) {
184
+ if (!statErr) {
185
+ fileInfos.push({
186
+ name: file,
187
+ path: filePath,
188
+ stat: stat
189
+ });
190
+ }
191
+ pending--;
192
+ if (pending === 0) {
193
+ fileInfos.sort(function (a, b) {
194
+ return b.stat.mtime.getTime() - a.stat.mtime.getTime();
195
+ });
196
+ var filesToDelete = fileInfos.slice(keepFiles);
197
+ filesToDelete.forEach(function (f) {
198
+ _this3.fs.unlink(f.path, function (unlinkErr) {
199
+ if (unlinkErr) {
200
+ console.warn("[CustomRotateTransport] Failed to delete log file: ".concat(f.path), unlinkErr);
201
+ } else {
202
+ console.log("[CustomRotateTransport] Deleted old log file: ".concat(f.path));
203
+ }
204
+ });
205
+ });
205
206
  }
206
207
  });
207
- }
208
- } catch (err) {
209
- console.warn('[CustomRotateTransport] Error cleaning up old log files:', err);
210
- }
208
+ });
209
+ });
211
210
  }
212
211
  }, {
213
212
  key: "log",
@@ -227,6 +226,21 @@ var createRotateTransport = exports.createRotateTransport = function createRotat
227
226
  }, {
228
227
  key: "close",
229
228
  value: function close() {
229
+ // 同步刷入 writeQueue 中还未写入的日志,防止进程退出时丢失
230
+ var remaining = this.writeQueue.splice(0);
231
+ if (remaining.length > 0 && this.currentFile) {
232
+ try {
233
+ var data = Buffer.concat(remaining.map(function (item) {
234
+ return item.buffer;
235
+ }));
236
+ this.fs.appendFileSync(this.currentFile, data);
237
+ } catch (_unused) {
238
+ // 关闭阶段忽略写入错误
239
+ }
240
+ remaining.forEach(function (item) {
241
+ return item.callback();
242
+ });
243
+ }
230
244
  if (this.currentStream) {
231
245
  this.currentStream.end();
232
246
  this.currentStream = null;