chore: refresh gramsrv public release
This commit is contained in:
parent
75cebe8dbf
commit
70b6820474
1274 changed files with 378751 additions and 59919 deletions
203
internal/rpc/messages_reactions_privacy.go
Normal file
203
internal/rpc/messages_reactions_privacy.go
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
package rpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gotd/td/tg"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
||||
func (r *Router) onMessagesSetDefaultReaction(ctx context.Context, reaction tg.ReactionClass) (bool, error) {
|
||||
userID, _, err := r.currentUserID(ctx)
|
||||
if err != nil {
|
||||
return false, internalErr()
|
||||
}
|
||||
parsed, err := domainMessageReactionFromTL(reaction)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if svc, ok := r.deps.Account.(accountDefaultReactionService); ok {
|
||||
if _, err := svc.SetDefaultReaction(ctx, userID, parsed); err != nil {
|
||||
return false, internalErr()
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (r *Router) onMessagesGetPaidReactionPrivacy(ctx context.Context) (tg.UpdatesClass, error) {
|
||||
userID, _, err := r.currentUserID(ctx)
|
||||
if err != nil {
|
||||
return nil, internalErr()
|
||||
}
|
||||
settings := domain.DefaultAccountReactionSettings()
|
||||
if svc, ok := r.deps.Account.(accountPaidReactionPrivacyService); ok {
|
||||
next, err := svc.GetReactionSettings(ctx, userID)
|
||||
if err != nil {
|
||||
return nil, internalErr()
|
||||
}
|
||||
settings = next
|
||||
}
|
||||
return &tg.Updates{
|
||||
Updates: []tg.UpdateClass{&tg.UpdatePaidReactionPrivacy{
|
||||
Private: r.tgPaidReactionPrivacy(ctx, userID, settings.PaidPrivacy),
|
||||
}},
|
||||
Users: []tg.UserClass{},
|
||||
Chats: []tg.ChatClass{},
|
||||
Date: int(r.clock.Now().Unix()),
|
||||
Seq: 0,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *Router) onMessagesTogglePaidReactionPrivacy(ctx context.Context, req *tg.MessagesTogglePaidReactionPrivacyRequest) (bool, error) {
|
||||
if req.MsgID <= 0 || req.MsgID > domain.MaxMessageBoxID {
|
||||
return false, messageIDInvalidErr()
|
||||
}
|
||||
userID, _, err := r.currentUserID(ctx)
|
||||
if err != nil {
|
||||
return false, internalErr()
|
||||
}
|
||||
if _, err := r.checkedDomainPeerFromInputPeer(ctx, userID, req.Peer); err != nil {
|
||||
return false, err
|
||||
}
|
||||
privacy, err := r.domainPaidReactionPrivacy(ctx, userID, req.Private)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if svc, ok := r.deps.Account.(accountPaidReactionPrivacyService); ok {
|
||||
next, err := svc.SetPaidReactionPrivacy(ctx, userID, privacy)
|
||||
if err != nil {
|
||||
return false, internalErr()
|
||||
}
|
||||
privacy = next.PaidPrivacy
|
||||
}
|
||||
r.pushUserUpdates(ctx, userID, &tg.Updates{
|
||||
Updates: []tg.UpdateClass{&tg.UpdatePaidReactionPrivacy{Private: r.tgPaidReactionPrivacy(ctx, userID, privacy)}},
|
||||
Users: []tg.UserClass{},
|
||||
Chats: []tg.ChatClass{},
|
||||
Date: int(r.clock.Now().Unix()),
|
||||
Seq: 0,
|
||||
})
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// onMessagesSendPaidReaction 为一条广播频道消息发送付费 reaction:从 Stars 账本 Debit
|
||||
// req.Count 星,累计到消息上,返回带 updateMessageReactions(含 ReactionPaid 总星数 +
|
||||
// top reactors)与 updateStarsBalance 的 Updates。崩溃约束:必须返回合法 Updates——
|
||||
// DrKLO StarsController 对响应无 instanceof 强转 (TLRPC.Updates)。
|
||||
func (r *Router) onMessagesSendPaidReaction(ctx context.Context, req *tg.MessagesSendPaidReactionRequest) (tg.UpdatesClass, error) {
|
||||
if req.MsgID <= 0 || req.MsgID > domain.MaxMessageBoxID {
|
||||
return nil, messageIDInvalidErr()
|
||||
}
|
||||
if req.Count <= 0 || req.Count > domain.MaxPaidReactionStarsPerRequest {
|
||||
return nil, starsAmountInvalidErr()
|
||||
}
|
||||
userID, _, err := r.currentUserID(ctx)
|
||||
if err != nil {
|
||||
return nil, internalErr()
|
||||
}
|
||||
peer, err := r.checkedDomainPeerFromInputPeer(ctx, userID, req.Peer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 付费 reaction 仅用于(广播)频道帖子。
|
||||
if peer.Type != domain.PeerTypeChannel {
|
||||
return nil, peerIDInvalidErr()
|
||||
}
|
||||
anonymous, err := r.resolvePaidReactionAnonymous(ctx, userID, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.deps.Stars == nil {
|
||||
return nil, balanceTooLowErr()
|
||||
}
|
||||
paidSvc, ok := r.deps.Channels.(channelPaidReactionService)
|
||||
if !ok {
|
||||
return nil, notImplementedErr()
|
||||
}
|
||||
channelPeer := domain.Peer{Type: domain.PeerTypeChannel, ID: peer.ID}
|
||||
// 1. 先从账本 Debit(余额不足→真实 BALANCE_TOO_LOW)。
|
||||
balance, err := r.deps.Stars.Debit(ctx, userID, int64(req.Count), domain.StarsReasonReaction, channelPeer, "Paid reaction", "")
|
||||
if err != nil {
|
||||
return nil, starsErr(err)
|
||||
}
|
||||
// 2. 累计付费 reaction;失败则补偿退款。
|
||||
res, err := paidSvc.SendPaidReaction(ctx, userID, domain.SendChannelPaidReactionRequest{
|
||||
UserID: userID,
|
||||
ChannelID: peer.ID,
|
||||
MessageID: req.MsgID,
|
||||
Stars: int64(req.Count),
|
||||
Anonymous: anonymous,
|
||||
Date: int(r.clock.Now().Unix()),
|
||||
})
|
||||
if err != nil {
|
||||
if _, refundErr := r.deps.Stars.Credit(ctx, userID, int64(req.Count), domain.StarsReasonReaction, channelPeer, "Paid reaction refund", ""); refundErr != nil {
|
||||
r.log.Error("paid reaction refund failed after record error",
|
||||
zap.Int64("user_id", userID), zap.Int64("channel_id", peer.ID), zap.Int("msg_id", req.MsgID), zap.Error(refundErr))
|
||||
}
|
||||
return nil, channelReactionErr(err)
|
||||
}
|
||||
// 3. 构建并扇出 updateMessageReactions;请求者额外带 updateStarsBalance。
|
||||
ids := []int{res.Message.ID}
|
||||
build := func(viewerUserID int64) *tg.Updates {
|
||||
updates := r.channelPaidReactionUpdates(ctx, userID, viewerUserID, res, ids)
|
||||
if updates != nil && viewerUserID == userID {
|
||||
updates.Updates = append(updates.Updates, &tg.UpdateStarsBalance{Balance: &tg.StarsAmount{Amount: balance.Balance}})
|
||||
}
|
||||
return updates
|
||||
}
|
||||
recipients := append([]int64{res.Message.SenderUserID}, res.Recipients...)
|
||||
r.pushChannelViewerUpdates(ctx, userID, res.Channel.ID, recipients, build)
|
||||
return build(userID), nil
|
||||
}
|
||||
|
||||
// resolvePaidReactionAnonymous 计算本次付费 reaction 是否匿名:显式 private 优先,
|
||||
// 缺省回退用户保存的默认付费 reaction 隐私。
|
||||
func (r *Router) resolvePaidReactionAnonymous(ctx context.Context, userID int64, req *tg.MessagesSendPaidReactionRequest) (bool, error) {
|
||||
if private, ok := req.GetPrivate(); ok {
|
||||
privacy, err := r.domainPaidReactionPrivacy(ctx, userID, private)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return privacy.Kind == domain.PaidReactionPrivacyAnonymous, nil
|
||||
}
|
||||
if svc, ok := r.deps.Account.(accountPaidReactionPrivacyService); ok {
|
||||
if settings, err := svc.GetReactionSettings(ctx, userID); err == nil {
|
||||
return settings.PaidPrivacy.Kind == domain.PaidReactionPrivacyAnonymous, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (r *Router) domainPaidReactionPrivacy(ctx context.Context, userID int64, in tg.PaidReactionPrivacyClass) (domain.PaidReactionPrivacy, error) {
|
||||
switch typed := in.(type) {
|
||||
case nil, *tg.PaidReactionPrivacyDefault:
|
||||
return domain.PaidReactionPrivacy{Kind: domain.PaidReactionPrivacyDefault}, nil
|
||||
case *tg.PaidReactionPrivacyAnonymous:
|
||||
return domain.PaidReactionPrivacy{Kind: domain.PaidReactionPrivacyAnonymous}, nil
|
||||
case *tg.PaidReactionPrivacyPeer:
|
||||
peer, err := r.checkedDomainPeerFromInputPeer(ctx, userID, typed.Peer)
|
||||
if err != nil {
|
||||
return domain.PaidReactionPrivacy{}, err
|
||||
}
|
||||
return domain.PaidReactionPrivacy{Kind: domain.PaidReactionPrivacyPeer, Peer: &peer}, nil
|
||||
default:
|
||||
return domain.PaidReactionPrivacy{}, inputConstructorInvalidErr()
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Router) tgPaidReactionPrivacy(ctx context.Context, userID int64, in domain.PaidReactionPrivacy) tg.PaidReactionPrivacyClass {
|
||||
switch in.Kind {
|
||||
case domain.PaidReactionPrivacyAnonymous:
|
||||
return &tg.PaidReactionPrivacyAnonymous{}
|
||||
case domain.PaidReactionPrivacyPeer:
|
||||
if in.Peer == nil {
|
||||
return &tg.PaidReactionPrivacyDefault{}
|
||||
}
|
||||
if peer := r.inputPeerForDomainPeer(ctx, userID, *in.Peer); peer != nil {
|
||||
return &tg.PaidReactionPrivacyPeer{Peer: peer}
|
||||
}
|
||||
}
|
||||
return &tg.PaidReactionPrivacyDefault{}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue