monsqlize 1.3.0 → 2.0.0

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 (172) hide show
  1. package/CHANGELOG.md +56 -60
  2. package/LICENSE +201 -21
  3. package/README.md +537 -1828
  4. package/changelogs/README.md +160 -0
  5. package/changelogs/v2.0.0.md +222 -0
  6. package/dist/cjs/index.cjs +10600 -0
  7. package/dist/cjs/mongodb/common/transaction-aware.cjs +10 -0
  8. package/dist/cjs/transaction/CacheLockManager.cjs +100 -0
  9. package/dist/cjs/transaction/Transaction.cjs +158 -0
  10. package/dist/cjs/transaction/TransactionManager.cjs +298 -0
  11. package/dist/esm/index.mjs +10650 -0
  12. package/dist/types/base.d.ts +81 -0
  13. package/dist/types/collection.d.ts +1031 -0
  14. package/dist/types/expression.d.ts +115 -0
  15. package/dist/types/index.d.ts +23 -0
  16. package/dist/types/lock.d.ts +74 -0
  17. package/dist/types/model.d.ts +526 -0
  18. package/dist/types/mongodb.d.ts +49 -0
  19. package/dist/types/monsqlize.d.ts +491 -0
  20. package/dist/types/pool.d.ts +84 -0
  21. package/dist/types/runtime.d.ts +362 -0
  22. package/dist/types/saga.d.ts +143 -0
  23. package/dist/types/slow-query-log.d.ts +126 -0
  24. package/dist/types/sync.d.ts +103 -0
  25. package/dist/types/transaction.d.ts +132 -0
  26. package/package.json +67 -69
  27. package/index.d.ts +0 -206
  28. package/index.mjs +0 -52
  29. package/lib/cache-invalidation.js +0 -279
  30. package/lib/cache.js +0 -530
  31. package/lib/common/cursor.js +0 -59
  32. package/lib/common/docs-urls.js +0 -73
  33. package/lib/common/index-options.js +0 -223
  34. package/lib/common/log.js +0 -61
  35. package/lib/common/namespace.js +0 -22
  36. package/lib/common/normalize.js +0 -34
  37. package/lib/common/page-result.js +0 -43
  38. package/lib/common/runner.js +0 -57
  39. package/lib/common/server-features.js +0 -232
  40. package/lib/common/shape-builders.js +0 -27
  41. package/lib/common/validation.js +0 -113
  42. package/lib/connect.js +0 -99
  43. package/lib/constants.js +0 -55
  44. package/lib/count-queue.js +0 -188
  45. package/lib/distributed-cache-invalidator.js +0 -260
  46. package/lib/errors.js +0 -168
  47. package/lib/expression/cache/ExpressionCache.js +0 -114
  48. package/lib/expression/compiler/ExpressionCompiler.js +0 -1090
  49. package/lib/expression/compiler/ExpressionCompilerExtensions.js +0 -531
  50. package/lib/expression/detector.js +0 -84
  51. package/lib/expression/factory.js +0 -29
  52. package/lib/expression/index.js +0 -19
  53. package/lib/function-cache.js +0 -533
  54. package/lib/index.js +0 -1251
  55. package/lib/infrastructure/ConnectionPoolManager.js +0 -464
  56. package/lib/infrastructure/HealthChecker.js +0 -281
  57. package/lib/infrastructure/PoolConfig.js +0 -199
  58. package/lib/infrastructure/PoolSelector.js +0 -225
  59. package/lib/infrastructure/PoolStats.js +0 -244
  60. package/lib/infrastructure/ssh-tunnel-ssh2.js +0 -212
  61. package/lib/infrastructure/ssh-tunnel.js +0 -41
  62. package/lib/infrastructure/uri-parser.js +0 -36
  63. package/lib/lock/Lock.js +0 -67
  64. package/lib/lock/errors.js +0 -28
  65. package/lib/lock/index.js +0 -13
  66. package/lib/logger.js +0 -225
  67. package/lib/model/examples/test.js +0 -311
  68. package/lib/model/features/defaults.js +0 -161
  69. package/lib/model/features/populate.js +0 -568
  70. package/lib/model/features/relations.js +0 -120
  71. package/lib/model/features/soft-delete.js +0 -349
  72. package/lib/model/features/version.js +0 -157
  73. package/lib/model/features/virtuals.js +0 -219
  74. package/lib/model/index.js +0 -1265
  75. package/lib/mongodb/common/accessor-helpers.js +0 -59
  76. package/lib/mongodb/common/agg-pipeline.js +0 -36
  77. package/lib/mongodb/common/aggregation-validator.js +0 -127
  78. package/lib/mongodb/common/iid.js +0 -28
  79. package/lib/mongodb/common/lexicographic-expr.js +0 -53
  80. package/lib/mongodb/common/shape.js +0 -32
  81. package/lib/mongodb/common/sort.js +0 -39
  82. package/lib/mongodb/common/transaction-aware.js +0 -25
  83. package/lib/mongodb/connect.js +0 -234
  84. package/lib/mongodb/index.js +0 -639
  85. package/lib/mongodb/management/admin-ops.js +0 -200
  86. package/lib/mongodb/management/bookmark-ops.js +0 -167
  87. package/lib/mongodb/management/cache-ops.js +0 -50
  88. package/lib/mongodb/management/collection-ops.js +0 -387
  89. package/lib/mongodb/management/database-ops.js +0 -202
  90. package/lib/mongodb/management/index-ops.js +0 -475
  91. package/lib/mongodb/management/index.js +0 -17
  92. package/lib/mongodb/management/namespace.js +0 -31
  93. package/lib/mongodb/management/validation-ops.js +0 -268
  94. package/lib/mongodb/queries/aggregate.js +0 -172
  95. package/lib/mongodb/queries/chain.js +0 -631
  96. package/lib/mongodb/queries/count.js +0 -99
  97. package/lib/mongodb/queries/distinct.js +0 -78
  98. package/lib/mongodb/queries/find-and-count.js +0 -193
  99. package/lib/mongodb/queries/find-by-ids.js +0 -236
  100. package/lib/mongodb/queries/find-one-by-id.js +0 -171
  101. package/lib/mongodb/queries/find-one.js +0 -71
  102. package/lib/mongodb/queries/find-page.js +0 -618
  103. package/lib/mongodb/queries/find.js +0 -171
  104. package/lib/mongodb/queries/index.js +0 -51
  105. package/lib/mongodb/queries/watch.js +0 -538
  106. package/lib/mongodb/writes/common/batch-retry.js +0 -65
  107. package/lib/mongodb/writes/delete-batch.js +0 -323
  108. package/lib/mongodb/writes/delete-many.js +0 -181
  109. package/lib/mongodb/writes/delete-one.js +0 -173
  110. package/lib/mongodb/writes/find-one-and-delete.js +0 -203
  111. package/lib/mongodb/writes/find-one-and-replace.js +0 -239
  112. package/lib/mongodb/writes/find-one-and-update.js +0 -240
  113. package/lib/mongodb/writes/increment-one.js +0 -259
  114. package/lib/mongodb/writes/index.js +0 -46
  115. package/lib/mongodb/writes/insert-batch.js +0 -508
  116. package/lib/mongodb/writes/insert-many.js +0 -223
  117. package/lib/mongodb/writes/insert-one.js +0 -169
  118. package/lib/mongodb/writes/replace-one.js +0 -226
  119. package/lib/mongodb/writes/result-handler.js +0 -237
  120. package/lib/mongodb/writes/update-batch.js +0 -416
  121. package/lib/mongodb/writes/update-many.js +0 -275
  122. package/lib/mongodb/writes/update-one.js +0 -273
  123. package/lib/mongodb/writes/upsert-one.js +0 -203
  124. package/lib/multi-level-cache.js +0 -244
  125. package/lib/operators.js +0 -330
  126. package/lib/redis-cache-adapter.js +0 -267
  127. package/lib/saga/SagaContext.js +0 -67
  128. package/lib/saga/SagaDefinition.js +0 -32
  129. package/lib/saga/SagaExecutor.js +0 -201
  130. package/lib/saga/SagaOrchestrator.js +0 -186
  131. package/lib/saga/index.js +0 -11
  132. package/lib/slow-query-log/base-storage.js +0 -70
  133. package/lib/slow-query-log/batch-queue.js +0 -97
  134. package/lib/slow-query-log/config-manager.js +0 -196
  135. package/lib/slow-query-log/index.js +0 -238
  136. package/lib/slow-query-log/mongodb-storage.js +0 -324
  137. package/lib/slow-query-log/query-hash.js +0 -39
  138. package/lib/sync/ChangeStreamSyncManager.js +0 -405
  139. package/lib/sync/ResumeTokenStore.js +0 -192
  140. package/lib/sync/SyncConfig.js +0 -127
  141. package/lib/sync/SyncTarget.js +0 -240
  142. package/lib/sync/index.js +0 -20
  143. package/lib/transaction/CacheLockManager.js +0 -162
  144. package/lib/transaction/DistributedCacheLockManager.js +0 -475
  145. package/lib/transaction/Transaction.js +0 -315
  146. package/lib/transaction/TransactionManager.js +0 -267
  147. package/lib/transaction/index.js +0 -11
  148. package/lib/utils/objectid-converter.js +0 -632
  149. package/types/README.md +0 -122
  150. package/types/base.ts +0 -94
  151. package/types/batch.ts +0 -187
  152. package/types/cache.ts +0 -71
  153. package/types/chain.ts +0 -254
  154. package/types/collection.ts +0 -357
  155. package/types/expression.ts +0 -109
  156. package/types/function-cache.d.ts +0 -135
  157. package/types/lock.ts +0 -95
  158. package/types/model/definition.ts +0 -152
  159. package/types/model/index.ts +0 -10
  160. package/types/model/instance.ts +0 -121
  161. package/types/model/relations.ts +0 -121
  162. package/types/model/virtuals.ts +0 -32
  163. package/types/monsqlize.ts +0 -245
  164. package/types/options.ts +0 -192
  165. package/types/pagination.ts +0 -154
  166. package/types/pool.ts +0 -125
  167. package/types/query.ts +0 -71
  168. package/types/saga.ts +0 -125
  169. package/types/stream.ts +0 -64
  170. package/types/sync.ts +0 -79
  171. package/types/transaction.ts +0 -79
  172. package/types/write.ts +0 -77
