fix: sync web page preview pending deadline
This commit is contained in:
parent
76e7efd6cc
commit
10de462191
4 changed files with 53 additions and 4 deletions
|
|
@ -380,7 +380,7 @@ func (r *Router) webPagePreviewMedia(ctx context.Context, message string, entiti
|
||||||
|
|
||||||
// resolveWebPageForRequest 为交互式读 RPC 解析链接预览:先查缓存(LookupWebPage,命中即返回,
|
// resolveWebPageForRequest 为交互式读 RPC 解析链接预览:先查缓存(LookupWebPage,命中即返回,
|
||||||
// 不抓取不阻塞);未命中才同步抓取,但用受限短预算(webpageRequestResolveBudget)而非异步解析
|
// 不抓取不阻塞);未命中才同步抓取,但用受限短预算(webpageRequestResolveBudget)而非异步解析
|
||||||
// 的 20s,避免慢/挂上游把 RPC worker 钉死。命中(含负缓存的 empty)返回 ok=true,调用方据 state
|
// 的 30s,避免慢/挂上游把 RPC worker 钉死。命中(含负缓存的 empty)返回 ok=true,调用方据 state
|
||||||
// 决定;抓取失败返回 false。未启用返回 false。
|
// 决定;抓取失败返回 false。未启用返回 false。
|
||||||
func (r *Router) resolveWebPageForRequest(ctx context.Context, url string) (domain.MessageWebPage, bool) {
|
func (r *Router) resolveWebPageForRequest(ctx context.Context, url string) (domain.MessageWebPage, bool) {
|
||||||
if page, ok := r.resolveAIComposeStyleWebPage(ctx, url); ok {
|
if page, ok := r.resolveAIComposeStyleWebPage(ctx, url); ok {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package rpc
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/iamxvbaba/td/tg"
|
"github.com/iamxvbaba/td/tg"
|
||||||
|
|
||||||
|
|
@ -27,6 +28,8 @@ func TestSendMessageAttachesWebPagePending(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
r, owner, friend := newMediaTestRouter(t)
|
r, owner, friend := newMediaTestRouter(t)
|
||||||
r.deps.Files.(*fakeFiles).webPagePreviewOn = true
|
r.deps.Files.(*fakeFiles).webPagePreviewOn = true
|
||||||
|
now := time.Date(2030, time.January, 2, 3, 4, 5, 0, time.UTC)
|
||||||
|
r.clock = fixedClock{now: now}
|
||||||
|
|
||||||
updates, err := r.onMessagesSendMessage(WithUserID(ctx, owner.ID), &tg.MessagesSendMessageRequest{
|
updates, err := r.onMessagesSendMessage(WithUserID(ctx, owner.ID), &tg.MessagesSendMessageRequest{
|
||||||
Peer: &tg.InputPeerUser{UserID: friend.ID, AccessHash: friend.AccessHash},
|
Peer: &tg.InputPeerUser{UserID: friend.ID, AccessHash: friend.AccessHash},
|
||||||
|
|
@ -55,11 +58,52 @@ func TestSendMessageAttachesWebPagePending(t *testing.T) {
|
||||||
if url, _ := pending.GetURL(); url != wpTestURL {
|
if url, _ := pending.GetURL(); url != wpTestURL {
|
||||||
t.Errorf("pending url = %q, want %q", url, wpTestURL)
|
t.Errorf("pending url = %q, want %q", url, wpTestURL)
|
||||||
}
|
}
|
||||||
|
wantDeadline := int(now.Add(webPagePendingLifetime).Unix())
|
||||||
|
if pending.Date != wantDeadline {
|
||||||
|
t.Errorf("pending date = %d, want retry deadline %d", pending.Date, wantDeadline)
|
||||||
|
}
|
||||||
|
if time.Unix(int64(pending.Date), 0).Sub(now) <= webPageResolveTimeout {
|
||||||
|
t.Errorf("pending deadline must outlive resolver timeout: deadline=%s timeout=%s", time.Unix(int64(pending.Date), 0), webPageResolveTimeout)
|
||||||
|
}
|
||||||
if !msg.InvertMedia {
|
if !msg.InvertMedia {
|
||||||
t.Errorf("invert_media not projected onto message")
|
t.Errorf("invert_media not projected onto message")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestSendChannelMessageUsesSameFutureWebPageDeadline 锁定频道发送也经过同一 pending
|
||||||
|
// 截止时间构造路径,避免只修私聊 echo 而频道仍被客户端立即判定过期。
|
||||||
|
func TestSendChannelMessageUsesSameFutureWebPageDeadline(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
r, owner, channel := newRichChannelTestRouter(t)
|
||||||
|
r.deps.Files.(*fakeFiles).webPagePreviewOn = true
|
||||||
|
// 本测试只验证发送投影,不启动异步解析 goroutine。
|
||||||
|
r.webPageResolveSem = nil
|
||||||
|
now := time.Date(2030, time.February, 3, 4, 5, 6, 0, time.UTC)
|
||||||
|
r.clock = fixedClock{now: now}
|
||||||
|
|
||||||
|
updates, err := r.onMessagesSendMessage(WithUserID(ctx, owner.ID), &tg.MessagesSendMessageRequest{
|
||||||
|
Peer: &tg.InputPeerChannel{ChannelID: channel.ID, AccessHash: channel.AccessHash},
|
||||||
|
Message: wpTestMessage,
|
||||||
|
Entities: wpURLEntities(),
|
||||||
|
RandomID: 5106,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("send channel message: %v", err)
|
||||||
|
}
|
||||||
|
msg := newMessageFromUpdates(t, updates)
|
||||||
|
wrap, ok := msg.Media.(*tg.MessageMediaWebPage)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("channel media = %T, want *tg.MessageMediaWebPage", msg.Media)
|
||||||
|
}
|
||||||
|
pending, ok := wrap.Webpage.(*tg.WebPagePending)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("channel webpage = %T, want *tg.WebPagePending", wrap.Webpage)
|
||||||
|
}
|
||||||
|
if want := int(now.Add(webPagePendingLifetime).Unix()); pending.Date != want {
|
||||||
|
t.Errorf("channel pending date = %d, want retry deadline %d", pending.Date, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestSendMessageAttachesCachedDoneCard 验证:URL 已缓存解析时,发送 echo 直接带 done 卡片
|
// TestSendMessageAttachesCachedDoneCard 验证:URL 已缓存解析时,发送 echo 直接带 done 卡片
|
||||||
// (非 pending)——官方行为,TDesktop 据此立即渲染、不依赖异步换卡。
|
// (非 pending)——官方行为,TDesktop 据此立即渲染、不依赖异步换卡。
|
||||||
func TestSendMessageAttachesCachedDoneCard(t *testing.T) {
|
func TestSendMessageAttachesCachedDoneCard(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,10 @@ import (
|
||||||
const (
|
const (
|
||||||
webPageResolveConcurrency = 16
|
webPageResolveConcurrency = 16
|
||||||
webPageResolveTimeout = 30 * time.Second
|
webPageResolveTimeout = 30 * time.Second
|
||||||
|
// webPagePendingLifetime 是客户端在重新拉取 pending 消息前等待的窗口。
|
||||||
|
// TDesktop 与 DrKLO 都把 webPagePending.date 解释为绝对截止时间,而不是处理开始时间;
|
||||||
|
// 该窗口必须严格大于 resolver 的最大执行时间,避免正常的慢解析被客户端提前标记为失败。
|
||||||
|
webPagePendingLifetime = 2 * time.Minute
|
||||||
)
|
)
|
||||||
|
|
||||||
type webPageResolveJob struct {
|
type webPageResolveJob struct {
|
||||||
|
|
|
||||||
|
|
@ -135,9 +135,10 @@ func (r *Router) webPagePendingOrCachedMedia(ctx context.Context, rawURL string,
|
||||||
State: domain.MessageWebPageStatePending,
|
State: domain.MessageWebPageStatePending,
|
||||||
ID: domain.WebPageURLHash(normalized),
|
ID: domain.WebPageURLHash(normalized),
|
||||||
URL: normalized,
|
URL: normalized,
|
||||||
// Date=「processing started」时刻:留 0(=1970)会被严格客户端判为 pending 早已
|
// date 是客户端重新拉取 pending 消息的绝对截止时间。TDesktop/DrKLO 在
|
||||||
// 过期 → 直接显示纯文本,须填发送时刻。
|
// date<=now 时立即重取;若 resolver 此时仍运行,TDesktop 会把占位记成 sticky
|
||||||
Date: int(r.clock.Now().Unix()),
|
// failed,后到的 done update 也不会重新显示卡片。
|
||||||
|
Date: int(r.clock.Now().Add(webPagePendingLifetime).Unix()),
|
||||||
ForceLargeMedia: forceLarge,
|
ForceLargeMedia: forceLarge,
|
||||||
ForceSmallMedia: forceSmall,
|
ForceSmallMedia: forceSmall,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue