diff --git a/internal/rpc/payments.go b/internal/rpc/payments.go index f564b4d5..bd57be06 100644 --- a/internal/rpc/payments.go +++ b/internal/rpc/payments.go @@ -12,9 +12,10 @@ import ( // registerPayments 注册 payments.* RPC。telesrv 不实现 Stars/Star Gift 经济: // 大部分曾经的 Stars/gift 动作 RPC 已不再注册;仍注册的几个只读状态 RPC -// (getStarsStatus/Subscriptions/Transactions/RevenueStats)返回固定空值, -// 因为部分客户端界面会无条件加载它们——错误返回会导致界面卡死或崩溃, -// 空值则让界面正常渲染成"没有 Stars"。 +// (getStarsStatus/Subscriptions/Transactions/RevenueStats、getStarGifts、 +// getSavedStarGifts)返回固定空值,因为部分客户端界面会无条件加载它们—— +// 错误返回会导致界面卡死或崩溃,且 tdesktop 对 500 会疯狂重试,空值则让界面 +// 正常渲染成"没有 Stars / 没有礼物"。 func (r *Router) registerPayments(d *tlprofile.Dispatcher) { registerRPC[*tg.PaymentsCanPurchaseStoreRequest](d, tlprofile.SemanticMethodPaymentsCanPurchaseStore, func(ctx context.Context, req *tg.PaymentsCanPurchaseStoreRequest) (any, error) { return r.onPaymentsCanPurchaseStore(ctx, req) @@ -51,7 +52,22 @@ func (r *Router) registerPayments(d *tlprofile.Dispatcher) { registerRPC[*tg.PaymentsGetStarsRevenueStatsRequest](d, tlprofile.SemanticMethodPaymentsGetStarsRevenueStats, func(ctx context.Context, req *tg.PaymentsGetStarsRevenueStatsRequest) (any, error) { return r.onPaymentsGetStarsRevenueStats(ctx, req) }) - + // Star Gift catalogue / profile gift list: telesrv has no gift economy, but + // tdesktop polls both on startup and retries hard on an error (a 500 turns + // into a request storm). Answer with a valid empty list so the client stops. + registerRPC[*tg.PaymentsGetStarGiftsRequest](d, tlprofile.SemanticMethodPaymentsGetStarGifts, func(ctx context.Context, _ *tg.PaymentsGetStarGiftsRequest) (any, error) { + if _, _, err := r.currentUserID(ctx); err != nil { + return nil, internalErr() + } + return &tg.PaymentsStarGifts{Gifts: []tg.StarGiftClass{}, Chats: []tg.ChatClass{}, Users: []tg.UserClass{}}, nil + }) + registerRPC[*tg.PaymentsGetSavedStarGiftsRequest](d, tlprofile.SemanticMethodPaymentsGetSavedStarGifts, func(ctx context.Context, _ *tg.PaymentsGetSavedStarGiftsRequest) (any, error) { + if _, _, err := r.currentUserID(ctx); err != nil { + return nil, internalErr() + } + // No next_offset: an empty page must be terminal, not an infinite scroll. + return &tg.PaymentsSavedStarGifts{Gifts: []tg.SavedStarGift{}, Chats: []tg.ChatClass{}, Users: []tg.UserClass{}}, nil + }) } func (r *Router) onPaymentsCanPurchaseStore(ctx context.Context, _ *tg.PaymentsCanPurchaseStoreRequest) (bool, error) { diff --git a/internal/rpc/router_dispatch_test.go b/internal/rpc/router_dispatch_test.go index a2fb3a2a..6d56b00c 100644 --- a/internal/rpc/router_dispatch_test.go +++ b/internal/rpc/router_dispatch_test.go @@ -1290,6 +1290,8 @@ func TestTDesktopStartupRPCsEncode(t *testing.T) { {name: "payments.canPurchaseStore", req: &tg.PaymentsCanPurchaseStoreRequest{Purpose: &tg.InputStorePaymentStarsTopup{Stars: 1000, Currency: "USD", Amount: 99}}}, {name: "payments.getStarsStatus", req: &tg.PaymentsGetStarsStatusRequest{Peer: &tg.InputPeerSelf{}}}, {name: "payments.getStarsSubscriptions", req: &tg.PaymentsGetStarsSubscriptionsRequest{Peer: &tg.InputPeerSelf{}}}, + {name: "payments.getStarGifts", req: &tg.PaymentsGetStarGiftsRequest{}}, + {name: "payments.getSavedStarGifts", req: &tg.PaymentsGetSavedStarGiftsRequest{Peer: &tg.InputPeerSelf{}, Limit: 20}}, {name: "updates.getDifference", req: &tg.UpdatesGetDifferenceRequest{}}, {name: "users.getFullUser", req: &tg.UsersGetFullUserRequest{ID: &tg.InputUserSelf{}}}, {name: "users.getRequirementsToContact", req: &tg.UsersGetRequirementsToContactRequest{ID: []tg.InputUserClass{&tg.InputUserSelf{}}}},