@@ -1,405 +0,0 @@
1
- /**
2
- * ChangeStreamSyncManager - Change Stream 同步管理器
3
- *
4
- * 负责管理 MongoDB Change Stream,实时同步数据到备份库
5
- *
6
- * 核心功能:
7
- * - 启动/停止 Change Stream
8
- * - 事件过滤和转换
9
- * - Resume Token 管理
10
- * - 错误处理和自动重连
11
- *
12
- * @module lib/sync/ChangeStreamSyncManager
13
- * @since v1.0.8
14
- */
15
-
16
- const SyncTarget = require('./SyncTarget');
17
- const ResumeTokenStore = require('./ResumeTokenStore');
18
- const { validateSyncConfig } = require('./SyncConfig');
19
-
20
- /**
21
- * Change Stream 同步管理器
22
- */
23
- class ChangeStreamSyncManager {
24
- /**
25
- * 构造函数
26
- *
27
- * @param {Object} options - 配置选项
28
- * @param {Object} options.db - MongoDB 数据库实例
29
- * @param {Object} options.poolManager - ConnectionPoolManager 实例
30
- * @param {Object} options.config - 同步配置
31
- * @param {Object} [options.logger] - 日志记录器
32
- */
33
- constructor(options) {
34
- this.db = options.db;
35
- this.poolManager = options.poolManager;
36
- this.config = options.config;
37
- this.logger = options.logger || console;
38
-
39
- // 验证配置
40
- validateSyncConfig(this.config);
41
-
42
- // Resume Token 管理器
43
- this.tokenStore = new ResumeTokenStore({
44
- storage: this.config.resumeToken?.storage || 'file',
45
- path: this.config.resumeToken?.path || './.sync-resume-token',
46
- redis: this.config.resumeToken?.redis,
47
- logger: this.logger
48
- });
49
-
50
- // 备份目标列表
51
- this.targets = [];
52
-
53
- // Change Stream 实例
54
- this.changeStream = null;
55
- this.isRunning = false;
56
- this.isReconnecting = false;
57
-
58
- // 统计信息
59
- this.stats = {
60
- eventCount: 0,
61
- syncedCount: 0,
62
- errorCount: 0,
63
- startTime: null,
64
- lastEventTime: null
65
- };
66
- }
67
-
68
- /**
69
- * 启动同步
70
- *
71
- * @returns {Promise<void>}
72
- */
73
- async start() {
74
- if (this.isRunning) {
75
- this.logger.warn('[ChangeStreamSync] 同步已在运行中');
76
- return;
77
- }
78
-
79
- try {
80
- // 1. 验证环境(检查 Change Stream 支持)
81
- await this._validateEnvironment();
82
-
83
- // 2. 初始化备份目标
84
- await this._initTargets();
85
-
86
- // 3. 加载 Resume Token
87
- const resumeAfter = await this.tokenStore.load();
88
-
89
- if (resumeAfter) {
90
- this.logger.info('[ChangeStreamSync] 从 Resume Token 恢复');
91
- }
92
-
93
- // 4. 构建过滤管道
94
- const pipeline = this._buildPipeline();
95
-
96
- // 5. 启动 Change Stream
97
- const options = {
98
- fullDocument: 'updateLookup', // 获取完整文档
99
- resumeAfter: resumeAfter || undefined
100
- };
101
-
102
- this.changeStream = this.db.watch(pipeline, options);
103
-
104
- // 6. 注册事件监听
105
- this.changeStream.on('change', (event) => this._handleChange(event));
106
- this.changeStream.on('error', (error) => this._handleError(error));
107
- this.changeStream.on('close', () => this._handleClose());
108
-
109
- this.isRunning = true;
110
- this.stats.startTime = new Date();
111
-
112
- this.logger.info('[ChangeStreamSync] 同步已启动', {
113
- targets: this.targets.length,
114
- targetNames: this.targets.map(t => t.name),
115
- resumeToken: !!resumeAfter,
116
- collections: this.config.collections || ['*']
117
- });
118
-
119
- } catch (error) {
120
- this.logger.error('[ChangeStreamSync] 启动失败', {
121
- error: error.message,
122
- stack: error.stack
123
- });
124
- throw error;
125
- }
126
- }
127
-
128
- /**
129
- * 停止同步
130
- *
131
- * @returns {Promise<void>}
132
- */
133
- async stop() {
134
- if (!this.isRunning) {
135
- this.logger.warn('[ChangeStreamSync] 同步未运行');
136
- return;
137
- }
138
-
139
- try {
140
- // 关闭 Change Stream
141
- if (this.changeStream) {
142
- await this.changeStream.close();
143
- this.changeStream = null;
144
- }
145
-
146
- // 关闭所有目标连接
147
- await Promise.all(this.targets.map(target => target.close()));
148
-
149
- this.isRunning = false;
150
-
151
- this.logger.info('[ChangeStreamSync] 同步已停止', {
152
- stats: this.getStats()
153
- });
154
-
155
- } catch (error) {
156
- this.logger.error('[ChangeStreamSync] 停止失败', {
157
- error: error.message
158
- });
159
- }
160
- }
161
-
162
- /**
163
- * 验证环境(检查 Change Stream 支持)
164
- *
165
- * @private
166
- * @returns {Promise<void>}
167
- */
168
- async _validateEnvironment() {
169
- try {
170
- // 创建临时 Change Stream 测试支持
171
- const testCollection = this.db.collection('_sync_test');
172
- const testStream = testCollection.watch();
173
- await testStream.close();
174
-
175
- this.logger.debug('[ChangeStreamSync] Change Stream 支持检查通过');
176
-
177
- } catch (error) {
178
- if (error.code === 40573 || error.message.includes('changeStream')) {
179
- throw new Error(
180
- 'Change Stream 不可用。请确保:\n' +
181
- '1. MongoDB 是 Replica Set 或 Sharded Cluster\n' +
182
- '2. MongoDB 版本 >= 4.0\n' +
183
- '3. 用户有 changeStream 权限\n' +
184
- '原始错误: ' + error.message
185
- );
186
- }
187
- throw error;
188
- }
189
- }
190
-
191
- /**
192
- * 初始化备份目标
193
- *
194
- * @private
195
- * @returns {Promise<void>}
196
- */
197
- async _initTargets() {
198
- this.targets = [];
199
-
200
- for (const targetConfig of this.config.targets) {
201
- const target = new SyncTarget({
202
- name: targetConfig.name,
203
- poolManager: this.poolManager,
204
- config: targetConfig,
205
- logger: this.logger
206
- });
207
-
208
- await target.connect();
209
- this.targets.push(target);
210
- }
211
-
212
- this.logger.info('[ChangeStreamSync] 备份目标已初始化', {
213
- count: this.targets.length,
214
- names: this.targets.map(t => t.name)
215
- });
216
- }
217
-
218
- /**
219
- * 构建过滤管道
220
- *
221
- * @private
222
- * @returns {Array} MongoDB Aggregation Pipeline
223
- */
224
- _buildPipeline() {
225
- const pipeline = [];
226
-
227
- // 过滤集合
228
- if (this.config.collections && this.config.collections[0] !== '*') {
229
- pipeline.push({
230
- $match: {
231
- 'ns.coll': { $in: this.config.collections }
232
- }
233
- });
234
- }
235
-
236
- // 过滤操作类型
237
- pipeline.push({
238
- $match: {
239
- operationType: { $in: ['insert', 'update', 'delete', 'replace'] }
240
- }
241
- });
242
-
243
- return pipeline;
244
- }
245
-
246
- /**
247
- * 处理 Change Event
248
- *
249
- * @private
250
- * @param {Object} event - Change Stream 事件
251
- * @returns {Promise<void>}
252
- */
253
- async _handleChange(event) {
254
- this.stats.eventCount++;
255
- this.stats.lastEventTime = new Date();
256
-
257
- try {
258
- // 1. 应用自定义过滤
259
- if (this.config.filter && !this.config.filter(event)) {
260
- this.logger.debug('[ChangeStreamSync] 事件被过滤', {
261
- operationType: event.operationType,
262
- collection: event.ns?.coll
263
- });
264
- return;
265
- }
266
-
267
- // 2. 数据转换
268
- let document = event.fullDocument;
269
- if (this.config.transform) {
270
- document = this.config.transform(document);
271
- }
272
-
273
- // 3. 同步到所有目标
274
- const syncPromises = this.targets.map(target =>
275
- target.apply(event.operationType, document, event.documentKey)
276
- .catch(err => {
277
- this.stats.errorCount++;
278
- this.logger.error('[ChangeStreamSync] 目标同步失败', {
279
- target: target.name,
280
- error: err.message
281
- });
282
- // 不抛出,继续同步其他目标
283
- })
284
- );
285
-
286
- await Promise.all(syncPromises);
287
-
288
- this.stats.syncedCount++;
289
-
290
- // 4. 保存 Resume Token
291
- await this.tokenStore.save(event._id);
292
-
293
- this.logger.debug('[ChangeStreamSync] 事件处理完成', {
294
- operationType: event.operationType,
295
- collection: event.ns?.coll,
296
- id: event.documentKey?._id
297
- });
298
-
299
- } catch (error) {
300
- this.stats.errorCount++;
301
- this.logger.error('[ChangeStreamSync] 事件处理失败', {
302
- error: error.message,
303
- event: event.operationType,
304
- collection: event.ns?.coll
305
- });
306
- }
307
- }
308
-
309
- /**
310
- * 处理 Change Stream 错误
311
- *
312
- * @private
313
- * @param {Error} error - 错误对象
314
- */
315
- async _handleError(error) {
316
- this.logger.error('[ChangeStreamSync] Change Stream 错误', {
317
- error: error.message,
318
- code: error.code
319
- });
320
-
321
- // 自动重连
322
- if (!this.isReconnecting) {
323
- await this._reconnect();
324
- }
325
- }
326
-
327
- /**
328
- * 处理 Change Stream 关闭
329
- *
330
- * @private
331
- */
332
- _handleClose() {
333
- this.logger.warn('[ChangeStreamSync] Change Stream 已关闭');
334
-
335
- if (this.isRunning && !this.isReconnecting) {
336
- // 意外关闭,尝试重连
337
- this._reconnect();
338
- }
339
- }
340
-
341
- /**
342
- * 自动重连
343
- *
344
- * @private
345
- * @returns {Promise<void>}
346
- */
347
- async _reconnect() {
348
- if (this.isReconnecting) {
349
- return;
350
- }
351
-
352
- this.isReconnecting = true;
353
- const maxRetries = 5;
354
- let retries = 0;
355
-
356
- this.logger.info('[ChangeStreamSync] 开始重连...');
357
-
358
- while (retries < maxRetries && this.isRunning) {
359
- try {
360
- await this.stop();
361
-
362
- // 指数退避
363
- const delay = 1000 * Math.pow(2, retries);
364
- this.logger.info(`[ChangeStreamSync] 等待 ${delay}ms 后重连...`);
365
- await new Promise(resolve => setTimeout(resolve, delay));
366
-
367
- await this.start();
368
-
369
- this.logger.info('[ChangeStreamSync] 重连成功');
370
- this.isReconnecting = false;
371
- return;
372
-
373
- } catch (error) {
374
- retries++;
375
- this.logger.error(`[ChangeStreamSync] 重连失败 (${retries}/${maxRetries})`, {
376
- error: error.message
377
- });
378
- }
379
- }
380
-
381
- this.isReconnecting = false;
382
- this.logger.error('[ChangeStreamSync] 重连失败,已达到最大重试次数');
383
- }
384
-
385
- /**
386
- * 获取统计信息
387
- *
388
- * @returns {Object} 统计信息
389
- */
390
- getStats() {
391
- return {
392
- isRunning: this.isRunning,
393
- eventCount: this.stats.eventCount,
394
- syncedCount: this.stats.syncedCount,
395
- errorCount: this.stats.errorCount,
396
- startTime: this.stats.startTime,
397
- lastEventTime: this.stats.lastEventTime,
398
- targets: this.targets.map(t => t.getStats())
399
- };
400
- }
401
- }
402
-
403
- module.exports = ChangeStreamSyncManager;
404
-
405
-
@@ -1,192 +0,0 @@
1
- /**
2
- * ResumeTokenStore - Resume Token 持久化存储
3
- *
4
- * 负责保存和加载 Change Stream Resume Token
5
- * 支持文件和 Redis 两种存储方式
6
- *
7
- * @module lib/sync/ResumeTokenStore
8
- * @since v1.0.8
9
- */
10
-
11
- const fs = require('fs').promises;
12
- const path = require('path');
13
-
14
- /**
15
- * Resume Token 存储器
16
- */
17
- class ResumeTokenStore {
18
- /**
19
- * 构造函数
20
- *
21
- * @param {Object} options - 配置选项
22
- * @param {string} options.storage - 存储类型 ('file' | 'redis')
23
- * @param {string} [options.path] - 文件路径(文件模式)
24
- * @param {Object} [options.redis] - Redis 实例(Redis 模式)
25
- * @param {Object} [options.logger] - 日志记录器
26
- */
27
- constructor(options = {}) {
28
- this.storage = options.storage || 'file';
29
- this.path = options.path || './.sync-resume-token';
30
- this.redis = options.redis;
31
- this.logger = options.logger || console;
32
-
33
- // Redis Key
34
- this.redisKey = 'monsqlize:sync:resume-token';
35
- }
36
-
37
- /**
38
- * 加载 Resume Token
39
- *
40
- * @returns {Promise<Object|null>} Resume Token 对象或 null
41
- */
42
- async load() {
43
- try {
44
- if (this.storage === 'redis' && this.redis) {
45
- return await this._loadFromRedis();
46
- } else {
47
- return await this._loadFromFile();
48
- }
49
- } catch (error) {
50
- this.logger.warn('[ResumeTokenStore] 加载 Token 失败', {
51
- storage: this.storage,
52
- error: error.message
53
- });
54
- return null;
55
- }
56
- }
57
-
58
- /**
59
- * 保存 Resume Token
60
- *
61
- * @param {Object} token - Resume Token 对象
62
- * @returns {Promise<void>}
63
- */
64
- async save(token) {
65
- try {
66
- if (this.storage === 'redis' && this.redis) {
67
- await this._saveToRedis(token);
68
- } else {
69
- await this._saveToFile(token);
70
- }
71
- } catch (error) {
72
- this.logger.error('[ResumeTokenStore] 保存 Token 失败', {
73
- storage: this.storage,
74
- error: error.message
75
- });
76
- // 不抛出错误,避免影响同步流程
77
- }
78
- }
79
-
80
- /**
81
- * 从文件加载
82
- *
83
- * @private
84
- * @returns {Promise<Object|null>}
85
- */
86
- async _loadFromFile() {
87
- try {
88
- const data = await fs.readFile(this.path, 'utf8');
89
- const token = JSON.parse(data);
90
-
91
- this.logger.debug('[ResumeTokenStore] 从文件加载 Token', {
92
- path: this.path
93
- });
94
-
95
- return token;
96
- } catch (error) {
97
- if (error.code === 'ENOENT') {
98
- // 文件不存在,返回 null
99
- this.logger.debug('[ResumeTokenStore] Token 文件不存在', {
100
- path: this.path
101
- });
102
- return null;
103
- }
104
- throw error;
105
- }
106
- }
107
-
108
- /**
109
- * 保存到文件
110
- *
111
- * @private
112
- * @param {Object} token - Resume Token
113
- * @returns {Promise<void>}
114
- */
115
- async _saveToFile(token) {
116
- // 确保目录存在
117
- const dir = path.dirname(this.path);
118
- await fs.mkdir(dir, { recursive: true });
119
-
120
- // 写入文件
121
- await fs.writeFile(this.path, JSON.stringify(token, null, 2), 'utf8');
122
-
123
- this.logger.debug('[ResumeTokenStore] Token 已保存到文件', {
124
- path: this.path
125
- });
126
- }
127
-
128
- /**
129
- * 从 Redis 加载
130
- *
131
- * @private
132
- * @returns {Promise<Object|null>}
133
- */
134
- async _loadFromRedis() {
135
- const data = await this.redis.get(this.redisKey);
136
-
137
- if (!data) {
138
- this.logger.debug('[ResumeTokenStore] Redis 中无 Token');
139
- return null;
140
- }
141
-
142
- const token = JSON.parse(data);
143
-
144
- this.logger.debug('[ResumeTokenStore] 从 Redis 加载 Token', {
145
- key: this.redisKey
146
- });
147
-
148
- return token;
149
- }
150
-
151
- /**
152
- * 保存到 Redis
153
- *
154
- * @private
155
- * @param {Object} token - Resume Token
156
- * @returns {Promise<void>}
157
- */
158
- async _saveToRedis(token) {
159
- await this.redis.set(this.redisKey, JSON.stringify(token));
160
-
161
- this.logger.debug('[ResumeTokenStore] Token 已保存到 Redis', {
162
- key: this.redisKey
163
- });
164
- }
165
-
166
- /**
167
- * 清除 Resume Token
168
- *
169
- * @returns {Promise<void>}
170
- */
171
- async clear() {
172
- try {
173
- if (this.storage === 'redis' && this.redis) {
174
- await this.redis.del(this.redisKey);
175
- this.logger.info('[ResumeTokenStore] Redis Token 已清除');
176
- } else {
177
- await fs.unlink(this.path);
178
- this.logger.info('[ResumeTokenStore] 文件 Token 已清除');
179
- }
180
- } catch (error) {
181
- if (error.code !== 'ENOENT') {
182
- this.logger.warn('[ResumeTokenStore] 清除 Token 失败', {
183
- error: error.message
184
- });
185
- }
186
- }
187
- }
188
- }
189
-
190
- module.exports = ResumeTokenStore;
191
-
192
-