koishi-plugin-codex-reset 0.1.6 → 0.1.7

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.
package/README.md CHANGED
@@ -30,6 +30,8 @@
30
30
 
31
31
  从 0.1.6 起,需要启用 Koishi 数据库服务(例如 SQLite、MySQL 或 PostgreSQL)。完整 API 快照、ETag、最近同步时间和下次允许请求的时间保存在 `codex_reset_cache` 表中,相同 API 地址共用一份记录。所有查询命令只读数据库,不直接请求上游;首次同步尚未成功时会提示稍后再试。重启、重载插件后仍可查询已保存的数据,并继续遵守冷却时间。同步失败时保留上次成功的数据,可能暂时不是最新状态。
32
32
 
33
+ 插件启动时立即检查并尝试同步,无需先等待 11 分钟;如果数据库中仍有未结束的冷却时间,则等待剩余时间后同步。从 0.1.7 起,首次同步期间的查询会等待正在进行的那次请求,不额外发请求。尚无快照且处于冷却时,命令会显示剩余等待秒数;启动日志也会说明当前数据和下次同步时间。同步按已保存的截止时间调度,重启不会重新等满一个轮询周期。
34
+
33
35
  后台默认每 660 秒同步一次;旧配置小于 660 秒时,实际请求也不会快于 660 秒。请求前先保存冷却时间,收到 HTTP 429 或 503 时遵循 `Retry-After`(也支持响应正文的 `retryAfter` 秒数),冷却期间不会因重启或手动查询再次请求。数据库写入失败时不会继续发起新的上游请求。
34
36
 
35
37
  图片生成最多同时进行 2 项,新的图片任务至少间隔 3 秒;历史图片超过 120 条事件时会提示缩小查询范围。图片中的长篇来源文字会截短。API 响应上限为 4 MiB。
package/lib/index.js CHANGED
@@ -248,13 +248,32 @@ class CodexResetMonitor {
248
248
  // Commands only read the database. A missing snapshot must not turn every
249
249
  // user command into another upstream request during a rate-limit window.
250
250
  try {
251
- return (await this.snapshots.read()).snapshot;
251
+ let cache = await this.snapshots.read();
252
+ if (!cache.snapshot && this.pollPromise) {
253
+ // Startup sync may still be receiving its first response. Wait for the
254
+ // existing poll instead of replying before it can populate the table.
255
+ await this.pollPromise;
256
+ cache = await this.snapshots.read();
257
+ }
258
+ return cache.snapshot;
252
259
  }
253
260
  catch (error) {
254
261
  this.ctx.logger('codex-reset').warn(`读取重置数据失败:${error instanceof Error ? error.message : String(error)}`);
255
262
  return null;
256
263
  }
257
264
  }
265
+ async unavailableMessage() {
266
+ try {
267
+ const cache = await this.snapshots.read();
268
+ const seconds = Math.ceil((cache.nextFetchAt - Date.now()) / 1000);
269
+ if (seconds > 0)
270
+ return `暂时无法获取 Codex 重置事件数据:尚无可用缓存,约 ${seconds} 秒后自动重试同步。`;
271
+ }
272
+ catch {
273
+ // ensureSnapshot already records database read failures.
274
+ }
275
+ return '暂时无法获取 Codex 重置事件数据:首次同步尚未完成,请稍后再试。';
276
+ }
258
277
  async poll() {
259
278
  if (this.disposed)
260
279
  return;
@@ -269,10 +288,31 @@ class CodexResetMonitor {
269
288
  }
270
289
  }
