owpengram-server/internal/rpc/phone_push.go
2026-07-20 16:03:33 +03:00

92 lines
4.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package rpc
import (
"context"
"github.com/iamxvbaba/td/proto"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap"
"telesrv/internal/domain"
)
// 通话信令推送全部走无 pts 直推pushUserMessage信令有效期秒级离线设备
// 重连后经 getDifference 补收一条早已失效的来电毫无意义甚至有害。唯一带 pts 的
// 产物是结束后的 messageActionPhoneCall 服务消息P2走 outbox 补偿离线设备)。
// phoneCallUpdates 把 viewer 视角的 phoneCall 状态包成可直推的 Updates 容器。
func (r *Router) phoneCallUpdates(ctx context.Context, call domain.PhoneCall, viewerID int64) *tg.Updates {
return r.phoneCallUpdatesWith(ctx, tgPhoneCallForViewer(call, viewerID), call, viewerID)
}
func (r *Router) phoneCallUpdatesWith(ctx context.Context, view tg.PhoneCallClass, call domain.PhoneCall, viewerID int64) *tg.Updates {
return &tg.Updates{
Updates: []tg.UpdateClass{&tg.UpdatePhoneCall{PhoneCall: view}},
Users: r.tgUsersForIDs(ctx, viewerID, []int64{call.AdminID, call.ParticipantID}),
Chats: []tg.ChatClass{},
Date: int(r.clock.Now().Unix()),
Seq: 0,
}
}
// pushPhoneCall 把 call 当前状态按 targetUserID 视角推给其全部在线设备
// ctx 携带的发起设备会被 pushUserMessage 的 except 语义排除)。
func (r *Router) pushPhoneCall(ctx context.Context, targetUserID int64, call domain.PhoneCall, logMessage string) int {
return r.pushUserMessage(ctx, targetUserID, logMessage, r.phoneCallUpdates(ctx, call, targetUserID))
}
// pushPhoneCallStopRinging 向被叫【其它设备】推合成 phoneCallDiscarded 停振铃P0-1 修正)。
// ctx 必须是接听设备的请求上下文。
//
// ⚠ 排除必须按【设备】perm/business auth_key整体做而不是按单个
// (raw auth_key, session)。接听设备可能有多条到本服务器的连接——OwpenGram 客户端
// 把 dc 1..5 都指向同一服务器,故一台真机常有数条连接/会话。若只排除受理 accept 的
// 那一条 session停振铃的 phoneCallDiscarded 会漏到同一台设备的其它连接上,客户端
// 的 update 处理器按 call_id 匹配后当作"通话被挂断"、立即杀掉它刚接起的通话
//(现象:被叫按下接听后立刻 Failed to connect主叫方/被叫单连接侧无此问题——故表现
// 为「A 打 B 正常、B 打 A 一接就断」的方向不对称)。按 business auth_key 排除可覆盖该
// 设备的全部连接。See memory: call-*.
func (r *Router) pushPhoneCallStopRinging(ctx context.Context, call domain.PhoneCall) int {
upd := r.phoneCallUpdatesWith(ctx, tgPhoneCallStopRinging(call), call, call.ParticipantID)
if pusher, ok := r.deps.Sessions.(DeviceExcludingSessionPusher); ok {
if businessAuthKeyID, has := AuthKeyIDFrom(ctx); has {
sent, err := pusher.PushToUserExceptBusinessAuthKey(ctx, call.ParticipantID, businessAuthKeyID, proto.MessageFromServer, upd, r.cfg.OutboundPushTimeout)
if err != nil {
r.log.Debug("phone call stop ringing", zap.Int64("user_id", call.ParticipantID), zap.Int("sent", sent), zap.Error(err))
}
return sent
}
}
// 回退:能力不可用时退回按 session 排除(旧行为)。
return r.pushUserMessage(ctx, call.ParticipantID, "phone call stop ringing", upd)
}
// pushPhoneCallDiscardedBoth 把终态推给双方全部设备(发起设备由 ctx except 排除,
// 其结果从 RPC 响应获得)。
func (r *Router) pushPhoneCallDiscardedBoth(ctx context.Context, call domain.PhoneCall) {
r.pushPhoneCall(ctx, call.AdminID, call, "phone call discarded")
r.pushPhoneCall(ctx, call.ParticipantID, call, "phone call discarded")
}
// pushPhoneSignalingData 把信令字节透传给对端。优先走设备锚点定向推送
// requestCall/acceptCall 受理设备),锚点失效(设备重连换 session则回退
// user 级扇出——非参与设备按 phone_call_id 不匹配静默丢弃TDesktop
// handleSignalingData 行为),扇出无害。
func (r *Router) pushPhoneSignalingData(ctx context.Context, targetUserID int64, device domain.SessionRef, callID int64, data []byte) {
upd := &tg.Updates{
Updates: []tg.UpdateClass{&tg.UpdatePhoneCallSignalingData{
PhoneCallID: callID,
Data: data,
}},
Users: []tg.UserClass{},
Chats: []tg.ChatClass{},
Date: int(r.clock.Now().Unix()),
Seq: 0,
}
if !device.Zero() && r.deps.Sessions != nil {
if err := r.deps.Sessions.PushToSessionForAuthKey(ctx, device.RawAuthKeyID, device.SessionID, proto.MessageFromServer, upd); err == nil {
return
}
}
r.pushUserMessage(ctx, targetUserID, "phone call signaling", upd)
}