From e792baa316170aeb4dd42d91e32e37191517696d Mon Sep 17 00:00:00 2001 From: AskaEth Date: Mon, 5 Oct 2026 11:29:54 +0800 Subject: [PATCH] =?UTF-8?q?docs(channels):=20=E4=BF=AE=E6=AD=A3=206=20?= =?UTF-8?q?=E5=A4=84=E6=8C=87=E5=90=91=E5=B7=B2=E4=B8=8D=E5=AD=98=E5=9C=A8?= =?UTF-8?q?=20design/08=20=E8=8A=82=E5=8F=B7=E7=9A=84=E6=B3=A8=E9=87=8A?= =?UTF-8?q?=EF=BC=88=E5=8F=AA=E6=94=B9=E6=B3=A8=E9=87=8A=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugins/channels/weixin_ilink/adapter.go | 4 ++-- plugins/channels/weixin_ilink/fake_test.go | 2 +- plugins/channels/weixin_ilink/media_key_test.go | 5 +++-- plugins/channels/weixin_ilink/poll.go | 3 ++- plugins/channels/weixin_ilink/send.go | 8 ++++---- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/plugins/channels/weixin_ilink/adapter.go b/plugins/channels/weixin_ilink/adapter.go index 1960e7e..331bf65 100644 --- a/plugins/channels/weixin_ilink/adapter.go +++ b/plugins/channels/weixin_ilink/adapter.go @@ -371,8 +371,8 @@ func (a *Adapter) setCursor(c string) { a.mu.Unlock() } -// recordInbound 刷新按对端的 context_token 与最后消息时间(design/08 §8:每条入站 -// 消息都刷新 token,使主动推送在窗口内有可用 token)。 +// recordInbound 刷新按对端的 context_token 与最后消息时间(见 design/08 §4 的 +// weixin-ilink 条目:每条入站消息都刷新 token,使主动推送在窗口内有可用 token)。 func (a *Adapter) recordInbound(token string, m adapter.UnifiedMessage) { peer := m.SenderID if m.IsGroup() { diff --git a/plugins/channels/weixin_ilink/fake_test.go b/plugins/channels/weixin_ilink/fake_test.go index e7cff81..37d63fb 100644 --- a/plugins/channels/weixin_ilink/fake_test.go +++ b/plugins/channels/weixin_ilink/fake_test.go @@ -95,7 +95,7 @@ func jsonBody(v any) []byte { func inlineJSON(v any) json.RawMessage { return json.RawMessage(jsonBody(v)) } // encodeToken 构造一个 base64 bot_token,其末尾字节是已知密钥,使 deriveInboundKey -// 得到确定性的 AES 密钥(design/08 §3.3)。 +// 得到确定性的 AES 密钥(见 design/08 §4 的 weixin-ilink 条目;旧 §3.3 口径已作废)。 func encodeToken(key []byte) string { return base64.StdEncoding.EncodeToString(append([]byte("prefix!"), key...)) } diff --git a/plugins/channels/weixin_ilink/media_key_test.go b/plugins/channels/weixin_ilink/media_key_test.go index 9b6060f..f059b9b 100644 --- a/plugins/channels/weixin_ilink/media_key_test.go +++ b/plugins/channels/weixin_ilink/media_key_test.go @@ -7,8 +7,9 @@ package weixin_ilink // `encrypt_query_param`(或 `full_url`)给地址、`aes_key` 给密钥(图片优先 // `image_item.aeskey`);文件名在 `file_name`,体积在**字符串** `len`。 // -// 旧实现只认平铺的 `file_item.url`,且把**整个 bot_token** 当 base64 去解(自标 ⚠️ 的 -// design/08 §3.3 口径)——真实 token 形如 `<12 位>@im.bot:<38 位十六进制>`,在第 12 个 +// 旧实现只认平铺的 `file_item.url`,且把**整个 bot_token** 当 base64 去解(旧口径原记在 +// 已不存在的 design/08 §3.3,2026-10-05 已在 §4 的 weixin-ilink 条目更正为「按条密钥」) +// ——真实 token 形如 `<12 位>@im.bot:<38 位十六进制>`,在第 12 个 // 字符 `@` 处必失败。下面的夹具因此刻意用「同形但不是真凭据」的 token,让「附件能不能 // 读出来」只取决于按条 aes_key 是否被用上。 diff --git a/plugins/channels/weixin_ilink/poll.go b/plugins/channels/weixin_ilink/poll.go index 1150faa..846bab3 100644 --- a/plugins/channels/weixin_ilink/poll.go +++ b/plugins/channels/weixin_ilink/poll.go @@ -175,7 +175,8 @@ func (a *Adapter) wait(ctx context.Context, d time.Duration) bool { } } -// retryDelay 在连续失败足够多之后,从快速重试切换到慢速退避(design/08 §5.4)。 +// retryDelay 在连续失败足够多之后,从快速重试切换到慢速退避(见 design/08 §4 的 +// weixin-ilink 条目:长轮询 + 游标)。 func (a *Adapter) retryDelay(failures int) time.Duration { if failures <= retryFastCount { return retryFastDelay diff --git a/plugins/channels/weixin_ilink/send.go b/plugins/channels/weixin_ilink/send.go index 74d9c53..eb41641 100644 --- a/plugins/channels/weixin_ilink/send.go +++ b/plugins/channels/weixin_ilink/send.go @@ -31,7 +31,7 @@ type sendResult struct { // SendMessage 向渠道投递一条回复。每条消息都发给从该消息(或 resp.ReplyTo) // 解析出的对端,并使用该对端已存的 context_token,以便平台把回复关联到正确的 -// 会话(design/08 §8)。 +// 会话(见 design/08 §4 的 weixin-ilink 条目:`context_token`)。 func (a *Adapter) SendMessage(ctx context.Context, resp adapter.UnifiedResponse) error { if err := a.sendGuard(); err != nil { return err @@ -49,9 +49,9 @@ func (a *Adapter) SendMessage(ctx context.Context, resp adapter.UnifiedResponse) } // SendProactive 推送一条并非由近期入站消息触发的消息。微信 iLink 只允许在用户 -// 最后一条消息之后的 24 小时窗口内这么做(design/08 §3-4):用户沉默更久、或从未 -// 发过消息时,推送以 ErrProactiveWindow 被拒,而 Capabilities.Proactive 仅为 true, -// 好让调用方知道该能力存在。 +// 最后一条消息之后的 24 小时窗口内这么做(见 design/08 §3 的主动推送表与 §4 的 +// weixin-ilink 条目):用户沉默更久、或从未发过消息时,推送以 ErrProactiveWindow +// 被拒,而 Capabilities.Proactive 仅为 true,好让调用方知道该能力存在。 func (a *Adapter) SendProactive(ctx context.Context, msg adapter.UnifiedMessage) error { if err := a.sendGuard(); err != nil { return err