271
290
  async start() {
291
+ this.ctx.logger('codex-reset').info('启动重置事件同步检查。');
272
292
  await this.poll();
273
- if (!this.disposed) {
274
- this.ctx.setInterval(() => this.poll(), Math.max(cache_1.MIN_POLL_INTERVAL_MS, this.config.pollInterval * 1000));
293
+ await this.scheduleNextPoll();
294
+ }
295
+ async scheduleNextPoll() {
296
+ if (this.disposed)
297
+ return;
298
+ let delay = Math.max(cache_1.MIN_POLL_INTERVAL_MS, this.config.pollInterval * 1000);
299
+ try {
300
+ const cache = await this.snapshots.read();
301
+ if (cache.nextFetchAt > Date.now())
302
+ delay = cache.nextFetchAt - Date.now();
303
+ this.ctx.logger('codex-reset').info(cache.snapshot
304
+ ? `重置数据已就绪(${cache.snapshot.events.length} 条事件),约 ${Math.ceil(delay / 1000)} 秒后同步。`
305
+ : `尚无可用重置数据,约 ${Math.ceil(delay / 1000)} 秒后自动重试同步。`);
306
+ }
307
+ catch (error) {
308
+ this.ctx.logger('codex-reset').warn(`读取同步计划失败:${error instanceof Error ? error.message : String(error)}`);
275
309
  }
310
+ if (this.disposed)
311
+ return;
312
+ this.ctx.setTimeout(async () => {
313
+ await this.poll();
314
+ await this.scheduleNextPoll();
315
+ }, Math.max(1000, Math.min(delay, 2_147_483_647)));
276
316
  }
277
317
  dispose() {
278
318
  this.disposed = true;
@@ -447,7 +487,7 @@ class CodexResetMonitor {
447
487
  try {
448
488
  const headers = {
449
489
  Accept: 'application/json',
450
- 'User-Agent': 'koishi-plugin-codex-reset/0.1.6',
490
+ 'User-Agent': 'koishi-plugin-codex-reset/0.1.7',
451
491
  };
452
492
  if (cache.etag && cache.snapshot)
453
493
  headers['If-None-Match'] = cache.etag;
@@ -531,7 +571,7 @@ function apply(ctx, config) {
531
571
  .action(async () => {
532
572
  const snapshot = await monitor.ensureSnapshot();
533
573
  if (!snapshot)
534
- return '暂时无法获取 Codex 重置事件数据,请稍后再试。';
574
+ return monitor.unavailableMessage();
535
575
  const summary = (0, stats_1.analyzeProbability)(snapshot);
536
576
  if (!monitor.hasPuppeteer)
537
577
  return (0, stats_1.formatProbability)(summary);
@@ -553,7 +593,7 @@ function apply(ctx, config) {
553
593
  .action(async () => {
554
594
  const snapshot = await monitor.ensureSnapshot();
555
595
  if (!snapshot)
556
- return '暂时无法获取 Codex 重置事件数据,请稍后再试。';
596
+ return monitor.unavailableMessage();
557
597
  const now = new Date();
558
598
  const latest = (0, stats_1.findLatestConfirmedReset)(snapshot, now);
559
599
  if (!latest)
@@ -581,7 +621,7 @@ function apply(ctx, config) {
581
621
  try {
582
622
  const image = await monitor.createCalendarImage();
583
623
  if (!image)
584
- return '暂时无法生成日历图片,请稍后再试。';
624
+ return monitor.unavailableMessage();
585
625
  return koishi_1.h.image(image, 'image/png');
586
626
  }
587
627
  catch (error) {
@@ -600,7 +640,7 @@ function apply(ctx, config) {
600
640
  try {
601
641
  const snapshot = await monitor.ensureSnapshot();
602
642
  if (!snapshot)
603
- return '暂时无法获取 Codex 重置事件数据,请稍后再试。';
643
+ return monitor.unavailableMessage();
604
644
  const now = new Date();
605
645
  const historyRange = argv.options?.all
606
646
  ? 'all'
@@ -610,7 +650,7 @@ function apply(ctx, config) {
610
650
  return `历史事件超过 ${MAX_HISTORY_EVENTS} 条,请缩小查询的月份范围。`;
611
651
  const image = await monitor.createHistoryImage(events, now);
612
652
  if (!image)
613
- return '暂时无法生成历史时间线图片,请稍后再试。';
653
+ return monitor.unavailableMessage();
614
654
  return koishi_1.h.image(image, 'image/png');
615
655
  }
616
656
  catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "koishi-plugin-codex-reset",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "Monitor AIHOT Codex reset events and notify Koishi channels.",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",