148 lines
7.2 KiB
Go
148 lines
7.2 KiB
Go
package rpc
|
||
|
||
import (
|
||
"context"
|
||
|
||
"github.com/iamxvbaba/td/tg"
|
||
"github.com/iamxvbaba/td/tgerr"
|
||
|
||
"github.com/iamxvbaba/td/tlprofile"
|
||
"telesrv/internal/compat/tdesktop"
|
||
)
|
||
|
||
// registerPayments 注册 payments.* RPC。telesrv 不实现 Stars/Star Gift 经济:
|
||
// 大部分曾经的 Stars/gift 动作 RPC 已不再注册;仍注册的几个只读状态 RPC
|
||
// (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)
|
||
})
|
||
registerRPC[*tg.PaymentsAssignPlayMarketTransactionRequest](d, tlprofile.SemanticMethodPaymentsAssignPlayMarketTransaction, func(ctx context.Context, req *tg.PaymentsAssignPlayMarketTransactionRequest) (any, error) {
|
||
return r.onPaymentsAssignPlayMarketTransaction(ctx, req)
|
||
})
|
||
registerRPC[*tg.PaymentsGetPremiumGiftCodeOptionsRequest](d, tlprofile.SemanticMethodPaymentsGetPremiumGiftCodeOptions, func(ctx context.Context, req *tg.PaymentsGetPremiumGiftCodeOptionsRequest) (any, error) {
|
||
return []tg.PremiumGiftCodeOption{}, nil
|
||
})
|
||
registerRPC[*tg.PaymentsGetStarsStatusRequest](d, tlprofile.SemanticMethodPaymentsGetStarsStatus, func(ctx context.Context, layerRequest *tg.PaymentsGetStarsStatusRequest) (any, error) {
|
||
return r.onPaymentsGetStarsStatus(ctx, layerRequest)
|
||
})
|
||
registerRPC[*tg.PaymentsGetStarsSubscriptionsRequest](d, tlprofile.SemanticMethodPaymentsGetStarsSubscriptions, func(ctx context.Context, req *tg.PaymentsGetStarsSubscriptionsRequest) (any, error) {
|
||
return r.onPaymentsGetStarsSubscriptions(ctx, req)
|
||
})
|
||
registerRPC[*tg.PaymentsGetStarsTransactionsRequest](d, tlprofile.SemanticMethodPaymentsGetStarsTransactions, func(ctx context.Context, layerRequest *tg.PaymentsGetStarsTransactionsRequest) (any, error) {
|
||
return r.onPaymentsGetStarsTransactions(ctx, layerRequest)
|
||
})
|
||
registerRPC[*tg.PaymentsGetStarsRevenueAdsAccountURLRequest](d, tlprofile.SemanticMethodPaymentsGetStarsRevenueAdsAccountURL, func(ctx context.Context, layerRequest *tg.PaymentsGetStarsRevenueAdsAccountURLRequest) (any, error) {
|
||
peer := layerRequest.
|
||
Peer
|
||
_ = peer
|
||
|
||
userID, _, err := r.currentUserID(ctx)
|
||
if err != nil {
|
||
return nil, internalErr()
|
||
}
|
||
if _, err := r.checkedDomainPeerFromInputPeer(ctx, userID, peer); err != nil {
|
||
return nil, err
|
||
}
|
||
return &tg.PaymentsStarsRevenueAdsAccountURL{URL: r.publicLink("")}, nil
|
||
})
|
||
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) {
|
||
if _, _, err := r.currentUserID(ctx); err != nil {
|
||
return false, internalErr()
|
||
}
|
||
// telesrv deliberately exposes no Google Play products or receipt verifier.
|
||
// DrKLO is steered to the invoice flow by appConfig; if a stale client still
|
||
// reaches this preflight, fail closed instead of authorizing an unverifiable
|
||
// external charge.
|
||
return false, nil
|
||
}
|
||
|
||
func (r *Router) onPaymentsAssignPlayMarketTransaction(ctx context.Context, _ *tg.PaymentsAssignPlayMarketTransactionRequest) (tg.UpdatesClass, error) {
|
||
if _, _, err := r.currentUserID(ctx); err != nil {
|
||
return nil, internalErr()
|
||
}
|
||
return nil, tgerr.New(400, "STORE_PAYMENT_UNAVAILABLE")
|
||
}
|
||
|
||
// onPaymentsGetStarsRevenueStats: telesrv has no Stars/gift economy, so every
|
||
// peer gets the same zero-balance compatibility response (no channel ledger
|
||
// branch left to read from).
|
||
func (r *Router) onPaymentsGetStarsRevenueStats(ctx context.Context, req *tg.PaymentsGetStarsRevenueStatsRequest) (*tg.PaymentsStarsRevenueStats, error) {
|
||
userID, _, err := r.currentUserID(ctx)
|
||
if err != nil {
|
||
return nil, internalErr()
|
||
}
|
||
if req == nil {
|
||
return nil, peerIDInvalidErr()
|
||
}
|
||
if _, err := r.checkedDomainPeerFromInputPeer(ctx, userID, req.Peer); err != nil {
|
||
return nil, err
|
||
}
|
||
return tdesktop.StarsRevenueStats(req.GetTon()), nil
|
||
}
|
||
|
||
// onPaymentsGetStarsStatus 无 Stars 账本,恒返回零余额(响应仍是合法的
|
||
// payments.starsStatus——两端客户端无条件读取 balance 字段)。
|
||
func (r *Router) onPaymentsGetStarsStatus(ctx context.Context, req *tg.PaymentsGetStarsStatusRequest) (*tg.PaymentsStarsStatus, error) {
|
||
if _, _, err := r.currentUserID(ctx); err != nil {
|
||
return nil, internalErr()
|
||
}
|
||
if req != nil && req.GetTon() {
|
||
return emptyStarsStatus(&tg.StarsTonAmount{}), nil
|
||
}
|
||
return emptyStarsStatus(&tg.StarsAmount{}), nil
|
||
}
|
||
|
||
// onPaymentsGetStarsSubscriptions returns a zero balance and no subscriptions
|
||
// — telesrv never creates recurring Stars subscriptions.
|
||
func (r *Router) onPaymentsGetStarsSubscriptions(ctx context.Context, req *tg.PaymentsGetStarsSubscriptionsRequest) (*tg.PaymentsStarsStatus, error) {
|
||
if _, _, err := r.currentUserID(ctx); err != nil {
|
||
return nil, internalErr()
|
||
}
|
||
return emptyStarsStatus(&tg.StarsAmount{}), nil
|
||
}
|
||
|
||
// onPaymentsGetStarsTransactions 无 Stars 账本,恒返回零余额、空流水(不设置
|
||
// next_offset,避免客户端无限翻页)。
|
||
func (r *Router) onPaymentsGetStarsTransactions(ctx context.Context, req *tg.PaymentsGetStarsTransactionsRequest) (*tg.PaymentsStarsStatus, error) {
|
||
if _, _, err := r.currentUserID(ctx); err != nil {
|
||
return nil, internalErr()
|
||
}
|
||
if req != nil && req.GetTon() {
|
||
return emptyStarsStatus(&tg.StarsTonAmount{}), nil
|
||
}
|
||
return emptyStarsStatus(&tg.StarsAmount{}), nil
|
||
}
|
||
|
||
// emptyStarsStatus 构造一个合法的最小 payments.starsStatus(chats/users 非空 vector 但可空)。
|
||
func emptyStarsStatus(balance tg.StarsAmountClass) *tg.PaymentsStarsStatus {
|
||
return &tg.PaymentsStarsStatus{
|
||
Balance: balance,
|
||
Chats: []tg.ChatClass{},
|
||
Users: []tg.UserClass{},
|
||
}
|
||
}
|