From 2ec50f3234fc7146d0478311450988d5364e0207 Mon Sep 17 00:00:00 2001 From: nav Date: Tue, 12 May 2026 10:37:27 +0000 Subject: [PATCH] feat(guild-messaging): add gap-detection metadata for seq backfill responses --- .../src/messaging/messaging.controller.ts | 32 +++++++++++++++++++ docs/TODO-backend-center-guild.md | 4 +-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/Fabric.Backend.Guild/src/messaging/messaging.controller.ts b/Fabric.Backend.Guild/src/messaging/messaging.controller.ts index 7db165a..0e7cf50 100644 --- a/Fabric.Backend.Guild/src/messaging/messaging.controller.ts +++ b/Fabric.Backend.Guild/src/messaging/messaging.controller.ts @@ -132,6 +132,26 @@ export class MessagingController { ? Math.min(requestedLimit, MAX_PAGE_LIMIT) : DEFAULT_PAGE_LIMIT; + if (from > to) { + return { + items: [], + page: { + seqFrom: from, + seqTo: to, + limit: safeLimit, + returned: 0, + hasMore: false, + nextExpectedSeq: from, + highestCommittedSeq: 0, + }, + }; + } + + const channel = await this.channelRepo.findOne({ where: { id: channelId } }); + if (!channel) { + throw new NotFoundException('channel not found'); + } + const qb = this.messageRepo .createQueryBuilder('m') .where('m.channelId = :channelId', { channelId }) @@ -143,6 +163,16 @@ export class MessagingController { const rows = await qb.limit(safeLimit).getMany(); const items = rows.map((m) => this.toView(m)); + let nextExpectedSeq = from; + for (const row of rows) { + if (row.seq > nextExpectedSeq) { + break; + } + if (row.seq === nextExpectedSeq) { + nextExpectedSeq += 1; + } + } + return { items, page: { @@ -151,6 +181,8 @@ export class MessagingController { limit: safeLimit, returned: items.length, hasMore: total > items.length, + nextExpectedSeq, + highestCommittedSeq: channel.lastSeq, }, }; } diff --git a/docs/TODO-backend-center-guild.md b/docs/TODO-backend-center-guild.md index 6214dcf..4fe0b4d 100644 --- a/docs/TODO-backend-center-guild.md +++ b/docs/TODO-backend-center-guild.md @@ -51,8 +51,8 @@ - [x] seq 分配改为 DB 原子方案(避免并发冲突) ### 2.3 一致性与回补 -- [ ] 回补接口:`seq_from/seq_to` -- [ ] 断片检测辅助响应字段(next_expected_seq 等) +- [x] 回补接口:`seq_from/seq_to` +- [x] 断片检测辅助响应字段(next_expected_seq 等) - [ ] 幂等键支持(写接口) ### 2.4 实时通信(MVP 后半)