Ctrl K
ComunidadGuías…

internal/domain/phone.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package domain

// PhoneCallState is the server state of the private 1:1 call signaling state machine.
// State transitions, TL perspective mapping and push strategy are in docs and internal/app/phone.
type PhoneCallState string

const (
	// PhoneCallStateRequested: requestCall has been accepted and phoneCallRequested has been pushed to the callee.
	PhoneCallStateRequested PhoneCallState = "requested"
	// PhoneCallStateRinging: at least one callee device reported receivedCall (the caller switches to the ringing UI based on receive_date).
	PhoneCallStateRinging PhoneCallState = "ringing"
	// PhoneCallStateAccepted: the callee's acceptCall has stored g_b, waiting for the caller's confirmCall.
	PhoneCallStateAccepted PhoneCallState = "accepted"
	// PhoneCallStateConfirmed: the caller's confirmCall completed the key exchange and the call is in progress.
	PhoneCallStateConfirmed PhoneCallState = "confirmed"
	// PhoneCallStateDiscarded: terminal state. Kept as a tombstone for a while to absorb late RPCs before being reclaimed.
	PhoneCallStateDiscarded PhoneCallState = "discarded"
)

// PhoneCallDiscardReason is the hangup reason, one-to-one with TL phoneCallDiscardReason*.
type PhoneCallDiscardReason string

const (
	PhoneCallDiscardReasonMissed     PhoneCallDiscardReason = "missed"
	PhoneCallDiscardReasonDisconnect PhoneCallDiscardReason = "disconnect"
	PhoneCallDiscardReasonHangup     PhoneCallDiscardReason = "hangup"
	PhoneCallDiscardReasonBusy       PhoneCallDiscardReason = "busy"
	// PhoneCallDiscardReasonMigrateConference is the migration hangup when upgrading to a conference call;
	// conference is currently unsupported and the reason is only echoed verbatim.
	PhoneCallDiscardReasonMigrateConference PhoneCallDiscardReason = "migrate_conference"
)

// PhoneCallProtocol is the tgcalls protocol negotiation parameters (TL phoneCallProtocol).
type PhoneCallProtocol struct {
	UDPP2P          bool
	UDPReflector    bool
	MinLayer        int
	MaxLayer        int
	LibraryVersions []string
}

// SessionRef identifies one specific device connection (the anchor for the signaling targeted-push fast path; allowed to go stale).
type SessionRef struct {
	RawAuthKeyID [8]byte
	SessionID    int64
}

// Zero reports whether the anchor is unrecorded.
func (s SessionRef) Zero() bool {
	return s == SessionRef{}
}

// PhoneCallConnection is a WebRTC STUN/TURN server entry issued to both sides
// (TL phoneConnectionWebrtc). Issued when requestCall is accepted and stable for the whole lifetime.
type PhoneCallConnection struct {
	ID       int64
	IP       string
	Port     int
	Username string
	Password string
	Stun     bool
	Turn     bool
}

// PhoneCallRequest is the acceptance input of phone.requestCall (privacy/block checks run first in the rpc layer).
type PhoneCallRequest struct {
	CalleeID     int64
	RandomID     int64
	GAHash       []byte
	Video        bool
	Protocol     PhoneCallProtocol
	CallerDevice SessionRef
	// PrivacyP2P is the two-way AND of phone_p2p privacy (computed by the rpc layer; set false when relay is forced).
	PrivacyP2P bool
	// Connections is the STUN/TURN list issued for this call (may be empty: when TURN is disabled it falls back to
	// a LAN direct connection that exchanges host candidates through pure signaling).
	Connections []PhoneCallConnection
}

// PhoneCall is the server-authoritative state of one private call. Key material (GAHash/GB/GA) lives only in an
// in-process registry and is destroyed with tombstone reclamation, never persisted to any storage.
type PhoneCall struct {
	ID         int64
	AccessHash int64
	// AdminID is the caller and ParticipantID the callee; named the same as the TL phoneCall fields and unchanged for the whole lifetime.
	AdminID       int64
	ParticipantID int64
	Video         bool
	State         PhoneCallState

	Date        int // requestCall acceptance time (unix seconds)
	ReceiveDate int // time of the first callee device's receivedCall; 0 means not yet reached
	StartDate   int // confirmCall completion time
	DiscardedAt int // time of entering the terminal state (basis for tombstone GC)

	GAHash         []byte // 32B, the commitment carried by requestCall
	GB             []byte // 256B, carried by acceptCall
	GA             []byte // 256B, revealed by confirmCall (the server verifies SHA256(GA)==GAHash)
	KeyFingerprint int64  // E2E fingerprint the server cannot verify and only relays

	// Protocol is the negotiated result (computed at accept); CallerProtocol/CalleeProtocol keep the two originals.
	Protocol       PhoneCallProtocol
	CallerProtocol PhoneCallProtocol
	CalleeProtocol PhoneCallProtocol

	P2PAllowed    bool
	DiscardReason PhoneCallDiscardReason
	// DiscardReasonSlug is set for migrate_conference and must resolve through
	// phone.getGroupCall(inputGroupCallSlug) before the discarded update is sent.
	DiscardReasonSlug string
	Duration          int

	// PrivacyP2P and Connections are preserved verbatim from PhoneCallRequest (see its comment).
	PrivacyP2P  bool
	Connections []PhoneCallConnection

	RandomID int64 // half of the caller-side idempotent dedup key (callerID+RandomID)

	// Device anchors: the originating device of requestCall / acceptCall, used only as a hint for targeted push.
	CallerDevice SessionRef
	CalleeDevice SessionRef
}

// Terminal reports whether the call has entered the terminal state.
func (c PhoneCall) Terminal() bool {
	return c.State == PhoneCallStateDiscarded
}

// PeerOf returns userID's peer in this call; returns 0 when userID is not a participant.
func (c PhoneCall) PeerOf(userID int64) int64 {
	switch userID {
	case c.AdminID:
		return c.ParticipantID
	case c.ParticipantID:
		return c.AdminID
	default:
		return 0
	}
}

// HasParticipant reports whether userID is a participant in this call.
func (c PhoneCall) HasParticipant(userID int64) bool {
	return userID != 0 && (userID == c.AdminID || userID == c.ParticipantID)
}