112 lines
4.3 KiB
Go
112 lines
4.3 KiB
Go
package rpc
|
||
|
||
import (
|
||
"context"
|
||
|
||
"github.com/iamxvbaba/td/tg"
|
||
"go.uber.org/zap"
|
||
|
||
"telesrv/internal/domain"
|
||
)
|
||
|
||
// Scheduled video chat(定时通话)RPC。客户端流程(TDesktop calls_group_call.cpp):
|
||
// createGroupCall(schedule_date) → State::Waiting 倒计时(不 join)→ 管理员
|
||
// startScheduledGroupCall 清 schedule_date → updateGroupCall(无 schedule_date)→
|
||
// 客户端 setScheduledDate(0) 触发 initialJoin 正式入会。开播提醒是 per-viewer 的
|
||
// schedule_start_subscribed flag(toggleGroupCallStartSubscription)。
|
||
|
||
// applyScheduleSubscription 为单个 viewer 回填 ScheduleStartSubscribed 投影字段。
|
||
func (r *Router) applyScheduleSubscription(ctx context.Context, call domain.GroupCall, viewerUserID int64) domain.GroupCall {
|
||
if call.ScheduleDate == 0 || viewerUserID == 0 {
|
||
return call
|
||
}
|
||
subs, err := r.deps.GroupCalls.ScheduleSubscriberIDs(ctx, call.ID)
|
||
if err != nil {
|
||
return call
|
||
}
|
||
for _, id := range subs {
|
||
if id == viewerUserID {
|
||
call.ScheduleStartSubscribed = true
|
||
break
|
||
}
|
||
}
|
||
return call
|
||
}
|
||
|
||
func (r *Router) onPhoneStartScheduledGroupCall(ctx context.Context, in tg.InputGroupCallClass) (tg.UpdatesClass, error) {
|
||
scope, err := r.groupCallScopeFrom(ctx, in)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if scope.call.Conference() || scope.channel.ID == 0 {
|
||
return nil, groupCallInvalidErr()
|
||
}
|
||
if !scope.canManage() {
|
||
return nil, tgerr400("CHAT_ADMIN_REQUIRED")
|
||
}
|
||
call, changed, err := r.deps.GroupCalls.StartScheduled(ctx, scope.call.ID)
|
||
if err != nil {
|
||
return nil, groupCallErr(err)
|
||
}
|
||
channel := scope.channel
|
||
if !changed {
|
||
// 幂等:已开始,只回快照,不重复扇出/服务消息。
|
||
return r.groupCallUpdateContainer(ctx, scope.userID, channel,
|
||
groupCallUpdateFor(channel, call, scope.userID, true, r.cfg.PublicBaseURL), nil), nil
|
||
}
|
||
now := int(r.clock.Now().Unix())
|
||
// started 服务消息(与即时创建的 started 同构)。
|
||
var serviceRes domain.SendChannelMessageResult
|
||
if res, err := r.deps.Channels.AppendCallServiceMessage(ctx, channel.ID, scope.userID, now, domain.ChannelMessageAction{
|
||
Type: domain.ChannelActionGroupCall,
|
||
CallID: call.ID,
|
||
CallAccessHash: call.AccessHash,
|
||
}); err == nil {
|
||
serviceRes = res
|
||
_ = r.deps.GroupCalls.SetStartedMessageID(ctx, call.ID, res.Message.ID)
|
||
} else {
|
||
r.log.Warn("scheduled group call started service message", zap.Int64("channel_id", channel.ID), zap.Error(err))
|
||
}
|
||
// 扇出:updateGroupCall(schedule_date 已清,客户端据此自动入会)+ 服务消息。
|
||
// 订阅者与普通在线成员走同一在线扇出;离线订阅者的推送提醒(push notification)
|
||
// 属通知系统范围,当前不实现(记矩阵 todo)。
|
||
r.pushGroupCallUpdate(ctx, channel, call)
|
||
if serviceRes.Event.Pts != 0 {
|
||
r.pushGroupCallServiceMessage(ctx, scope.userID, serviceRes)
|
||
}
|
||
out := r.groupCallUpdateContainer(ctx, scope.userID, channel,
|
||
groupCallUpdateFor(channel, call, scope.userID, true, r.cfg.PublicBaseURL), nil)
|
||
if serviceRes.Event.Pts != 0 {
|
||
if msgUpdate := tgChannelUpdate(scope.userID, serviceRes.Event); msgUpdate != nil {
|
||
out.Updates = append(out.Updates, msgUpdate)
|
||
}
|
||
}
|
||
return out, nil
|
||
}
|
||
|
||
func (r *Router) onPhoneToggleGroupCallStartSubscription(ctx context.Context, req *tg.PhoneToggleGroupCallStartSubscriptionRequest) (tg.UpdatesClass, error) {
|
||
if req == nil {
|
||
return nil, inputRequestInvalidErr()
|
||
}
|
||
scope, err := r.groupCallScopeFrom(ctx, req.Call)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if !scope.call.Active() {
|
||
return nil, groupCallAlreadyDiscardedErr()
|
||
}
|
||
if scope.call.ScheduleDate == 0 {
|
||
// 只有未开始的定时通话才有开播提醒可订。
|
||
return nil, groupCallInvalidErr()
|
||
}
|
||
if err := r.deps.GroupCalls.SetScheduleSubscription(ctx, scope.call.ID, scope.userID, req.Subscribed); err != nil {
|
||
return nil, groupCallErr(err)
|
||
}
|
||
call := scope.call
|
||
call.ScheduleStartSubscribed = req.Subscribed
|
||
// 订阅是 per-viewer 私有状态:响应给本设备,推送同步本人其它在线设备即可。
|
||
update := groupCallUpdateFor(scope.channel, call, scope.userID, scope.canManage(), r.cfg.PublicBaseURL)
|
||
r.pushUserMessage(ctx, scope.userID, "schedule subscription update",
|
||
r.groupCallUpdateContainer(ctx, scope.userID, scope.channel, update, nil))
|
||
return r.groupCallUpdateContainer(ctx, scope.userID, scope.channel, update, nil), nil
|
||
}
|