fix: sync call ringing device scope
This commit is contained in:
parent
27ec9dce33
commit
bf72c246b6
3 changed files with 103 additions and 12 deletions
|
|
@ -25,6 +25,7 @@ import (
|
|||
// phonePushRecord 记录一次定向推送(目标用户、被排除的 session、载荷)。
|
||||
type phonePushRecord struct {
|
||||
userID int64
|
||||
rawAuthKeyID [8]byte
|
||||
targetSession int64
|
||||
excludeSession int64
|
||||
msg bin.Encoder
|
||||
|
|
@ -32,8 +33,9 @@ type phonePushRecord struct {
|
|||
|
||||
// phoneCaptureSessions 是带完整推送日志的 SessionBinder fake(captureSessions 只留最后一条)。
|
||||
type phoneCaptureSessions struct {
|
||||
mu sync.Mutex
|
||||
log []phonePushRecord
|
||||
mu sync.Mutex
|
||||
log []phonePushRecord
|
||||
pushErr error
|
||||
}
|
||||
|
||||
func (s *phoneCaptureSessions) BindAuthKeyForSession([8]byte, int64, [8]byte) {}
|
||||
|
|
@ -47,11 +49,11 @@ func (s *phoneCaptureSessions) UserIDResolvedForAuthKey([8]byte, int64) (int64,
|
|||
func (s *phoneCaptureSessions) UnbindAuthKey([8]byte) int { return 0 }
|
||||
func (s *phoneCaptureSessions) SetReceivesUpdatesForAuthKey([8]byte, int64, bool) {}
|
||||
|
||||
func (s *phoneCaptureSessions) PushToSessionForAuthKey(_ context.Context, _ [8]byte, sessionID int64, _ proto.MessageType, msg tg.UpdatesClass) error {
|
||||
func (s *phoneCaptureSessions) PushToSessionForAuthKey(_ context.Context, rawAuthKeyID [8]byte, sessionID int64, _ proto.MessageType, msg tg.UpdatesClass) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.log = append(s.log, phonePushRecord{targetSession: sessionID, msg: msg})
|
||||
return nil
|
||||
s.log = append(s.log, phonePushRecord{rawAuthKeyID: rawAuthKeyID, targetSession: sessionID, msg: msg})
|
||||
return s.pushErr
|
||||
}
|
||||
|
||||
func (s *phoneCaptureSessions) PushToUserExceptAuthKeySession(_ context.Context, userID int64, _ [8]byte, excludeSessionID int64, _ proto.MessageType, msg tg.UpdatesClass) (int, error) {
|
||||
|
|
@ -73,6 +75,12 @@ func (s *phoneCaptureSessions) reset() {
|
|||
s.log = nil
|
||||
}
|
||||
|
||||
func (s *phoneCaptureSessions) setPushError(err error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.pushErr = err
|
||||
}
|
||||
|
||||
// stubPrivacy 只为 CanSee 服务;其余接口方法不在通话链路使用。
|
||||
type stubPrivacy struct {
|
||||
deny map[domain.PrivacyKey]bool
|
||||
|
|
@ -104,8 +112,15 @@ type phoneFixture struct {
|
|||
}
|
||||
|
||||
const (
|
||||
phoneCallerSession = int64(101)
|
||||
phoneCalleeSession = int64(202)
|
||||
phoneCallerSession = int64(101)
|
||||
phoneCalleeSession = int64(202)
|
||||
phoneOtherCalleeSession = int64(303)
|
||||
)
|
||||
|
||||
var (
|
||||
phoneCallerRawAuthKey = [8]byte{0x11, 0x01}
|
||||
phoneCalleeRawAuthKey = [8]byte{0x22, 0x02}
|
||||
phoneOtherCalleeRawAuthKey = [8]byte{0x33, 0x03}
|
||||
)
|
||||
|
||||
func newPhoneFixture(t *testing.T, privacy PrivacyService) *phoneFixture {
|
||||
|
|
@ -133,11 +148,16 @@ func newPhoneFixture(t *testing.T, privacy PrivacyService) *phoneFixture {
|
|||
}
|
||||
|
||||
func (f *phoneFixture) callerCtx() context.Context {
|
||||
return WithSessionID(WithUserID(f.ctx, f.caller.ID), phoneCallerSession)
|
||||
return WithSessionID(WithRawAuthKeyID(WithUserID(f.ctx, f.caller.ID), phoneCallerRawAuthKey), phoneCallerSession)
|
||||
}
|
||||
|
||||
func (f *phoneFixture) calleeCtx() context.Context {
|
||||
return WithSessionID(WithUserID(f.ctx, f.callee.ID), phoneCalleeSession)
|
||||
return WithSessionID(WithRawAuthKeyID(WithUserID(f.ctx, f.callee.ID), phoneCalleeRawAuthKey), phoneCalleeSession)
|
||||
|
||||
}
|
||||
|
||||
func (f *phoneFixture) otherCalleeCtx() context.Context {
|
||||
return WithSessionID(WithRawAuthKeyID(WithUserID(f.ctx, f.callee.ID), phoneOtherCalleeRawAuthKey), phoneOtherCalleeSession)
|
||||
}
|
||||
|
||||
func phoneTestProtocol() tg.PhoneCallProtocol {
|
||||
|
|
@ -226,8 +246,8 @@ func TestPhoneCallRPCHappyPath(t *testing.T) {
|
|||
t.Fatalf("receivedCall = %v err=%v", ok, err)
|
||||
}
|
||||
pushes = f.sessions.records()
|
||||
if len(pushes) != 1 || pushes[0].userID != f.caller.ID {
|
||||
t.Fatalf("receivedCall pushes = %+v, want one to caller", pushes)
|
||||
if len(pushes) != 1 || pushes[0].rawAuthKeyID != phoneCallerRawAuthKey || pushes[0].targetSession != phoneCallerSession {
|
||||
t.Fatalf("receivedCall pushes = %+v, want caller device %x/%d", pushes, phoneCallerRawAuthKey, phoneCallerSession)
|
||||
}
|
||||
ringing, ok := phoneCallPayload(t, pushes[0]).(*tg.PhoneCallWaiting)
|
||||
if !ok || ringing.ReceiveDate == 0 {
|
||||
|
|
@ -236,6 +256,15 @@ func TestPhoneCallRPCHappyPath(t *testing.T) {
|
|||
}
|
||||
f.sessions.reset()
|
||||
|
||||
// 其它被叫设备晚到的 receivedCall 幂等成功,但不得再次推 ringing。
|
||||
if ok, err := f.router.onPhoneReceivedCall(f.otherCalleeCtx(), tg.InputPhoneCall{ID: callID, AccessHash: accessHash}); err != nil || !ok {
|
||||
t.Fatalf("duplicate receivedCall = %v err=%v", ok, err)
|
||||
}
|
||||
if pushes := f.sessions.records(); len(pushes) != 0 {
|
||||
t.Fatalf("duplicate receivedCall pushes = %+v, want none", pushes)
|
||||
}
|
||||
f.sessions.reset()
|
||||
|
||||
// --- acceptCall(被叫赢家设备) ---
|
||||
acceptRes, err := f.router.onPhoneAcceptCall(f.calleeCtx(), &tg.PhoneAcceptCallRequest{
|
||||
Peer: tg.InputPhoneCall{ID: callID, AccessHash: accessHash},
|
||||
|
|
@ -388,6 +417,35 @@ func TestPhoneCallRPCHappyPath(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestPhoneReceivedCallDevicePushFailureDoesNotBroadcast(t *testing.T) {
|
||||
f := newPhoneFixture(t, stubPrivacy{})
|
||||
_, gaHash, _ := phoneTestKeys()
|
||||
|
||||
res, err := f.router.onPhoneRequestCall(f.callerCtx(), &tg.PhoneRequestCallRequest{
|
||||
UserID: &tg.InputUser{UserID: f.callee.ID, AccessHash: f.callee.AccessHash},
|
||||
RandomID: 43,
|
||||
GAHash: gaHash,
|
||||
Protocol: phoneTestProtocol(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("requestCall: %v", err)
|
||||
}
|
||||
waiting := res.PhoneCall.(*tg.PhoneCallWaiting)
|
||||
f.sessions.reset()
|
||||
f.sessions.setPushError(errors.New("caller session gone"))
|
||||
|
||||
if ok, err := f.router.onPhoneReceivedCall(f.calleeCtx(), tg.InputPhoneCall{ID: waiting.ID, AccessHash: waiting.AccessHash}); err != nil || !ok {
|
||||
t.Fatalf("receivedCall = %v err=%v", ok, err)
|
||||
}
|
||||
pushes := f.sessions.records()
|
||||
if len(pushes) != 1 || pushes[0].rawAuthKeyID != phoneCallerRawAuthKey || pushes[0].targetSession != phoneCallerSession {
|
||||
t.Fatalf("receivedCall pushes = %+v, want one failed attempt to caller device", pushes)
|
||||
}
|
||||
if pushes[0].userID != 0 {
|
||||
t.Fatalf("receivedCall failure fell back to user broadcast: %+v", pushes)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPhoneCallRPCValidation(t *testing.T) {
|
||||
f := newPhoneFixture(t, stubPrivacy{})
|
||||
_, gaHash, gb := phoneTestKeys()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue