owpengram-server/internal/rpc/deps.go
2026-07-24 11:57:00 +08:00

1143 lines
97 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"
"time"
"github.com/iamxvbaba/td/proto"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/domain"
"telesrv/internal/sfu"
"telesrv/internal/store"
"telesrv/internal/turnsrv"
)
// 本文件按「消费者定义接口」惯例,在 rpc 包定义 Router 依赖的业务服务接口。
// app/* 的 Service 实现它们;微服务化时 gRPC client 同样可实现rpc 层无需改动。
// 接口方法只用 domain 类型与基本类型,不依赖 app 具体包——这是 rpc↔业务的契约边界。
// AuthService 抽象登录/注册业务。
type AuthService interface {
BindTempAuthKey(ctx context.Context, sessionID int64, binding domain.TempAuthKeyBinding) error
ResolveAuthKey(ctx context.Context, authKeyID [8]byte) ([8]byte, bool, error)
UserID(ctx context.Context, authKeyID [8]byte) (int64, bool, error)
PendingPasswordUserID(ctx context.Context, authKeyID [8]byte) (int64, bool, error)
CompletePasswordSignIn(ctx context.Context, authKeyID [8]byte) error
SendCode(ctx context.Context, phone string) (string, error)
CodeDelivery(ctx context.Context, phoneCodeHash string) (domain.AuthCodeDelivery, bool, error)
ResendCode(ctx context.Context, phone, phoneCodeHash string) (string, error)
CancelCode(ctx context.Context, phone, phoneCodeHash string) error
SignIn(ctx context.Context, a domain.Authorization, phone, phoneCodeHash, code string) (domain.User, domain.Message, bool, error)
// SignInWithEmail 处理带 email_verification 的 auth.signIn登录邮箱路径
SignInWithEmail(ctx context.Context, a domain.Authorization, phone, phoneCodeHash, code string) (domain.User, domain.Message, bool, error)
SignUp(ctx context.Context, a domain.Authorization, phone, phoneCodeHash, firstName, lastName string) (domain.User, domain.Message, error)
AcceptLoginToken(ctx context.Context, a domain.Authorization, userID int64) (domain.Authorization, error)
// BindVerifiedLogin 绑定一个已由外部强因子(passkey)验证身份的用户,直接完成授权。
BindVerifiedLogin(ctx context.Context, a domain.Authorization, userID int64) (domain.User, error)
// SignInBot 校验 bot token 并绑定授权auth.importBotAuthorization
// 校验失败返回 domain.ErrBotTokenInvalid。
SignInBot(ctx context.Context, a domain.Authorization, token string) (domain.User, error)
LogOut(ctx context.Context, authKeyID [8]byte) error
Authorization(ctx context.Context, authKeyID [8]byte) (domain.Authorization, bool, error)
AuthKeyClientInfo(ctx context.Context, authKeyID [8]byte) (domain.AuthKeyClientInfo, bool, error)
UpdateAuthKeyClientInfo(ctx context.Context, authKeyID [8]byte, info domain.AuthKeyClientInfo) error
ListAuthorizations(ctx context.Context, userID int64) ([]domain.Authorization, error)
ResetAuthorization(ctx context.Context, userID, hash int64) (domain.Authorization, bool, error)
ResetAuthorizations(ctx context.Context, userID int64, keepAuthKeyID [8]byte) ([]domain.Authorization, error)
}
type AuthDeliveryReportService interface {
ReportMissingCode(ctx context.Context, req domain.AuthMissingCodeReportRequest) (domain.AuthDeliveryReport, bool, error)
}
type ClientTelemetryService interface {
Record(ctx context.Context, userID int64, kind domain.ClientTelemetryKind, peer domain.Peer, subjectIDs []int64, payload any, createdAt time.Time) (domain.ClientTelemetryEvent, bool, error)
}
// SessionBinder 抽象登录后 session 与 user 的在线绑定。
//
// MTProto session 的完整身份是 raw auth_key_id + session_id。所有定位单个 session
// 的方法都必须携带这两个值;禁止退回只按 session_id 查询,否则不同 auth key 复用
// 同一随机 session_id 时会产生跨账号绑定、排除或推送歧义。
type SessionBinder interface {
BindAuthKeyForSession(rawAuthKeyID [8]byte, sessionID int64, authKeyID [8]byte)
AuthKeyIDForSession(rawAuthKeyID [8]byte, sessionID int64) ([8]byte, bool)
BindUserForAuthKey(rawAuthKeyID [8]byte, sessionID, userID int64)
UserIDResolvedForAuthKey(rawAuthKeyID [8]byte, sessionID int64) (userID int64, resolved bool)
UnbindAuthKey(authKeyID [8]byte) int
SetReceivesUpdatesForAuthKey(rawAuthKeyID [8]byte, sessionID int64, receives bool)
PushToSessionForAuthKey(ctx context.Context, rawAuthKeyID [8]byte, sessionID int64, t proto.MessageType, msg tg.UpdatesClass) error
// excludeAuthKeyID/excludeSessionID 必须同时为零(不排除)或同时非零(精确排除)。
PushToUserExceptAuthKeySession(ctx context.Context, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64, t proto.MessageType, msg tg.UpdatesClass) (int, error)
}
// RawAuthKeySessionBinder 在 auth.bindTempAuthKey 成功后,把同一 raw temporary key
// 已建立的所有 session 一次性切到 canonical permanent identity。只更新当前 session
// 会让并发启动的其它连接永久粘在 raw identity。
type RawAuthKeySessionBinder interface {
BindAuthKeyForRawAuthKey(rawAuthKeyID [8]byte, authKeyID [8]byte) int
}
// RawAuthKeyMetadataProvider 暴露握手时确定的 raw key protocol expiry。0 表示
// permanent key正值表示 temporary key。Router 只用它判断 cached==raw 是否可作为
// permanent 快路径,协议过期的实际拒绝仍由 mtprotoedge 完成。
type RawAuthKeyMetadataProvider interface {
AuthKeyExpiresAtForSession(rawAuthKeyID [8]byte, sessionID int64) (expiresAt int, found bool)
}
// ImmediateSessionPusher 是可选的登录前信号直推能力。
// 它绕过登录后 updates-ready 队列,只能用于会解锁登录流程本身的握手消息,
// 例如 updateLoginToken。
type ImmediateSessionPusher interface {
PushToSessionForAuthKeyImmediate(ctx context.Context, rawAuthKeyID [8]byte, sessionID int64, t proto.MessageType, msg tg.UpdatesClass) error
}
// SessionUpdatesStateProvider 暴露连接当前的 updates 接收状态(可选能力)。
// 用于按 RPC 置位 receivesUpdates 时的幂等短路;不实现时每次都走完整置位(幂等,仅多余开销)。
type SessionUpdatesStateProvider interface {
ReceivesUpdatesForAuthKey(rawAuthKeyID [8]byte, sessionID int64) bool
}
// ClientLayerBinder 把协商 TL layer 即时下推到连接(可选能力)。
// invokeWithLayer 在 Dispatch 入口被观测到时立即调用,使同一请求 handler 执行期间
// 触发的 pending flush / 并发 push 就已按正确 layer 降级;不实现时连接层只能靠
// Dispatch 返回后的兜底刷新,重连老客户端首条 RPC 期间的推送会漏降级。
type ClientLayerBinder interface {
SetClientLayerForAuthKey(rawAuthKeyID [8]byte, sessionID int64, layer int)
}
// AuthKeyLayerBinder seeds an inherited auth-key default into every live
// session that still has no explicit invokeWithLayer observation. Implementors
// must not overwrite an explicit per-session profile; the returned count is
// diagnostic only.
//
// Router uses this optional capability after auth.bindTempAuthKey normalizes a
// raw temporary key to its permanent identity. Keeping it separate from
// ClientLayerBinder makes the source distinction explicit: inherited defaults
// are mutable initialization state, while an explicit session observation is a
// correction for exactly one logical session.
type AuthKeyLayerBinder interface {
SeedInheritedLayerForRawAuthKey(rawAuthKeyID [8]byte, layer int) int
}
// BusinessAuthKeyLayerBinder seeds unknown live sessions across every raw PFS
// key currently normalized to the same permanent/business auth key.
type BusinessAuthKeyLayerBinder interface {
SeedInheritedLayerForBusinessAuthKey(authKeyID [8]byte, layer int) int
}
// AuthKeyLayerRefresher is the identity-normalization variant used after
// auth.bindTempAuthKey. It may replace an inherited raw-key shadow with the
// permanent key's default, but must still preserve every explicit session
// profile.
type AuthKeyLayerRefresher interface {
RefreshInheritedLayerForRawAuthKey(rawAuthKeyID [8]byte, layer int) int
}
// AuthKeyInheritedLayerClearer removes only the mutable inherited default for
// a physical/raw key. Explicit per-session invokeWithLayer profiles are wire
// evidence and must survive. Router uses this when a temp key binds to a
// permanent key whose durable Layer is authoritative but unsupported by this
// binary; retaining the raw key's older inherited default would silently
// downgrade naked RPCs instead of asking the client to correct explicitly.
type AuthKeyInheritedLayerClearer interface {
ClearInheritedLayerForRawAuthKey(rawAuthKeyID [8]byte) int
}
// ActiveSessionLayerEvidenceProvider exposes the live connection's explicit
// profile when auth.bindTempAuthKey runs after the Router's bounded exact-
// profile retention window. It is deliberately session-scoped and must never
// report an inherited profile as explicit evidence.
type ActiveSessionLayerEvidenceProvider interface {
ExplicitLayerEvidenceForAuthKey(rawAuthKeyID [8]byte, sessionID int64) (layer int, msgID int64, ok bool)
}
// SessionTerminator 暴露按业务 auth_key 强制断开活跃连接的能力(可选)。
// 授权撤销(被踢设备)必须断开连接:出站推送用连接持有的密钥加密、不回查授权,
// perm-key 连接的授权缓存也只有断开重连才会重新回查授权表。
type SessionTerminator interface {
CloseSessionsForBusinessAuthKey(authKeyID [8]byte) int
}
// RawSessionTerminator 暴露按连接实际 raw auth_key 强制断开的能力(可选)。
// temp auth key 被撤销时Router 会先从 temp→perm 缓存里找出同一授权的 raw temp key
// 再用这个接口踢掉仍未完全解析到业务 key 的活跃连接,避免等缓存 TTL 或下一帧才失效。
type RawSessionTerminator interface {
CloseSessionsForRawAuthKeyExcept(authKeyID [8]byte, exceptSessionID int64) int
}
// BestEffortSessionBinder 是带 raw auth_key_id 精确排除当前设备的短超时推送接口;
// 不用于 RPC result/ack。
type BestEffortSessionBinder interface {
PushToUserExceptAuthKeySessionBestEffort(ctx context.Context, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64, t proto.MessageType, msg tg.UpdatesClass, timeout time.Duration) (int, error)
}
// TransientSessionBinder 推送短命、不写 durable log 的 updatetyping / presence
// 与普通推送的关键区别:目标 session 未就绪时直接跳过、不进 pending——transient 数据
// getDifference 无法补,就绪后由 getState 快照/下次状态变化重建,囤积过期 transient 无意义。
type TransientSessionBinder interface {
PushToUserTransientExceptAuthKeySession(ctx context.Context, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64, t proto.MessageType, msg tg.UpdatesClass, timeout time.Duration) (int, error)
}
// AuthKeyTargetedSessionBinder 把 update 定向投递给某用户【绑定到具体 business auth_key
// 这台设备】的就绪连接密聊设备级投递。SessionManager 实现;测试替身/未装配时
// rpc 层回退账号级推送。未就绪连接跳过、不进 pending密聊离线靠 getDifference 补)。
type AuthKeyTargetedSessionBinder interface {
PushToUserAuthKey(ctx context.Context, userID int64, businessAuthKeyID [8]byte, t proto.MessageType, msg tg.UpdatesClass) (int, error)
PushToUserAuthKeyTransient(ctx context.Context, userID int64, businessAuthKeyID [8]byte, t proto.MessageType, msg tg.UpdatesClass, timeout time.Duration) (int, error)
}
// ExactLayerTransientSessionBinder is the admission boundary for updates whose
// constructors do not exist in older profiles. Implementations must filter the
// live session index before encoding, skip unknown/not-ready profiles, and must
// never queue the transient payload for later delivery.
type ExactLayerTransientSessionBinder interface {
PushToUserTransientAtLeastLayer(ctx context.Context, userID int64, minLayer int, t proto.MessageType, msg tg.UpdatesClass, timeout time.Duration) (int, error)
PushToUserAuthKeyTransientAtLeastLayer(ctx context.Context, userID int64, businessAuthKeyID [8]byte, minLayer int, t proto.MessageType, msg tg.UpdatesClass, timeout time.Duration) (int, error)
}
// OnlineUserProvider exposes a bounded runtime snapshot for best-effort fanout.
type OnlineUserProvider interface {
IsUserOnline(userID int64) bool
OnlineUserIDsForCandidates(candidateUserIDs []int64, limit int) []int64
TrackChannelInterest(rawAuthKeyID [8]byte, sessionID, userID int64, channelIDs []int64)
ClearChannelInterest(rawAuthKeyID [8]byte, sessionID, userID int64)
OnlineChannelUserIDs(channelID int64, limit int) []int64
// ChannelMembershipGeneration / SetSessionChannelMemberships 配对使用:调用方在读取
// 持久成员列表前采样修订号,落地时带回;期间发生增量 Add/Remove 时 Set 走合并路径
// 并保持未就绪,由下一条 RPC 重试全量同步(防全量替换覆盖窗口内的增量 join/leave
ChannelMembershipGeneration(rawAuthKeyID [8]byte, sessionID int64) int64
SetSessionChannelMemberships(rawAuthKeyID [8]byte, sessionID, userID int64, channelIDs []int64, expectedGen int64)
AddUserChannelMembership(userID, channelID int64)
RemoveUserChannelMembership(userID, channelID int64)
OnlineChannelMemberUserIDs(channelID int64, limit int) []int64
}
// ChannelNudgeProvider 暴露「频道在线成员中排除已投递集合后的剩余 user id」用于 >cap
// 在线成员的 UpdateChannelTooLong nudgeP0-8。SessionManager 实现;测试/未装配 fake 可不实现
// type-assert 失败时跳过 nudge不影响完整 payload 投递)。
type ChannelNudgeProvider interface {
OnlineChannelMemberUserIDsExcluding(channelID int64, exclude map[int64]struct{}, limit int) []int64
}
// ChannelFanoutRecoverySessionProvider snapshots the process-local online joined-channel index in
// stable channel-id order. It is used only after every keyed fan-out mailbox is saturated. The
// fixed recovery actor accepts the temporary 8*C id slice so one sweep never repeatedly scans the
// SessionManager index or holds its global lock while sorting/database work runs.
type ChannelFanoutRecoverySessionProvider interface {
OnlineChannelIDsSnapshot() []int64
}
// ChannelFanoutRecoveryPtsProvider reloads the authoritative channel pts after in-memory fan-out
// saturation. Production channels.Service implements it through the channel store; keeping this
// separate from ChannelsService avoids burdening lightweight RPC fakes that never run the worker.
type ChannelFanoutRecoveryPtsProvider interface {
MaxChannelPtsBatch(ctx context.Context, channelIDs []int64) (map[int64]int, error)
}
// RateLimiter 抽象 RPC 高频写操作限流。
type RateLimiter interface {
Allow(ctx context.Context, key string, limit int, window time.Duration) (allowed bool, retryAfterSeconds int, err error)
AllowN(ctx context.Context, key string, cost, limit int, window time.Duration) (allowed bool, retryAfterSeconds int, err error)
}
// UsersService 抽象用户查询。
type UsersService interface {
Self(ctx context.Context, userID int64) (domain.User, error)
ByID(ctx context.Context, currentUserID, userID int64) (domain.User, bool, error)
ByIDs(ctx context.Context, currentUserID int64, userIDs []int64) ([]domain.User, error)
}
// TelegramLoginService is the domain-only boundary shared by the MTProto RPC
// edge and the public OIDC provider. PostgreSQL remains authoritative for all
// consent transitions; the RPC layer only projects domain state to TL.
type TelegramLoginService interface {
ValidateMessageButton(ctx context.Context, botUserID int64, rawURL string) (normalizedURL, domainName string, err error)
AuthorizeMessageButton(ctx context.Context, params domain.TelegramLoginMessageButtonAuthorization) (domain.TelegramLoginMessageButtonResult, error)
RequestByDeepLink(ctx context.Context, deepLink string) (domain.TelegramLoginRequest, error)
RequestByDeepLinkForOrigin(ctx context.Context, deepLink, inAppOrigin string) (domain.TelegramLoginRequest, error)
CheckMatchCode(ctx context.Context, deepLink, selected string) (bool, error)
Approve(ctx context.Context, deepLink string, identity domain.TelegramLoginIdentitySnapshot, writeAllowed, phoneShared bool, matchCode string) (domain.TelegramLoginRequest, domain.TelegramLoginWebAuthorization, error)
FinalizeRedirectByDeepLink(ctx context.Context, deepLink string) (string, error)
FinalizeInAppRedirectByDeepLink(ctx context.Context, deepLink string) (string, error)
Decline(ctx context.Context, deepLink string, userID int64) (domain.TelegramLoginRequest, error)
ListWebAuthorizations(ctx context.Context, userID int64) ([]domain.TelegramLoginWebAuthorization, error)
RevokeWebAuthorization(ctx context.Context, userID, hash int64) error
RevokeAllWebAuthorizations(ctx context.Context, userID int64) (int64, error)
}
// BatchViewerUsersResolver 是 UsersService 的可选能力:跨多个 viewer 一次性投影同一组 user
// fan-out 模板化,把 per-recipient 的 ByIDs(=ForViewer) 折叠成 O(owner) 查询)。结果按 viewer
// 与 ByIDs(viewer, ids) 字节等价personal photo overlay 除外,见 users.ByIDsForViewers
// 未实现时 fan-out 预热静默跳过,回退逐 viewer 解析(行为不变,仅退化为旧的 O(viewer) 成本)。
type BatchViewerUsersResolver interface {
ByIDsForViewers(ctx context.Context, viewerUserIDs []int64, userIDs []int64) (map[int64][]domain.User, error)
}
// BotsService 抽象 bot 元数据查询与管理bots.* RPC + userFull.bot_info hydrate
// 写方法返回 bump 后的 bot_info_version客户端据此重拉
type BotsService interface {
BotInfo(ctx context.Context, botUserID int64) (domain.BotProfile, bool, error)
OwnsBot(ctx context.Context, ownerUserID, botUserID int64) (bool, error)
CheckUsername(ctx context.Context, ownerUserID int64, username string) (bool, error)
CreateBot(ctx context.Context, ownerUserID int64, name, username string) (domain.User, string, error)
ListOwnedBots(ctx context.Context, ownerUserID int64) ([]domain.User, error)
ExportBotToken(ctx context.Context, ownerUserID, botUserID int64, revoke bool) (string, error)
SetBotCommands(ctx context.Context, botUserID int64, commands []domain.BotCommand) (int, error)
GetBotCommands(ctx context.Context, botUserID int64) ([]domain.BotCommand, error)
SetBotInfo(ctx context.Context, botUserID int64, upd domain.BotInfoUpdate) (int, error)
GetBotInfo(ctx context.Context, botUserID int64) (name, about, description string, err error)
SetBotMenuButton(ctx context.Context, botUserID int64, button domain.BotMenuButton) (int, error)
GetBotMenuButton(ctx context.Context, botUserID int64) (domain.BotMenuButton, error)
SetInlinePlaceholder(ctx context.Context, botUserID int64, placeholder string) (int, error)
CanSendMessage(ctx context.Context, userID, botUserID int64) (bool, error)
AllowSendMessage(ctx context.Context, userID, botUserID int64, fromRequest bool) (bool, error)
UpsertBotApp(ctx context.Context, botUserID int64, app domain.BotApp) (domain.BotApp, int, error)
GetBotAppByID(ctx context.Context, appID, accessHash int64) (domain.BotApp, bool, error)
GetBotAppByShortName(ctx context.Context, botUserID int64, shortName string) (domain.BotApp, bool, error)
GetMainBotApp(ctx context.Context, botUserID int64) (domain.BotApp, bool, error)
ListBotApps(ctx context.Context, botUserID int64) ([]domain.BotApp, error)
GetBotAppSettings(ctx context.Context, botUserID int64) (domain.BotAppSettings, bool, error)
UpsertBotAppSettings(ctx context.Context, botUserID int64, settings domain.BotAppSettings) (int, error)
ListBotAppPreviewMedia(ctx context.Context, botUserID, appID int64) ([]domain.BotAppPreviewMedia, error)
UpsertBotAppPreviewMedia(ctx context.Context, media domain.BotAppPreviewMedia) (domain.BotAppPreviewMedia, int, error)
DeleteBotAppPreviewMedia(ctx context.Context, botUserID, appID, mediaID int64) (int, error)
ReorderBotAppPreviewMedia(ctx context.Context, botUserID, appID int64, mediaIDs []int64) (int, error)
UpsertAttachMenuBot(ctx context.Context, botUserID int64, bot domain.BotAttachMenuBot) (int, error)
GetAttachMenuBot(ctx context.Context, botUserID int64) (domain.BotAttachMenuBot, bool, error)
ListAttachMenuBots(ctx context.Context) ([]domain.BotAttachMenuBot, error)
GetAttachMenuState(ctx context.Context, userID, botUserID int64) (domain.BotAttachMenuState, bool, error)
SetAttachMenuState(ctx context.Context, state domain.BotAttachMenuState) (domain.BotAttachMenuState, error)
SaveRequestedWebViewButton(ctx context.Context, button domain.BotRequestedWebViewButton) (domain.BotRequestedWebViewButton, error)
GetRequestedWebViewButton(ctx context.Context, botUserID, userID int64, reqID string) (domain.BotRequestedWebViewButton, bool, error)
DeleteRequestedWebViewButton(ctx context.Context, botUserID, userID int64, reqID string) error
SetBotEmojiStatusPermission(ctx context.Context, botUserID, userID int64, allowed bool) error
BotEmojiStatusPermission(ctx context.Context, botUserID, userID int64) (bool, error)
PutWebViewCustomMethodQuery(ctx context.Context, botUserID, userID int64, method, paramsJSON string) (domain.BotWebViewCustomMethodQuery, error)
}
// UserIdentityService 是 UsersService 的资料扩展能力,用于 username/phone 解析。
type UserIdentityService interface {
CheckUsername(ctx context.Context, userID int64, username string) (bool, error)
UpdateProfile(ctx context.Context, userID int64, update domain.UserProfileUpdate) (domain.User, error)
UpdateUsername(ctx context.Context, userID int64, username string) (domain.User, error)
UpdateBirthday(ctx context.Context, userID int64, birthday domain.Birthday) (domain.User, error)
UpdatePersonalChannel(ctx context.Context, userID int64, channelID int64) (domain.User, error)
ResolveUsername(ctx context.Context, currentUserID int64, username string) (domain.User, bool, error)
ResolvePhone(ctx context.Context, currentUserID int64, phone string) (domain.User, bool, error)
}
// UserPremiumService 是 UsersService 的会员扩展能力:授予/续期、到期清理
// PremiumSweeper与 emoji statuspremium 专属)。设计见 docs/premium-module.md。
type UserPremiumService interface {
GrantPremium(ctx context.Context, userID int64, months int) (domain.User, error)
SweepExpiredPremium(ctx context.Context, now int64, limit int) ([]domain.User, error)
UpdateEmojiStatus(ctx context.Context, userID int64, status domain.UserEmojiStatus) (domain.User, error)
}
// UserEmojiStatusDurableService exposes the aggregate state+event write used
// by account.updateEmojiStatus. The bool is false for lightweight stores that
// require the RPC Updates service to append the event separately.
type UserEmojiStatusDurableService interface {
UpdateEmojiStatusWithEvent(ctx context.Context, userID int64, status domain.UserEmojiStatus, date int, excludeAuthKeyID [8]byte, excludeSessionID int64) (domain.User, domain.UpdateEvent, bool, error)
}
// UserColorService 是 UsersService 的个人色板扩展能力。用于 account.updateColor
// 持久化当前账号的消息气泡 accent 或资料页背景色。
type UserColorService interface {
UpdateColor(ctx context.Context, userID int64, forProfile bool, color domain.PeerColor) (domain.User, error)
}
// UserPremiumStatusService 暴露轻量会员判断(基础用户缓存路径,不做 viewer
// 投影供限额双档reaction 上限等)低成本调用。
type UserPremiumStatusService interface {
PremiumActive(ctx context.Context, userID int64) bool
}
// AccountService 抽象账号设置查询。
type AccountService interface {
SendChangePhoneCode(ctx context.Context, userID int64, authKeyID [8]byte, sessionID int64, phone string) (string, domain.AuthCodeDelivery, error)
ChangePhone(ctx context.Context, userID int64, authKeyID, originRawAuthKeyID [8]byte, sessionID int64, phone, phoneCodeHash, code string, date int) (domain.PhoneChangeResult, error)
GetPassword(ctx context.Context, userID int64) (domain.PasswordSettings, error)
GetPasswordSettings(ctx context.Context, userID int64, check domain.PasswordCheck) (domain.PrivatePasswordSettings, error)
UpdatePasswordSettings(ctx context.Context, userID int64, check domain.PasswordCheck, input domain.PasswordInputSettings) error
CheckPassword(ctx context.Context, userID int64, check domain.PasswordCheck) error
RequestPasswordRecovery(ctx context.Context, userID int64) (string, error)
CheckRecoveryPassword(ctx context.Context, userID int64, code string) error
RecoverPassword(ctx context.Context, userID int64, code string, input *domain.PasswordInputSettings) error
ConfirmPasswordEmail(ctx context.Context, userID int64, code string) error
ResendPasswordEmail(ctx context.Context, userID int64) error
CancelPasswordEmail(ctx context.Context, userID int64) error
// 登录邮箱(独立于 2FA 恢复邮箱authed 走 userID登录流程/重置走 phone。
SendLoginEmailCode(ctx context.Context, userID int64, phone, phoneCodeHash, email string, setup bool) (string, int, error)
VerifyLoginEmail(ctx context.Context, userID int64, phone, phoneCodeHash, code string, setup bool) (string, error)
SetLoginEmail(ctx context.Context, userID int64, email string) error
LoginEmail(ctx context.Context, userID int64) (string, bool, error)
LoginEmailByPhone(ctx context.Context, phone string) (string, bool, error)
ClearLoginEmail(ctx context.Context, userID int64) error
ResetPassword(ctx context.Context, userID int64) (domain.PasswordResetResult, error)
DeclinePasswordReset(ctx context.Context, userID int64) error
SaveMusic(ctx context.Context, userID int64, req domain.SaveMusicRequest) (bool, error)
ListSavedMusicIDs(ctx context.Context, userID int64, limit int) ([]int64, error)
ListSavedMusic(ctx context.Context, userID int64, offset, limit int) (domain.SavedMusicList, error)
GetSavedMusicByIDs(ctx context.Context, userID int64, ids []int64) (domain.SavedMusicList, error)
}
// AccountBusinessAutomationService 是账号业务自动化的可选扩展。
// 只暴露 domain DTO避免 Telegram TL 类型越过 rpc 边界。
type AccountBusinessAutomationService interface {
GetBusinessProfile(ctx context.Context, userID int64) (domain.BusinessProfile, bool, error)
UpdateBusinessWorkHours(ctx context.Context, userID int64, hours *domain.BusinessWorkHours) (domain.BusinessProfile, error)
UpdateBusinessLocation(ctx context.Context, userID int64, location *domain.BusinessLocation) (domain.BusinessProfile, error)
UpdateBusinessIntro(ctx context.Context, userID int64, intro *domain.BusinessIntro) (domain.BusinessProfile, error)
UpdateBusinessGreetingMessage(ctx context.Context, userID int64, greeting *domain.BusinessGreetingMessage) (domain.BusinessProfile, error)
UpdateBusinessAwayMessage(ctx context.Context, userID int64, away *domain.BusinessAwayMessage) (domain.BusinessProfile, error)
ListBusinessChatLinks(ctx context.Context, userID int64) ([]domain.BusinessChatLink, error)
CreateBusinessChatLink(ctx context.Context, userID int64, input domain.BusinessChatLinkInput) (domain.BusinessChatLink, error)
EditBusinessChatLink(ctx context.Context, userID int64, slug string, input domain.BusinessChatLinkInput) (domain.BusinessChatLink, error)
DeleteBusinessChatLink(ctx context.Context, userID int64, slug string) (bool, error)
ResolveBusinessChatLink(ctx context.Context, slug string, bumpViews bool) (domain.BusinessChatLink, bool, error)
ListQuickReplies(ctx context.Context, userID int64) (domain.QuickReplyList, error)
CheckQuickReplyShortcut(ctx context.Context, userID int64, shortcut string) (bool, error)
SaveQuickReplyText(ctx context.Context, userID int64, shortcut string, msg domain.QuickReplyMessage) (domain.QuickReplyMutation, error)
GetQuickReplyMessages(ctx context.Context, userID int64, shortcutID int, ids []int) (domain.QuickReplyMessages, error)
RenameQuickReplyShortcut(ctx context.Context, userID int64, shortcutID int, shortcut string) (domain.QuickReplyMutation, error)
ReorderQuickReplies(ctx context.Context, userID int64, order []int) (domain.QuickReplyMutation, error)
DeleteQuickReplyShortcut(ctx context.Context, userID int64, shortcutID int) (domain.QuickReplyMutation, error)
DeleteQuickReplyMessages(ctx context.Context, userID int64, shortcutID int, ids []int) (domain.QuickReplyMutation, error)
GetConnectedBusinessBot(ctx context.Context, ownerUserID int64) (domain.ConnectedBusinessBot, bool, error)
SaveConnectedBusinessBot(ctx context.Context, ownerUserID int64, bot domain.ConnectedBusinessBot) (domain.ConnectedBusinessBot, error)
DeleteConnectedBusinessBot(ctx context.Context, ownerUserID, botUserID int64) (bool, error)
SetConnectedBusinessBotPaused(ctx context.Context, ownerUserID, peerUserID int64, paused bool) (domain.ConnectedBusinessBotPeerState, error)
DisableConnectedBusinessBotForPeer(ctx context.Context, ownerUserID, peerUserID int64) (domain.ConnectedBusinessBotPeerState, error)
GetConnectedBusinessBotPeerState(ctx context.Context, ownerUserID, peerUserID int64) (domain.ConnectedBusinessBotPeerState, bool, error)
}
// PrivacyService owns account privacy rule storage/evaluation.
type PrivacyService interface {
GetRules(ctx context.Context, ownerUserID int64, key domain.PrivacyKey) (domain.PrivacyRules, error)
SetRules(ctx context.Context, ownerUserID int64, key domain.PrivacyKey, rules []domain.PrivacyRule) (domain.PrivacyRules, error)
AddAllowUser(ctx context.Context, ownerUserID int64, key domain.PrivacyKey, targetUserID int64) (domain.PrivacyRules, bool, error)
CanSee(ctx context.Context, ownerUserID, viewerUserID int64, key domain.PrivacyKey) (bool, error)
}
// HelpService 抽象启动配置与国家区号目录。
type HelpService interface {
GetAppConfig(ctx context.Context, userID int64, hash int) (domain.AppConfig, bool, error)
GetCountries(ctx context.Context, langCode string, hash int) (domain.CountriesList, bool, error)
}
// AccountFreezeService exposes the account-level read-only fact used by the
// central RPC mutation gate. It is domain-only and shared with app/help.
type AccountFreezeService interface {
AccountFreeze(ctx context.Context, userID int64) (domain.AccountFreeze, bool, error)
}
// UpdatesService 抽象 update 状态查询。
type UpdatesService interface {
GetState(ctx context.Context, authKeyID [8]byte, userID int64) (domain.UpdateState, error)
CurrentState(ctx context.Context, userID int64) (domain.UpdateState, error)
ConfirmedState(ctx context.Context, authKeyID [8]byte, userID int64) (domain.UpdateState, bool, error)
ObserveDifferenceRequest(ctx context.Context, authKeyID [8]byte, userID int64, from domain.UpdateState) (domain.UpdateState, error)
GetDifference(ctx context.Context, authKeyID [8]byte, userID int64, from domain.UpdateState) (domain.UpdateDifference, error)
CommitDeliveredState(ctx context.Context, authKeyID [8]byte, userID int64, state domain.UpdateState, mode domain.UpdateStateCommitMode) error
ClearAuthKey(ctx context.Context, authKeyID [8]byte) error
RecordNewMessage(ctx context.Context, authKeyID [8]byte, userID int64, msg domain.Message) (domain.UpdateEvent, domain.UpdateState, error)
PublishNewMessage(ctx context.Context, userID int64, msg domain.Message) (domain.UpdateEvent, domain.UpdateState, error)
RecordStory(ctx context.Context, stateAuthKeyID [8]byte, userID int64, story domain.Story, excludeAuthKeyID [8]byte, excludeSessionID int64) (domain.UpdateEvent, domain.UpdateState, error)
RecordStoryFanout(ctx context.Context, userID int64, story domain.Story) (domain.UpdateEvent, domain.UpdateState, error)
RecordReadStories(ctx context.Context, stateAuthKeyID [8]byte, userID int64, read domain.StoryReadResult, excludeAuthKeyID [8]byte, excludeSessionID int64) (domain.UpdateEvent, domain.UpdateState, error)
RecordSentStoryReaction(ctx context.Context, stateAuthKeyID [8]byte, userID int64, reaction domain.StoryReactionResult, excludeAuthKeyID [8]byte, excludeSessionID int64) (domain.UpdateEvent, domain.UpdateState, error)
RecordNewStoryReaction(ctx context.Context, stateAuthKeyID [8]byte, ownerUserID int64, reaction domain.StoryReactionResult, excludeAuthKeyID [8]byte, excludeSessionID int64) (domain.UpdateEvent, domain.UpdateState, error)
RecordQuickReplyMutation(ctx context.Context, stateAuthKeyID [8]byte, userID int64, mutation domain.QuickReplyMutation, excludeAuthKeyID [8]byte, excludeSessionID int64) (domain.UpdateEvent, domain.UpdateState, error)
RecordReadHistory(ctx context.Context, stateAuthKeyID [8]byte, userID int64, read domain.ReadHistoryResult, excludeAuthKeyID [8]byte, excludeSessionID int64) (domain.UpdateEvent, domain.UpdateState, error)
RecordContactsReset(ctx context.Context, stateAuthKeyID [8]byte, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64) (domain.UpdateEvent, domain.UpdateState, error)
RecordChannelState(ctx context.Context, stateAuthKeyID [8]byte, userID, channelID int64, excludeAuthKeyID [8]byte, excludeSessionID int64) (domain.UpdateEvent, domain.UpdateState, error)
RecordDialogPinned(ctx context.Context, stateAuthKeyID [8]byte, userID int64, peer domain.Peer, pinned bool, folderID int, excludeAuthKeyID [8]byte, excludeSessionID int64) (domain.UpdateEvent, domain.UpdateState, error)
RecordPinnedDialogs(ctx context.Context, stateAuthKeyID [8]byte, userID int64, folderID int, order []domain.Peer, excludeAuthKeyID [8]byte, excludeSessionID int64) (domain.UpdateEvent, domain.UpdateState, error)
RecordSavedDialogPinned(ctx context.Context, stateAuthKeyID [8]byte, userID int64, peer domain.Peer, pinned bool, excludeAuthKeyID [8]byte, excludeSessionID int64) (domain.UpdateEvent, domain.UpdateState, error)
RecordPinnedSavedDialogs(ctx context.Context, stateAuthKeyID [8]byte, userID int64, order []domain.Peer, excludeAuthKeyID [8]byte, excludeSessionID int64) (domain.UpdateEvent, domain.UpdateState, error)
RecordDialogUnreadMark(ctx context.Context, stateAuthKeyID [8]byte, userID int64, peer domain.Peer, unread bool, excludeAuthKeyID [8]byte, excludeSessionID int64) (domain.UpdateEvent, domain.UpdateState, error)
RecordPeerSettings(ctx context.Context, stateAuthKeyID [8]byte, userID int64, peer domain.Peer, settings domain.PeerSettings, excludeAuthKeyID [8]byte, excludeSessionID int64) (domain.UpdateEvent, domain.UpdateState, error)
RecordPeerStoryBlocked(ctx context.Context, stateAuthKeyID [8]byte, userID int64, peer domain.Peer, blocked bool, excludeAuthKeyID [8]byte, excludeSessionID int64) (domain.UpdateEvent, domain.UpdateState, error)
RecordDialogFilter(ctx context.Context, stateAuthKeyID [8]byte, userID int64, folderID int, folder *domain.DialogFolder, excludeAuthKeyID [8]byte, excludeSessionID int64) (domain.UpdateEvent, domain.UpdateState, error)
RecordDialogFilterOrder(ctx context.Context, stateAuthKeyID [8]byte, userID int64, order []int, excludeAuthKeyID [8]byte, excludeSessionID int64) (domain.UpdateEvent, domain.UpdateState, error)
RecordDialogFiltersReload(ctx context.Context, stateAuthKeyID [8]byte, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64) (domain.UpdateEvent, domain.UpdateState, error)
RecordFolderPeers(ctx context.Context, stateAuthKeyID [8]byte, userID int64, peers []domain.FolderPeerUpdate, excludeAuthKeyID [8]byte, excludeSessionID int64) (domain.UpdateEvent, domain.UpdateState, error)
RecordChannelAvailableMessages(ctx context.Context, stateAuthKeyID [8]byte, userID, channelID int64, availableMinID int, excludeAuthKeyID [8]byte, excludeSessionID int64) (domain.UpdateEvent, domain.UpdateState, error)
RecordChannelViewForumAsMessages(ctx context.Context, stateAuthKeyID [8]byte, userID, channelID int64, enabled bool, excludeAuthKeyID [8]byte, excludeSessionID int64) (domain.UpdateEvent, domain.UpdateState, error)
RecordChannelDiscussionInbox(ctx context.Context, stateAuthKeyID [8]byte, userID, channelID int64, topicID, maxID int, excludeAuthKeyID [8]byte, excludeSessionID int64) (domain.UpdateEvent, domain.UpdateState, error)
RecordDraftMessage(ctx context.Context, stateAuthKeyID [8]byte, userID int64, peer domain.Peer, topMsgID int, excludeAuthKeyID [8]byte, excludeSessionID int64) (domain.UpdateEvent, domain.UpdateState, error)
}
// UserEmojiStatusUpdatesService is the optional durable settings-update
// extension used by account.updateEmojiStatus. Keeping it separate preserves
// lightweight test/service implementations of the core UpdatesService.
type UserEmojiStatusUpdatesService interface {
RecordUserEmojiStatus(ctx context.Context, stateAuthKeyID [8]byte, userID int64, status domain.UserEmojiStatus, excludeAuthKeyID [8]byte, excludeSessionID int64) (domain.UpdateEvent, domain.UpdateState, error)
}
// ContactsService 抽象通讯录查询。
type ContactsService interface {
GetContacts(ctx context.Context, userID int64, hash int64) (domain.ContactList, bool, error)
ContactIDs(ctx context.Context, userID int64, hash int64) ([]int, bool, error)
AddContact(ctx context.Context, userID int64, input domain.ContactInput) (domain.Contact, error)
AcceptContact(ctx context.Context, userID, contactUserID int64) (domain.Contact, error)
ImportContacts(ctx context.Context, userID int64, inputs []domain.ContactInput) (domain.ImportContactsResult, error)
Search(ctx context.Context, userID int64, query string, limit int) (domain.UserSearchResult, error)
DeleteContacts(ctx context.Context, userID int64, contactUserIDs []int64) (int, error)
EditCloseFriends(ctx context.Context, userID int64, contactUserIDs []int64) (domain.CloseFriendsEditResult, error)
UpdateContactNote(ctx context.Context, userID, contactUserID int64, note string, entities []domain.MessageEntity) (domain.Contact, error)
SetPersonalPhoto(ctx context.Context, userID, contactUserID int64, photo domain.Photo, date int) (domain.Contact, error)
ClearPersonalPhoto(ctx context.Context, userID, contactUserID int64, date int) (domain.Contact, error)
PersonalPhotos(ctx context.Context, userID int64, contactUserIDs []int64) (map[int64]domain.ProfilePhotoRef, error)
GetPeerSettings(ctx context.Context, userID int64, peer domain.Peer) (domain.PeerSettings, error)
BlockContact(ctx context.Context, userID, peerUserID int64, date int) (bool, error)
UnblockContact(ctx context.Context, userID, peerUserID int64) (bool, error)
IsBlocked(ctx context.Context, userID, peerUserID int64) (bool, error)
GetBlocked(ctx context.Context, userID int64, offset, limit int) (domain.BlockedContactList, error)
}
// DialogsService 抽象会话列表查询。
type DialogsService interface {
GetDialogsHash(ctx context.Context, userID int64, filter domain.DialogFilter) (domain.DialogHashCheck, error)
GetDialogs(ctx context.Context, userID int64, filter domain.DialogFilter) (domain.DialogList, error)
GetPeerDialogs(ctx context.Context, userID int64, peers []domain.Peer) (domain.DialogList, error)
SaveDraft(ctx context.Context, userID int64, draft domain.DialogDraft) (bool, error)
GetDraft(ctx context.Context, userID int64, peer domain.Peer, topMessageID int) (domain.DialogDraft, bool, error)
DeleteDraft(ctx context.Context, userID int64, peer domain.Peer, topMessageID int) (bool, error)
ListDrafts(ctx context.Context, userID int64, limit int) ([]domain.DialogDraft, error)
ClearDrafts(ctx context.Context, userID int64, limit int) ([]domain.DialogDraft, error)
TogglePinned(ctx context.Context, userID int64, peer domain.Peer, pinned bool) (bool, int, error)
ToggleArchivePinned(ctx context.Context, userID int64, pinned bool) (bool, error)
ReorderPinned(ctx context.Context, userID int64, folderID int, order []domain.Peer, force bool) (bool, error)
MarkUnread(ctx context.Context, userID int64, peer domain.Peer, unread bool) (bool, error)
UnreadMarks(ctx context.Context, userID int64) ([]domain.Peer, error)
HidePeerSettingsBar(ctx context.Context, userID int64, peer domain.Peer) (bool, error)
PeerSettingsBarHidden(ctx context.Context, userID int64, peer domain.Peer) (bool, error)
GetDialogFolders(ctx context.Context, userID int64) (domain.DialogFolderList, error)
SaveDialogFolder(ctx context.Context, userID int64, folder domain.DialogFolder) error
DeleteDialogFolder(ctx context.Context, userID int64, folderID int) error
ReorderDialogFolders(ctx context.Context, userID int64, order []int) error
ToggleDialogFolderTags(ctx context.Context, userID int64, enabled bool) error
EditPeerFolders(ctx context.Context, userID int64, peers []domain.FolderPeerUpdate) error
}
// ChatlistsService 抽象 Telegram shared folders / chatlists 业务。
type ChatlistsService interface {
ExportInvite(ctx context.Context, userID int64, filterID int, title string, peers []domain.DialogFolderPeer, date int) (domain.DialogFolder, domain.ChatlistInvite, error)
ListInvites(ctx context.Context, userID int64, filterID int) ([]domain.ChatlistInvite, error)
EditInvite(ctx context.Context, userID int64, filterID int, slug string, title *string, peers *[]domain.DialogFolderPeer, revoke bool) (domain.ChatlistInvite, error)
DeleteInvite(ctx context.Context, userID int64, filterID int, slug string) (domain.DialogFolder, bool, error)
CheckInvite(ctx context.Context, userID int64, slug string) (domain.ChatlistInvitePreview, error)
JoinInvite(ctx context.Context, userID int64, slug string, peers []domain.DialogFolderPeer, date int) (domain.ChatlistJoinResult, error)
GetUpdates(ctx context.Context, userID int64, localFilterID int) (domain.ChatlistUpdates, error)
JoinUpdates(ctx context.Context, userID int64, localFilterID int, peers []domain.DialogFolderPeer, date int) (domain.ChatlistJoinResult, error)
HideUpdates(ctx context.Context, userID int64, localFilterID int) error
Leave(ctx context.Context, userID int64, localFilterID int, peers []domain.DialogFolderPeer, date int) (domain.ChatlistLeaveResult, error)
LeaveSuggestions(ctx context.Context, userID int64, localFilterID int) ([]domain.DialogFolderPeer, error)
}
// MessagesService 抽象消息历史、搜索与已读。
type MessagesService interface {
SendPrivateText(ctx context.Context, userID int64, req domain.SendPrivateTextRequest) (domain.SendPrivateTextResult, error)
SetChatTheme(ctx context.Context, userID int64, req domain.SetPrivateChatThemeRequest) (domain.SetPrivateChatThemeResult, error)
ForwardPrivateMessages(ctx context.Context, userID int64, req domain.ForwardPrivateMessagesRequest) (domain.ForwardPrivateMessagesResult, error)
GetMessages(ctx context.Context, userID int64, ids []int) (domain.MessageList, error)
GetHistory(ctx context.Context, userID int64, filter domain.MessageFilter) (domain.MessageList, error)
Search(ctx context.Context, userID int64, filter domain.MessageFilter) (domain.MessageList, error)
SearchPrivateMedia(ctx context.Context, userID, peerID int64, req domain.MediaSearchRequest) (domain.MessageList, error)
CountPrivateMediaCategories(ctx context.Context, userID, peerID int64) (domain.MediaCategoryCounts, error)
ReadHistory(ctx context.Context, userID int64, req domain.ReadHistoryRequest) (domain.ReadHistoryResult, error)
ReadMessageContents(ctx context.Context, userID int64, req domain.ReadMessageContentsRequest) (domain.ReadMessageContentsResult, error)
GetOutboxReadDate(ctx context.Context, userID int64, req domain.OutboxReadDateRequest) (int, error)
SetMessageReactions(ctx context.Context, userID int64, req domain.SetPrivateMessageReactionsRequest) (domain.PrivateMessageReactionsResult, error)
GetMessageReactions(ctx context.Context, userID int64, req domain.PrivateMessageReactionsRequest) (domain.PrivateMessageReactionsResult, error)
VoteMessagePoll(ctx context.Context, userID int64, req domain.VotePrivateMessagePollRequest) (domain.PrivateMessagePollResult, error)
CloseMessagePoll(ctx context.Context, userID int64, req domain.ClosePrivateMessagePollRequest) (domain.PrivateMessagePollResult, error)
ListUnreadReactionMessages(ctx context.Context, userID int64, peer domain.Peer, limit int) ([]domain.Message, error)
ReadPeerReactions(ctx context.Context, userID int64, peer domain.Peer) (int, error)
EditMessage(ctx context.Context, userID int64, req domain.EditMessageRequest) (domain.EditMessageResult, error)
PinPrivateMessage(ctx context.Context, userID int64, req domain.PinPrivateMessageRequest) (domain.PinPrivateMessageResult, error)
UnpinAllPrivateMessages(ctx context.Context, userID int64, req domain.UnpinAllPrivateMessagesRequest) (domain.PinPrivateMessageResult, error)
DeleteMessages(ctx context.Context, userID int64, req domain.DeleteMessagesRequest) (domain.DeleteMessagesResult, error)
DeleteHistory(ctx context.Context, userID int64, req domain.DeleteHistoryRequest) (domain.DeleteMessagesResult, error)
GetSavedDialogs(ctx context.Context, userID int64, filter domain.SavedDialogsFilter) (domain.SavedDialogList, error)
GetPinnedSavedDialogs(ctx context.Context, userID int64) (domain.SavedDialogList, error)
GetSavedDialogsByPeers(ctx context.Context, userID int64, peers []domain.Peer) (domain.SavedDialogList, error)
ToggleSavedDialogPin(ctx context.Context, userID int64, peer domain.Peer, pinned bool) (bool, error)
ReorderPinnedSavedDialogs(ctx context.Context, userID int64, order []domain.Peer, force bool) error
DeleteSavedHistory(ctx context.Context, userID int64, req domain.DeleteSavedHistoryRequest) (domain.DeleteSavedHistoryResult, error)
}
// TranslationService owns read-only translation and the durable per-account
// peer preference. It only exposes domain values to the RPC edge.
type TranslationService interface {
Translate(ctx context.Context, req domain.TranslationRequest) (domain.TranslationResult, error)
SetPeerDisabled(ctx context.Context, userID int64, peer domain.Peer, disabled bool) (bool, error)
PeerDisabled(ctx context.Context, userID int64, peer domain.Peer) (bool, error)
}
// AlbumGroupService 是 MessagesService 的可选、生产必备能力sendMultiMedia 在
// 解析任何媒体或落第一条消息前,持久预留整批 random_id 的 grouped_id。
// 单独定义可避免让不触发 sendMultiMedia 的轻量测试替身实现无关方法。
type AlbumGroupService interface {
ReserveAlbumGroup(ctx context.Context, userID int64, req domain.AlbumGroupReservationRequest) (int64, error)
}
// StoriesService 抽象 story 读取、已读、观看与 reaction 状态。
type StoriesService interface {
CreateStory(ctx context.Context, userID int64, req domain.StoryCreateRequest) (domain.StoryCreateResult, error)
GetAllStories(ctx context.Context, viewerUserID int64, hidden bool, now, limit int) (domain.StoryList, error)
GetAllStoriesPage(ctx context.Context, viewerUserID int64, hidden bool, now int, cursor domain.StoryListCursor, limit int) (domain.StoryList, error)
GetAllStoriesDigest(ctx context.Context, viewerUserID int64, hidden bool, now int) (domain.StoryListDigest, error)
ListOwnerActiveStories(ctx context.Context, userID int64, owner domain.Peer, now, limit int) (domain.StoryList, error)
GetPeerStories(ctx context.Context, viewerUserID int64, peer domain.Peer, now int) (domain.PeerStories, error)
GetStoriesByID(ctx context.Context, viewerUserID int64, peer domain.Peer, ids []int, now int) (domain.StoryList, error)
GetStoriesArchive(ctx context.Context, viewerUserID int64, peer domain.Peer, offsetID, limit, now int) (domain.StoryList, error)
GetPinnedStories(ctx context.Context, viewerUserID int64, peer domain.Peer, offsetID, limit, now int) (domain.StoryList, error)
HasPinnedStories(ctx context.Context, viewerUserID int64, peer domain.Peer, now int) (bool, error)
ListReadStates(ctx context.Context, viewerUserID int64) ([]domain.StoryReadState, error)
GetPeerMaxIDs(ctx context.Context, viewerUserID int64, peers []domain.Peer, now int) ([]domain.RecentStory, error)
GetPeerHiddenStates(ctx context.Context, viewerUserID int64, peers []domain.Peer) (map[domain.Peer]bool, error)
GetPeerStoryProjections(ctx context.Context, viewerUserID int64, peers []domain.Peer, now int) ([]domain.PeerStoryProjection, error)
ReadStories(ctx context.Context, viewerUserID int64, peer domain.Peer, maxID, date int) (domain.StoryReadResult, error)
IncrementViews(ctx context.Context, viewerUserID int64, peer domain.Peer, ids []int, date int) (int, error)
SendReaction(ctx context.Context, viewerUserID int64, peer domain.Peer, storyID int, reaction *domain.MessageReaction, date int) (domain.StoryReactionResult, error)
GetStoryViewsList(ctx context.Context, viewerUserID int64, req domain.StoryViewListRequest) (domain.StoryViewList, error)
GetStoryReactionsList(ctx context.Context, viewerUserID int64, req domain.StoryReactionListRequest) (domain.StoryReactionList, error)
GetStoryPublicForwards(ctx context.Context, viewerUserID int64, req domain.StoryPublicForwardListRequest) (domain.StoryPublicForwardList, error)
CanViewStoryStats(ctx context.Context, userID int64, peer domain.Peer) error
ListStoryViewerIDs(ctx context.Context, userID int64, owner domain.Peer, storyID, limit int) ([]int64, error)
EditStory(ctx context.Context, userID int64, req domain.StoryEditRequest) (domain.StoryEditResult, error)
DeleteStories(ctx context.Context, userID int64, peer domain.Peer, ids []int, date int) (domain.StoryMutationResult, error)
TogglePinned(ctx context.Context, userID int64, peer domain.Peer, ids []int, pinned bool, date int) (domain.StoryMutationResult, error)
TogglePinnedToTop(ctx context.Context, userID int64, peer domain.Peer, ids []int) error
TogglePeerStoriesHidden(ctx context.Context, viewerUserID int64, peer domain.Peer, hidden bool) error
CanSendStory(ctx context.Context, viewerUserID int64, peer domain.Peer) (int, error)
}
// ChannelsService 抽象超级群/频道业务。
type ChannelsService interface {
CreateMegagroupFromCreateChat(ctx context.Context, userID int64, req domain.CreateChannelRequest) (domain.CreateChannelResult, error)
CreateChannel(ctx context.Context, userID int64, req domain.CreateChannelRequest) (domain.CreateChannelResult, error)
GetChannel(ctx context.Context, userID, channelID int64) (domain.ChannelView, error)
// ResolveChannel 是 GetChannel 的轻量版(仅访问校验 + Channel/Self跳过 dialog/boost
// 供 inputPeerFor 等只需 access_hash / 频道标志的解析路径用。
ResolveChannel(ctx context.Context, userID, channelID int64) (domain.ChannelView, error)
GetChannels(ctx context.Context, userID int64, channelIDs []int64) ([]domain.ChannelView, error)
GetJoinableChannel(ctx context.Context, userID, channelID int64) (domain.Channel, error)
GetParticipants(ctx context.Context, userID, channelID int64, filter domain.ChannelParticipantsFilter, offset, limit int) (domain.ChannelParticipantList, error)
GetParticipant(ctx context.Context, userID, channelID, participantUserID int64) (domain.ChannelMember, error)
FutureCreatorAfterLeave(ctx context.Context, userID, channelID int64) (domain.ChannelMember, error)
InviteToChannel(ctx context.Context, userID, channelID int64, userIDs []int64, date int) (domain.CreateChannelResult, error)
JoinChannel(ctx context.Context, userID, channelID int64, date int) (domain.CreateChannelResult, error)
LeaveChannel(ctx context.Context, userID, channelID int64, date int) (domain.CreateChannelResult, error)
EditTitle(ctx context.Context, userID int64, req domain.EditChannelTitleRequest) (domain.EditChannelTitleResult, error)
SetWallpaper(ctx context.Context, userID int64, req domain.SetChannelWallpaperRequest) (domain.SetChannelWallpaperResult, error)
EditAbout(ctx context.Context, userID int64, req domain.EditChannelAboutRequest) (domain.Channel, error)
EditAdmin(ctx context.Context, userID int64, req domain.EditChannelAdminRequest) (domain.EditChannelAdminResult, error)
TransferOwnership(ctx context.Context, userID int64, req domain.TransferChannelOwnershipRequest) (domain.TransferChannelOwnershipResult, error)
EditMemberRank(ctx context.Context, userID int64, req domain.EditChannelMemberRankRequest) (domain.EditChannelAdminResult, error)
EditBanned(ctx context.Context, userID int64, req domain.EditChannelBannedRequest) (domain.EditChannelBannedResult, error)
EditDefaultBannedRights(ctx context.Context, userID int64, req domain.EditChannelDefaultBannedRightsRequest) (domain.Channel, error)
DeleteChannel(ctx context.Context, userID int64, req domain.DeleteChannelRequest) (domain.DeleteChannelResult, error)
CheckUsername(ctx context.Context, userID, channelID int64, username string) (bool, error)
UpdateUsername(ctx context.Context, userID int64, req domain.UpdateChannelUsernameRequest) (domain.Channel, error)
ListAdminedPublicChannels(ctx context.Context, userID int64) ([]domain.Channel, error)
ListCommunityLinkableChannels(ctx context.Context, userID int64) ([]domain.Channel, error)
ListStoryPostableChannels(ctx context.Context, userID int64) ([]domain.Channel, error)
ListSendAsChannels(ctx context.Context, userID int64) ([]domain.Channel, error)
ResolvePublicUsername(ctx context.Context, userID int64, username string) (domain.Channel, bool, error)
SearchPublicChannels(ctx context.Context, userID int64, query string, limit int) (domain.PublicChannelSearchResult, error)
SetSignatures(ctx context.Context, userID, channelID int64, enabled bool) (domain.Channel, error)
SetPhoto(ctx context.Context, userID, channelID int64, photo *domain.Photo, date int) (domain.SetChannelPhotoResult, error)
SetPreHistoryHidden(ctx context.Context, userID, channelID int64, enabled bool) (domain.Channel, error)
SetParticipantsHidden(ctx context.Context, userID, channelID int64, enabled bool) (domain.Channel, error)
SetForum(ctx context.Context, userID, channelID int64, enabled, tabs bool) (domain.Channel, error)
SetAutotranslation(ctx context.Context, userID, channelID int64, enabled bool) (domain.Channel, error)
SetRestrictedSponsored(ctx context.Context, userID, channelID int64, restricted bool) (domain.Channel, error)
SetPaidMessagesPrice(ctx context.Context, userID, channelID int64, stars int64, broadcastMessagesAllowed bool) (domain.ChannelPaidMessagesPriceResult, error)
SetAntiSpam(ctx context.Context, userID, channelID int64, enabled bool) (domain.Channel, error)
SetSlowMode(ctx context.Context, userID, channelID int64, seconds int) (domain.Channel, error)
SetBoostsToUnblockRestrictions(ctx context.Context, userID, channelID int64, boosts int) (domain.Channel, error)
SetNoForwards(ctx context.Context, userID, channelID int64, enabled bool) (domain.Channel, error)
SetJoinToSend(ctx context.Context, userID, channelID int64, enabled bool) (domain.Channel, error)
SetJoinRequest(ctx context.Context, userID, channelID int64, enabled bool) (domain.Channel, error)
SetAvailableReactions(ctx context.Context, userID, channelID int64, policy domain.ChannelReactionPolicy) (domain.Channel, error)
SetColor(ctx context.Context, userID, channelID int64, forProfile bool, color domain.ChannelPeerColor) (domain.Channel, error)
SetEmojiStatus(ctx context.Context, userID, channelID int64, status domain.ChannelEmojiStatus) (domain.Channel, error)
ListAdminLog(ctx context.Context, userID int64, req domain.ChannelAdminLogRequest) (domain.ChannelAdminLogResult, error)
GetChannelForChangeInfo(ctx context.Context, userID, channelID int64) (domain.ChannelView, error)
SaveDefaultSendAs(ctx context.Context, userID int64, req domain.SaveChannelDefaultSendAsRequest) (domain.ChannelView, error)
GetMessageViews(ctx context.Context, userID int64, req domain.ChannelMessageViewsRequest) (domain.ChannelMessageViewsResult, error)
SetMessageReactions(ctx context.Context, userID int64, req domain.SetChannelMessageReactionsRequest) (domain.ChannelMessageReactionsResult, error)
GetMessageReactions(ctx context.Context, userID int64, req domain.ChannelMessageReactionsRequest) (domain.ChannelMessageReactionsResult, error)
VoteMessagePoll(ctx context.Context, userID int64, req domain.VoteChannelMessagePollRequest) (domain.ChannelMessagePollResult, error)
CloseMessagePoll(ctx context.Context, userID int64, req domain.CloseChannelMessagePollRequest) (domain.ChannelMessagePollResult, error)
ListMessageReactions(ctx context.Context, userID int64, req domain.ChannelMessageReactionsListRequest) (domain.ChannelMessageReactionsList, error)
FindMessageReaction(ctx context.Context, userID int64, req domain.ChannelMessageReactionLookupRequest) (domain.ChannelMessageReactionLookup, bool, error)
TopReactions(ctx context.Context, userID int64, limit int) ([]domain.MessageReaction, error)
RecentReactions(ctx context.Context, userID int64, limit int) ([]domain.MessageReaction, error)
ClearRecentReactions(ctx context.Context, userID int64) error
SavedReactionTags(ctx context.Context, userID int64, limit int) ([]domain.SavedReactionTag, error)
UpdateSavedReactionTag(ctx context.Context, userID int64, tag domain.SavedReactionTag) error
GetPremiumBoostStatus(ctx context.Context, userID, channelID int64, now int) (domain.PremiumBoostStatus, error)
ListPremiumBoosts(ctx context.Context, userID, channelID int64, gifts bool, offset string, limit, now int) (domain.PremiumBoostList, error)
GetPremiumMyBoosts(ctx context.Context, userID int64, now, premiumUntil int) (domain.PremiumMyBoosts, error)
ApplyPremiumBoost(ctx context.Context, userID, channelID int64, slots []int, now, premiumUntil int) (domain.PremiumMyBoosts, error)
GetPremiumUserBoosts(ctx context.Context, userID, channelID, targetUserID int64, now int) (domain.PremiumBoostList, error)
ReadMessageContents(ctx context.Context, userID int64, req domain.ReadChannelMessageContentsRequest) (domain.ReadChannelMessageContentsResult, error)
GetMessageAuthor(ctx context.Context, userID int64, req domain.GetChannelMessageAuthorRequest) (domain.GetChannelMessageAuthorResult, error)
CreateForumTopic(ctx context.Context, userID int64, req domain.CreateChannelForumTopicRequest) (domain.CreateChannelForumTopicResult, error)
EditForumTopic(ctx context.Context, userID int64, req domain.EditChannelForumTopicRequest) (domain.EditChannelForumTopicResult, error)
UpdatePinnedForumTopic(ctx context.Context, userID int64, req domain.UpdateChannelForumTopicPinnedRequest) (domain.UpdateChannelForumTopicPinnedResult, error)
ReorderPinnedForumTopics(ctx context.Context, userID int64, req domain.ReorderChannelPinnedForumTopicsRequest) (domain.ReorderChannelPinnedForumTopicsResult, error)
DeleteForumTopicHistory(ctx context.Context, userID int64, req domain.DeleteChannelForumTopicHistoryRequest) (domain.DeleteChannelHistoryResult, error)
GetForumTopics(ctx context.Context, userID int64, filter domain.ChannelForumTopicFilter) (domain.ChannelForumTopicList, error)
GetForumTopicsByID(ctx context.Context, userID, channelID int64, ids []int) (domain.ChannelForumTopicList, error)
SendMessage(ctx context.Context, userID int64, req domain.SendChannelMessageRequest) (domain.SendChannelMessageResult, error)
EditMessage(ctx context.Context, userID int64, req domain.EditChannelMessageRequest) (domain.EditChannelMessageResult, error)
GetInlineBotMessage(ctx context.Context, botID, channelID int64, id int) (domain.Channel, domain.ChannelMessage, bool, error)
ListStoryMessageForwards(ctx context.Context, userID int64, req domain.StoryMessageForwardListRequest) (domain.StoryMessageForwardList, error)
EditInlineBotMessage(ctx context.Context, botID int64, req domain.EditChannelMessageRequest) (domain.EditChannelMessageResult, error)
DeleteMessages(ctx context.Context, userID int64, req domain.DeleteChannelMessagesRequest) (domain.DeleteChannelMessagesResult, error)
DeleteHistory(ctx context.Context, userID int64, req domain.DeleteChannelHistoryRequest) (domain.DeleteChannelHistoryResult, error)
DeleteParticipantHistory(ctx context.Context, userID int64, req domain.DeleteChannelParticipantHistoryRequest) (domain.DeleteChannelHistoryResult, error)
UpdatePinnedMessage(ctx context.Context, userID int64, req domain.UpdateChannelPinnedMessageRequest) (domain.UpdateChannelPinnedMessageResult, error)
UnpinAllMessages(ctx context.Context, userID int64, req domain.UnpinAllChannelMessagesRequest) (domain.UpdateChannelPinnedMessageResult, error)
ClearDanglingPinnedMessage(ctx context.Context, channelID int64, messageID int) error
ExportInvite(ctx context.Context, userID int64, req domain.ExportChannelInviteRequest) (domain.ExportChannelInviteResult, error)
CheckInvite(ctx context.Context, userID int64, hash string, date int) (domain.CheckChannelInviteResult, error)
ImportInvite(ctx context.Context, userID int64, req domain.ImportChannelInviteRequest) (domain.CreateChannelResult, error)
ListExportedInvites(ctx context.Context, userID int64, req domain.ChannelInviteListRequest) (domain.ChannelInviteList, error)
GetExportedInvite(ctx context.Context, userID int64, req domain.GetChannelInviteRequest) (domain.ChannelInvite, error)
EditExportedInvite(ctx context.Context, userID int64, req domain.EditChannelInviteRequest) (domain.EditChannelInviteResult, error)
DeleteExportedInvite(ctx context.Context, userID int64, req domain.DeleteChannelInviteRequest) error
DeleteRevokedExportedInvites(ctx context.Context, userID int64, req domain.DeleteRevokedChannelInvitesRequest) error
ListAdminsWithInvites(ctx context.Context, userID, channelID int64) ([]domain.ChannelAdminInviteCount, error)
ListInviteImporters(ctx context.Context, userID int64, req domain.ChannelInviteImportersRequest) (domain.ChannelInviteImporterList, error)
PendingJoinRequests(ctx context.Context, channelID int64, limit int) (domain.ChannelPendingJoinRequests, error)
HideChatJoinRequest(ctx context.Context, userID int64, req domain.HideChannelJoinRequestRequest) (domain.CreateChannelResult, error)
HideAllChatJoinRequests(ctx context.Context, userID int64, req domain.HideChannelJoinRequestsRequest) (domain.CreateChannelResult, error)
CommonChannels(ctx context.Context, userID int64, req domain.CommonChannelsRequest) (domain.CommonChannelsResult, error)
LeftChannels(ctx context.Context, userID int64, offset, limit int) (domain.LeftChannelsResult, error)
InactiveChannels(ctx context.Context, userID int64, limit int) (domain.ChannelDialogList, error)
ChannelRecommendations(ctx context.Context, userID int64, req domain.ChannelRecommendationsRequest) (domain.ChannelRecommendationsResult, error)
DiscussionGroups(ctx context.Context, userID int64, limit int) ([]domain.Channel, error)
SetDiscussionGroup(ctx context.Context, userID, broadcastID, groupID int64) (domain.DiscussionGroupUpdateResult, error)
SetViewForumAsMessages(ctx context.Context, userID, channelID int64, enabled bool) (bool, error)
GetHistory(ctx context.Context, userID int64, filter domain.ChannelHistoryFilter) (domain.ChannelHistory, error)
SearchChannelMedia(ctx context.Context, userID, channelID int64, req domain.MediaSearchRequest) (domain.ChannelHistory, error)
CountChannelMediaCategories(ctx context.Context, userID, channelID int64) (domain.MediaCategoryCounts, error)
SearchPosts(ctx context.Context, userID int64, req domain.ChannelSearchPostsRequest) (domain.ChannelHistory, error)
SearchJoinedMessages(ctx context.Context, userID int64, req domain.ChannelGlobalSearchRequest) (domain.ChannelHistory, error)
GetMessages(ctx context.Context, userID, channelID int64, ids []int) (domain.ChannelHistory, error)
ChannelPollFanoutViews(ctx context.Context, channelID int64, msgID int, viewers []int64, now int) (map[int64]*domain.MessagePoll, error)
GetReplies(ctx context.Context, userID int64, filter domain.ChannelRepliesFilter) (domain.ChannelHistory, error)
GetUnreadMentions(ctx context.Context, userID int64, filter domain.ChannelUnreadMentionsFilter) (domain.ChannelHistory, error)
ReadMentions(ctx context.Context, userID int64, req domain.ReadChannelMentionsRequest) (domain.ReadChannelMentionsResult, error)
GetUnreadReactions(ctx context.Context, userID int64, filter domain.ChannelUnreadReactionsFilter) (domain.ChannelHistory, error)
ReadReactions(ctx context.Context, userID int64, req domain.ReadChannelReactionsRequest) (domain.ReadChannelReactionsResult, error)
GetDiscussionMessage(ctx context.Context, userID, channelID int64, msgID int) (domain.ChannelDiscussionMessage, error)
SendMonoforumMessage(ctx context.Context, req domain.SendMonoforumMessageRequest) (domain.SendChannelMessageResult, error)
ListMonoforumHistory(ctx context.Context, filter domain.MonoforumHistoryFilter) (domain.ChannelHistory, error)
ListMonoforumDialogs(ctx context.Context, filter domain.MonoforumDialogsFilter) (domain.MonoforumDialogList, error)
ResolveMonoforumSend(ctx context.Context, viewerUserID, monoforumID int64) (domain.Channel, bool, error)
ReadHistory(ctx context.Context, userID int64, req domain.ReadChannelHistoryRequest) (domain.ReadChannelHistoryResult, error)
ReadTopicHistory(ctx context.Context, userID int64, req domain.ReadChannelTopicHistoryRequest) (domain.ReadChannelTopicHistoryResult, error)
GeneralForumTopic(ctx context.Context, userID, channelID int64) (domain.ChannelForumTopic, error)
GetMessageReadParticipants(ctx context.Context, userID int64, req domain.ChannelReadParticipantsRequest) (domain.ChannelReadParticipantsResult, error)
GetDifference(ctx context.Context, userID int64, req domain.ChannelDifferenceRequest) (domain.ChannelDifference, error)
ActiveChannelIDsForUser(ctx context.Context, userID, afterChannelID int64, limit int) ([]int64, error)
DirtyActiveChannelsForUser(ctx context.Context, userID int64, sinceDate int, afterChannelID int64, limit int) ([]domain.DirtyChannel, error)
ActiveMemberIDs(ctx context.Context, userID, channelID int64, limit int) ([]int64, error)
// SetActiveCall / AppendCallServiceMessage 是群通话模块的频道侧挂接点。
SetActiveCall(ctx context.Context, channelID, callID, callAccessHash int64, notEmpty bool) (domain.Channel, error)
AppendCallServiceMessage(ctx context.Context, channelID, senderUserID int64, date int, action domain.ChannelMessageAction) (domain.SendChannelMessageResult, error)
AppendStarGiftAdminLog(ctx context.Context, channelID, senderUserID int64, savedID int64, date int, action domain.ChannelMessageAction) error
InviteAdminMemberIDs(ctx context.Context, channelID int64, limit int) ([]int64, error)
FilterActiveMemberIDs(ctx context.Context, channelID int64, userIDs []int64) ([]int64, error)
}
// ChannelAuthoritativeProjectionService bypasses long-lived channel read
// models for a durable channel_state refresh emitted by an admin mutation.
type ChannelAuthoritativeProjectionService interface {
GetChannelsAuthoritative(ctx context.Context, userID int64, channelIDs []int64) ([]domain.ChannelView, error)
}
// CommunitiesService abstracts the Layer 228 Community aggregation domain.
// Community containers never expose tg types and never own message/read/pts state.
type CommunitiesService interface {
Create(ctx context.Context, userID int64, req domain.CreateCommunityRequest) (domain.CommunityView, error)
Get(ctx context.Context, userID, communityID int64) (domain.CommunityView, error)
GetMany(ctx context.Context, userID int64, ids []int64) ([]domain.CommunityView, error)
ListJoined(ctx context.Context, userID int64) ([]domain.CommunityView, error)
TogglePeerLink(ctx context.Context, userID int64, req domain.CommunityTogglePeerLinkRequest) (domain.CommunityTogglePeerLinkResult, error)
SetCollapsed(ctx context.Context, userID, communityID int64, collapsed bool) (domain.CommunityView, bool, error)
ListPeerLinkRequests(ctx context.Context, userID, communityID int64, offset string, limit int) (domain.CommunityPeerLinkRequestPage, error)
DecidePeerLinkRequest(ctx context.Context, userID, communityID int64, peer domain.Peer, reject bool, date int) (domain.CommunityTogglePeerLinkResult, error)
DecideAllPeerLinkRequests(ctx context.Context, userID, communityID int64, reject bool, date int) ([]domain.CommunityTogglePeerLinkResult, error)
ToggleParticipantBanned(ctx context.Context, userID, communityID, participantUserID int64, unban bool, date int) (domain.CommunityParticipantBanResult, error)
ParticipantJoinedChats(ctx context.Context, userID, communityID, participantUserID int64) (domain.CommunityParticipantJoinedChats, error)
Participants(ctx context.Context, userID, communityID int64, filter domain.ChannelParticipantsFilter, offset, limit int) (domain.CommunityParticipantList, error)
EditTitle(ctx context.Context, userID, communityID int64, title string) (domain.CommunityView, bool, error)
EditAbout(ctx context.Context, userID, communityID int64, about string) (domain.CommunityView, bool, error)
EditAdmin(ctx context.Context, userID int64, req domain.CommunityEditAdminRequest) (domain.CommunityView, bool, error)
EditDefaultBannedRights(ctx context.Context, userID, communityID int64, rights domain.ChannelBannedRights) (domain.CommunityView, bool, error)
SetPhoto(ctx context.Context, userID, communityID int64, photo *domain.Photo, date int) (domain.CommunityView, bool, error)
Delete(ctx context.Context, userID, communityID int64, date int) (domain.CommunityView, []domain.Peer, error)
SetPinned(ctx context.Context, userID, communityID int64, pinned bool) (bool, error)
ReorderPinned(ctx context.Context, userID int64, order []domain.Peer, force bool) (bool, error)
SearchScope(ctx context.Context, userID, communityID int64) (domain.CommunitySearchScope, error)
}
// FilesService 抽象文件上传分片、下载与媒体document/photo组装。
// 方法只用 domain 类型rpc 层负责 tg.InputFileLocation / InputMedia ↔ domain 转换。
type FilesService interface {
SaveFilePart(ctx context.Context, ownerUserID, fileID int64, part int, bytes []byte) (bool, error)
SaveBigFilePart(ctx context.Context, ownerUserID, fileID int64, part, totalParts int, bytes []byte) (bool, error)
GetFile(ctx context.Context, req domain.FileDownloadRequest) (domain.FileChunk, bool, error)
// CreateEncryptedFileFromUpload 把密聊上传分片组装成盲 blob 并铸造 EncryptedFile 快照P2
CreateEncryptedFileFromUpload(ctx context.Context, file domain.UploadedFileRef, keyFingerprint int) (domain.EncryptedFileRef, error)
// GeoMapTile 渲染 geo 消息地图缩略占位图upload.getWebFile确定性、无外部依赖。
GeoMapTile(lat, long float64, w, h, zoom, scale int) ([]byte, string)
// 资源读取reaction / sticker / document
ListAvailableReactions(ctx context.Context) ([]domain.AvailableReaction, error)
AvailableEffects(ctx context.Context) ([]domain.AvailableEffect, int, error)
GetDocuments(ctx context.Context, ids []int64) ([]domain.Document, error)
ResolveStickerSet(ctx context.Context, ref domain.StickerSetRef) (set domain.StickerSet, documents []domain.Document, found bool, err error)
ListStickerSets(ctx context.Context, kind domain.StickerSetKind) ([]domain.StickerSet, error)
CheckStickerSetShortName(ctx context.Context, shortName string) (bool, error)
SuggestStickerSetShortName(ctx context.Context, title string, userID int64) (string, error)
CreateStickerSet(ctx context.Context, req domain.CreateStickerSetRequest) (domain.StickerSet, []domain.Document, error)
ListCreatedStickerSets(ctx context.Context, userID int64, offsetID int64, limit int) ([]domain.StickerSet, int, error)
AddStickerToSet(ctx context.Context, actorUserID int64, ref domain.StickerSetRef, item domain.StickerSetItemInput) (domain.StickerSet, []domain.Document, error)
RemoveStickerFromSet(ctx context.Context, actorUserID int64, documentID int64, accessHash int64) (domain.StickerSet, []domain.Document, error)
ChangeStickerPosition(ctx context.Context, actorUserID int64, documentID int64, accessHash int64, position int) (domain.StickerSet, []domain.Document, error)
RenameStickerSet(ctx context.Context, actorUserID int64, ref domain.StickerSetRef, title string) (domain.StickerSet, []domain.Document, error)
DeleteStickerSet(ctx context.Context, actorUserID int64, ref domain.StickerSetRef) (domain.StickerSetKind, error)
// 头像profile photo与消息媒体组装。
CreatePhotoFromUpload(ctx context.Context, file domain.UploadedFileRef) (domain.Photo, error)
CreatePhotoFromBytes(ctx context.Context, data []byte) (domain.Photo, error)
// CreatePhotoFromURL / CreateDocumentFromURL 抓取外链媒体inputMediaPhoto/DocumentExternal
// SSRF 安全;未启用返回 ErrExternalMediaDisabled。
CreatePhotoFromURL(ctx context.Context, rawURL string) (domain.Photo, error)
CreateDocumentFromURL(ctx context.Context, rawURL string) (domain.Document, error)
// ResolveWebPage 解析链接预览messages.getWebPagePreview / 发送挂卡片SSRF 安全,
// 经 L1+L3 去重缓存。未启用返回 ErrWebPagePreviewDisabled瞬时失败返回错误调用方降级
ResolveWebPage(ctx context.Context, rawURL string) (domain.MessageWebPage, error)
// WebPagePreviewEnabled 报告是否启用链接预览;未启用时发送不挂 pending 占位(否则会永久 pending
WebPagePreviewEnabled() bool
// LookupWebPage 仅查缓存(不抓取)返回已解析的链接预览。发送时用它:若客户端输入时
// getWebPagePreview 已解析过,则 echo 直接带 done 卡片(与官方一致),不依赖异步换卡。
LookupWebPage(ctx context.Context, rawURL string) (domain.MessageWebPage, bool)
CreateAvatarFromUpload(ctx context.Context, file domain.UploadedFileRef) (domain.Photo, error)
CreateAvatarVideoFromUpload(ctx context.Context, file domain.UploadedFileRef, videoStartTs float64) (domain.Photo, error)
CreateAvatarVideoMarkupFromUpload(ctx context.Context, file domain.UploadedFileRef, videoStartTs float64, markup domain.PhotoSize) (domain.Photo, error)
CreateAvatarMarkup(ctx context.Context, size domain.PhotoSize) (domain.Photo, error)
CreateDocumentFromUpload(ctx context.Context, file domain.UploadedFileRef, spec domain.DocumentSpec) (domain.Document, error)
CreateDocumentFromBytes(ctx context.Context, data []byte, spec domain.DocumentSpec) (domain.Document, error)
GetPhoto(ctx context.Context, id int64) (domain.Photo, bool, error)
GetDocument(ctx context.Context, id int64) (domain.Document, bool, error)
UploadProfilePhoto(ctx context.Context, ownerType domain.PeerType, ownerID int64, file domain.UploadedFileRef, date int) (domain.Photo, error)
UploadProfilePhotoKind(ctx context.Context, ownerType domain.PeerType, ownerID int64, kind domain.ProfilePhotoKind, file domain.UploadedFileRef, date int) (domain.Photo, error)
SetCurrentProfilePhoto(ctx context.Context, ownerType domain.PeerType, ownerID, photoID int64, date int) (domain.Photo, bool, error)
SetCurrentProfilePhotoKind(ctx context.Context, ownerType domain.PeerType, ownerID int64, kind domain.ProfilePhotoKind, photoID int64, date int) (domain.Photo, bool, error)
CurrentProfilePhoto(ctx context.Context, ownerType domain.PeerType, ownerID int64) (domain.Photo, bool, error)
CurrentProfilePhotoKind(ctx context.Context, ownerType domain.PeerType, ownerID int64, kind domain.ProfilePhotoKind) (domain.Photo, bool, error)
GetProfilePhotos(ctx context.Context, ownerType domain.PeerType, ownerID int64, offset, limit int, maxID int64) (photos []domain.Photo, total int, err error)
GetProfilePhotosKind(ctx context.Context, ownerType domain.PeerType, ownerID int64, kind domain.ProfilePhotoKind, offset, limit int, maxID int64) (photos []domain.Photo, total int, err error)
DeleteProfilePhotos(ctx context.Context, ownerType domain.PeerType, ownerID int64, photoIDs []int64) (int, error)
DeleteProfilePhotosKind(ctx context.Context, ownerType domain.PeerType, ownerID int64, kind domain.ProfilePhotoKind, photoIDs []int64) (int, error)
}
// LangPackService 抽象客户端语言包查询。
type LangPackService interface {
GetLangPack(ctx context.Context, langPack, langCode string) (domain.LangPack, error)
GetDifference(ctx context.Context, langPack, langCode string, fromVersion int) (domain.LangPack, error)
GetStrings(ctx context.Context, langPack, langCode string, keys []string) (domain.LangPack, error)
ListLanguages(ctx context.Context, langPack string) ([]domain.LangPackLanguage, error)
}
// AIComposeService 抽象客户端输入框 AI 改写/润色与 aicompose tones 目录。
// 这里只使用 domain DTOrpc 层负责 tg.TextWithEntities/InputAiComposeTone ↔ domain 转换。
type AIComposeService interface {
ListTones(ctx context.Context, userID, hash int64) (domain.AIComposeTones, bool, error)
GetTone(ctx context.Context, userID int64, ref domain.AIComposeToneRef) (domain.AIComposeTones, error)
CreateTone(ctx context.Context, input domain.AIComposeToneInput) (domain.AIComposeTone, error)
UpdateTone(ctx context.Context, update domain.AIComposeToneUpdate) (domain.AIComposeTone, error)
SaveTone(ctx context.Context, userID int64, ref domain.AIComposeToneRef, unsave bool) error
DeleteTone(ctx context.Context, userID int64, ref domain.AIComposeToneRef) error
GetToneExample(ctx context.Context, userID int64, ref domain.AIComposeToneRef, num int) (domain.AIComposeToneExample, error)
Compose(ctx context.Context, req domain.AIComposeRequest) (domain.AIComposeResult, error)
}
// EphemeralService owns Layer 228 short-lived bot/member state. It must never
// write ordinary messages, dialogs, pts/qts/seq logs or durable update outbox.
type EphemeralService interface {
SendFromClient(ctx context.Context, request domain.SendClientEphemeralRequest) (domain.EphemeralMessage, bool, error)
SendFromBot(ctx context.Context, request domain.SendBotEphemeralRequest) (domain.EphemeralMessage, bool, error)
SendFromBotLazy(ctx context.Context, request domain.SendBotEphemeralRequest, build func(context.Context) (domain.EphemeralContent, error)) (domain.EphemeralMessage, bool, error)
EditFromBot(ctx context.Context, botUserID int64, peer domain.Peer, id int, content domain.EphemeralContent) (domain.EphemeralMessage, error)
EditFieldsFromBot(ctx context.Context, botUserID, receiverUserID int64, peer domain.Peer, id int, mode domain.EphemeralEditMode, fields domain.EditEphemeralFields) (domain.EphemeralMessage, error)
EditFieldsFromBotLazy(ctx context.Context, botUserID, receiverUserID int64, peer domain.Peer, id int, mode domain.EphemeralEditMode, build func(context.Context) (domain.EditEphemeralFields, error)) (domain.EphemeralMessage, error)
Delete(ctx context.Context, actorUserID, receiverUserID int64, peer domain.Peer, id int) (domain.EphemeralMessage, bool, error)
DeleteFromDevice(ctx context.Context, actorUserID, receiverUserID int64, device domain.EphemeralDevice, peer domain.Peer, id int) (domain.EphemeralMessage, bool, error)
Callback(ctx context.Context, userID int64, device domain.EphemeralDevice, peer domain.Peer, id int, data []byte) (domain.EphemeralCallback, error)
PutCallbackAction(ctx context.Context, action domain.EphemeralCallbackAction) (bool, error)
ReportTarget(ctx context.Context, userID int64, device domain.EphemeralDevice, peer domain.Peer, id int) (domain.EphemeralMessage, error)
}
// ModerationService accepts only final report choices. Implementations must
// validate and snapshot referenced evidence, then durably commit the immutable
// submission before returning success.
type ModerationService interface {
ReportPeer(ctx context.Context, reporterUserID int64, source domain.ModerationReportSource, target domain.Peer, reason domain.ModerationReason, option, comment string, createdAt time.Time) (domain.ModerationReport, bool, error)
ReportMessages(ctx context.Context, req domain.ModerationMessageReportRequest) (domain.ModerationReport, bool, error)
ReportProfilePhoto(ctx context.Context, req domain.ModerationProfilePhotoReportRequest) (domain.ModerationReport, bool, error)
ReportChannelSpam(ctx context.Context, req domain.ModerationChannelSpamReportRequest) (domain.ModerationReport, bool, error)
ReportReaction(ctx context.Context, req domain.ModerationReactionReportRequest) (domain.ModerationReport, bool, error)
ReportEncryptedSpam(ctx context.Context, reporterUserID int64, chat domain.SecretChat, createdAt time.Time) (domain.ModerationReport, bool, error)
ReportStories(ctx context.Context, req domain.ModerationStoryReportRequest) (domain.ModerationReport, bool, error)
ReportEphemeral(ctx context.Context, reporterUserID int64, target domain.EphemeralMessage, reason domain.ModerationReason, option, comment string, createdAt time.Time) (domain.ModerationReport, bool, error)
SponsoredImpression(ctx context.Context, userID int64, randomID []byte, now time.Time) (domain.SponsoredMessageImpression, error)
ReportSponsored(ctx context.Context, userID int64, randomID []byte, reason domain.ModerationReason, option string, now time.Time) (domain.ModerationReport, bool, error)
ReportAntiSpamFalsePositive(ctx context.Context, reporterUserID, channelID int64, messageID int, now time.Time) (domain.ModerationReport, bool, error)
}
// Deps 按业务域注入服务接口。各域的 handler 注册见对应文件auth.go / users.go / updates.go
type Deps struct {
Auth AuthService
AuthDeliveryReports AuthDeliveryReportService
ClientTelemetry ClientTelemetryService
// AuthKeySessionLayers is the protocol-only durable ordering boundary for
// explicit invokeWithLayer evidence. Production must wire the same auth-key
// store used by the MTProto edge; nil is reserved for isolated router tests.
AuthKeySessionLayers store.AuthKeySessionLayerStore
Account AccountService
Privacy PrivacyService
Help HelpService
AccountFreeze AccountFreezeService
AICompose AIComposeService
Ephemeral EphemeralService
EphemeralPush store.EphemeralPushBroker
Moderation ModerationService
Users UsersService
TelegramLogin TelegramLoginService
Updates UpdatesService
BootstrapUpdates store.BootstrapUpdateJobStore
BotAPIUpdates store.BotAPIUpdateStore
BotCallbacks store.BotCallbackRegistryStore
Contacts ContactsService
Dialogs DialogsService
Chatlists ChatlistsService
Messages MessagesService
Translation TranslationService
Stories StoriesService
Channels ChannelsService
Communities CommunitiesService
Files FilesService
Bots BotsService
Polls PollsService
Phone PhoneService
GroupCalls GroupCallsService
LiveStreams LiveStreamsService
SFU sfu.Service
TURN turnsrv.Service
LangPack LangPackService
Sessions SessionBinder
Inline store.InlineRegistryStore
Limiter RateLimiter
Metrics Metrics
SecretChats SecretChatService
Stars StarsService
Gifts GiftsService
Passkey PasskeyService
Themes ThemeService
}
// ThemeService 抽象自定义云主题(app/themes):创建/更新/查询主题 + 维护每用户已安装列表。
// 文件上传(uploadTheme)由 rpc 层直接经 Files 完成,不经此接口。只用 domain + 基本类型。
type ThemeService interface {
Create(ctx context.Context, spec domain.ThemeSpec) (domain.Theme, error)
Update(ctx context.Context, userID int64, ref domain.ThemeRef, upd domain.ThemeUpdate) (domain.Theme, error)
Get(ctx context.Context, ref domain.ThemeRef) (domain.Theme, bool, error)
Save(ctx context.Context, userID int64, ref domain.ThemeRef) error
Unsave(ctx context.Context, userID int64, ref domain.ThemeRef) error
Install(ctx context.Context, userID int64, ref domain.ThemeRef, dark bool) error
ListInstalled(ctx context.Context, userID int64) ([]domain.Theme, error)
ListForUser(ctx context.Context, userID int64) ([]domain.Theme, error)
}
// PasskeyService 抽象 passkey(WebAuthn)登录与管理(app/passkey)。挑战选项以 DataJSON
// 字节返回;注册/登录验证收原始字节(credentialID 已 base64url 解码)。FinishLogin 返回
// 已验证用户 id,auth_key 绑定由 rpc 经 Auth.BindVerifiedLogin 完成。
type PasskeyService interface {
InitLogin(ctx context.Context) ([]byte, error)
FinishLogin(ctx context.Context, credentialID, clientDataJSON, authenticatorData, signature []byte, userHandle string) (int64, error)
InitRegistration(ctx context.Context, userID int64, displayName string) ([]byte, error)
Register(ctx context.Context, userID int64, credentialID, clientDataJSON, attestationObject []byte, name string) (domain.PasskeyCredential, error)
List(ctx context.Context, userID int64) ([]domain.PasskeyCredential, error)
Delete(ctx context.Context, userID int64, credentialID []byte) (bool, error)
}
// GiftsService 抽象 Star 礼物app/stargifts目录 + peer 收到的礼物实例 CRUD。
// 扣费/退款/服务消息投递由 rpc 层经 Stars 账本 + Messages.SendPrivateText 编排。
type GiftsService interface {
Catalog(ctx context.Context) ([]domain.StarGift, error)
CatalogHash(ctx context.Context) (int, error)
GiftByID(ctx context.Context, id int64) (domain.StarGift, bool, error)
GiftRevisionByID(ctx context.Context, revisionID int64) (domain.StarGift, bool, error)
CollectiblePreview(ctx context.Context, giftID int64) (domain.StarGiftUpgradePreview, bool, error)
CollectibleAvailability(ctx context.Context, giftIDs []int64) (map[int64]domain.StarGiftCollectibleAvailability, error)
UniqueBySlug(ctx context.Context, slug string) (domain.UniqueStarGift, bool, error)
UniqueByID(ctx context.Context, uniqueGiftID int64) (domain.UniqueStarGift, bool, error)
UniqueByIDs(ctx context.Context, uniqueGiftIDs []int64) (map[int64]domain.UniqueStarGift, error)
ListUniqueByOwner(ctx context.Context, owner domain.Peer, limit int) ([]domain.UniqueStarGift, error)
Upgrade(ctx context.Context, req domain.StarGiftUpgradeRequest) (domain.StarGiftUpgradeResult, error)
UpgradeReceipt(ctx context.Context, userID int64, commandKey string) (domain.StarGiftUpgradeReceipt, bool, error)
RecordSavedGift(ctx context.Context, gift domain.SavedStarGift) (int64, error)
ListSaved(ctx context.Context, owner domain.Peer, excludeUnsaved bool, offset string, limit int) (domain.SavedStarGiftPage, error)
ListSavedFiltered(ctx context.Context, filter domain.SavedStarGiftFilter) (domain.SavedStarGiftPage, error)
GetSaved(ctx context.Context, ref domain.SavedStarGiftRef) (domain.SavedStarGift, bool, error)
ResolveSavedIDs(ctx context.Context, owner domain.Peer, refs []domain.SavedStarGiftRef) ([]int64, error)
CountSaved(ctx context.Context, owner domain.Peer) (int, error)
ToggleSaved(ctx context.Context, ref domain.SavedStarGiftRef, unsaved bool) (bool, error)
ConvertAggregate(ctx context.Context, req domain.StarGiftConvertRequest) (domain.StarGiftConvertResult, error)
ListCollections(ctx context.Context, owner domain.Peer) ([]domain.StarGiftCollection, error)
CreateCollection(ctx context.Context, owner domain.Peer, title string, savedGiftIDs []int64) (domain.StarGiftCollection, error)
UpdateCollection(ctx context.Context, owner domain.Peer, collectionID int, patch domain.StarGiftCollectionPatch) (domain.StarGiftCollection, error)
DeleteCollection(ctx context.Context, owner domain.Peer, collectionID int) (bool, error)
ReorderCollections(ctx context.Context, owner domain.Peer, collectionIDs []int) error
SetPinned(ctx context.Context, owner domain.Peer, savedGiftIDs []int64) error
ListResale(ctx context.Context, filter domain.StarGiftResaleFilter) (domain.StarGiftResalePage, error)
ValueInfo(ctx context.Context, uniqueGiftID int64) (domain.StarGiftValueInfo, error)
SetListing(ctx context.Context, req domain.StarGiftListingRequest) (domain.UniqueStarGift, error)
Transfer(ctx context.Context, req domain.StarGiftTransferRequest) (domain.StarGiftTransferResult, error)
PurchaseResale(ctx context.Context, req domain.StarGiftResalePurchaseRequest) (domain.StarGiftTransferResult, error)
SendOffer(ctx context.Context, req domain.StarGiftOfferRequest) (domain.StarGiftOfferResult, error)
ResolveOffer(ctx context.Context, req domain.StarGiftResolveOfferRequest) (domain.StarGiftOfferResult, error)
ListCraft(ctx context.Context, userID, giftID int64, offset string, limit int) (domain.SavedStarGiftPage, error)
Craft(ctx context.Context, req domain.StarGiftCraftRequest) (domain.StarGiftCraftResult, error)
AuctionState(ctx context.Context, userID, giftID int64, slug string, now int) (domain.StarGiftAuction, error)
ActiveAuctions(ctx context.Context, userID int64, now int) ([]domain.StarGiftAuction, error)
AuctionAcquired(ctx context.Context, userID, giftID int64) ([]domain.StarGiftAuctionAcquired, error)
BidAuction(ctx context.Context, req domain.StarGiftAuctionBidRequest) (domain.StarGiftAuction, domain.StarsBalance, error)
PrepaidUpgradeTarget(ctx context.Context, owner domain.Peer, hash string) (domain.SavedStarGift, int64, error)
PrepayUpgrade(ctx context.Context, req domain.StarGiftPrepaidUpgradeRequest) (domain.StarGiftPrepaidUpgradeResult, error)
DropOriginalDetails(ctx context.Context, req domain.StarGiftDropOriginalDetailsRequest) (domain.StarGiftDropOriginalDetailsResult, error)
SetNotifications(ctx context.Context, userID, channelID int64, enabled bool) error
Withdraw(ctx context.Context, req domain.StarGiftWithdrawalRequest) (domain.StarGiftWithdrawal, error)
TonBalance(ctx context.Context, userID int64) (int64, error)
TonTransactions(ctx context.Context, userID int64, offset string, limit int) (domain.TonTransactionPage, error)
IssuePurchaseForm(ctx context.Context, form domain.StarGiftPurchaseForm) (domain.StarGiftPurchaseForm, error)
ValidatePurchaseForm(ctx context.Context, req domain.StarGiftPurchaseRequest) error
Purchase(ctx context.Context, req domain.StarGiftPurchaseRequest) (domain.StarGiftPurchaseResult, error)
}
// StarsService 抽象 Stars 本地账本app/stars余额查询、贷记/借记、流水分页。
// 借记原子且永不为负;余额不足返回 domain.ErrStarsInsufficientrpc 经 starsErr
// 映射为 BALANCE_TOO_LOW。getStarsStatus 首读时惰性授予起始余额。
type StarsService interface {
GetBalance(ctx context.Context, userID int64) (domain.StarsBalance, error)
Credit(ctx context.Context, userID, amount int64, reason domain.StarsTransactionReason, peer domain.Peer, title, desc string) (domain.StarsBalance, error)
Debit(ctx context.Context, userID, amount int64, reason domain.StarsTransactionReason, peer domain.Peer, title, desc string) (domain.StarsBalance, error)
ListTransactions(ctx context.Context, userID int64, offset string, limit int) (domain.StarsTransactionPage, error)
}
// SecretChatService 抽象私聊端对端加密Secret Chat握手状态机app/secretchat
// 服务端是盲中继;错误集合见 domain.ErrSecretChat* 与 app/secretchat.ErrGAInvalid
// rpc 层经 secretChatErr 映射为 ENCRYPTION_* / CHAT_ID_INVALID / DH_G_A_INVALID
type SecretChatService interface {
RequestEncryption(ctx context.Context, req domain.SecretChatRequest) (domain.SecretChat, error)
AcceptEncryption(ctx context.Context, chatID int, viewerUserID, participantAuthKeyID, accessHash int64, gb []byte, keyFingerprint int64) (domain.SecretChat, error)
DiscardEncryption(ctx context.Context, chatID int, viewerUserID int64, deleteHistory bool) (domain.SecretChat, bool, error)
// DiscardForAuthKey 级联 discard 绑定该 perm auth_key 的全部活跃密聊(设备登出/授权撤销),
// 返回实际迁移到 discarded 的密聊供通知对端。
DiscardForAuthKey(ctx context.Context, authKeyID int64) ([]domain.SecretChat, error)
GetSecretChat(ctx context.Context, chatID int) (domain.SecretChat, bool, error)
SendEncrypted(ctx context.Context, chatID int, viewerUserID, accessHash int64, delivery domain.SecretMessageDelivery) (domain.SecretChat, domain.SecretChatMessage, error)
ListNewMessages(ctx context.Context, deviceAuthKeyID int64, sinceQts, limit int) ([]domain.SecretChatMessage, error)
DeviceReservedQts(ctx context.Context, deviceAuthKeyID int64) (int, error)
AckQueue(ctx context.Context, deviceAuthKeyID int64, maxQts int) error
RecordEncryptionEvent(ctx context.Context, chatID int, targetUserID, targetAuthKeyID int64, date int) error
RecordReadEvent(ctx context.Context, chatID int, targetUserID, targetAuthKeyID int64, maxDate, date int) error
ListStateEvents(ctx context.Context, userID, deviceAuthKeyID int64, limit int) ([]domain.EncryptedStateEvent, error)
MarkStateEventsDelivered(ctx context.Context, deviceAuthKeyID int64, eventIDs []int64) error
PutEncryptedFile(ctx context.Context, ownerUserID int64, ref domain.EncryptedFileRef) error
GetEncryptedFile(ctx context.Context, id, accessHash int64) (domain.EncryptedFileRef, bool, error)
}
// PhoneService 抽象私聊 1:1 通话信令状态机app/phone。所有返回值都是状态快照
// 错误集合见 app/phone 的 Err*rpc 层经 phoneCallErr 映射为 CALL_* RPC_ERROR
type PhoneService interface {
RequestCall(ctx context.Context, callerID int64, in domain.PhoneCallRequest) (domain.PhoneCall, error)
ReceivedCall(ctx context.Context, userID, callID, accessHash int64) (domain.PhoneCall, bool, error)
AcceptCall(ctx context.Context, userID, callID, accessHash int64, gb []byte, proto domain.PhoneCallProtocol, device domain.SessionRef) (domain.PhoneCall, error)
ConfirmCall(ctx context.Context, userID, callID, accessHash int64, ga []byte, keyFingerprint int64, proto domain.PhoneCallProtocol) (call domain.PhoneCall, forcedDiscard bool, err error)
DiscardCall(ctx context.Context, userID, callID, accessHash int64, reason domain.PhoneCallDiscardReason, duration int) (call domain.PhoneCall, already bool, err error)
DiscardCallWithSlug(ctx context.Context, userID, callID, accessHash int64, reason domain.PhoneCallDiscardReason, reasonSlug string, duration int) (call domain.PhoneCall, already bool, err error)
// Signal 在该通话的信令顺序锁内执行 forwarddrop=true 表示按契约静默吞掉。
// peerDevice 是对端受理设备锚点(可零值/失效),定向推送失败须回退 user 扇出。
Signal(ctx context.Context, userID, callID, accessHash int64, forward func(peerUserID int64, peerDevice domain.SessionRef)) (drop bool, err error)
Lookup(ctx context.Context, callID, accessHash int64) (domain.PhoneCall, bool)
// ExpireDue 由 PhoneExpiryDispatcher 周期调用:迁移超时通话并返回快照。
ExpireDue(ctx context.Context, now time.Time) []domain.PhoneCall
}
// GroupCallsService 抽象超级群语音聊天信令app/groupcalls
// 错误集合见 domain.ErrGroupCall*rpc 层映射为 GROUPCALL_* RPC_ERROR
type GroupCallsService interface {
Create(ctx context.Context, channelID, creatorUserID int64, title string, rtmpStream, joinMuted bool, scheduleDate, now int) (domain.GroupCall, error)
// RtmpStreamKey 取/轮换 channel 的持久 RTMP 推流密钥rotate=true 覆盖旧 key
RtmpStreamKey(ctx context.Context, channelID int64, rotate bool, now int) (string, error)
// StartScheduled / SetScheduleSubscription / ScheduleSubscriberIDs 是定时通话流程。
StartScheduled(ctx context.Context, callID int64) (domain.GroupCall, bool, error)
SetScheduleSubscription(ctx context.Context, callID, userID int64, subscribed bool) error
ScheduleSubscriberIDs(ctx context.Context, callID int64) ([]int64, error)
CreateConference(ctx context.Context, creatorUserID, randomID, migratedFromPhoneCallID int64, now int) (domain.GroupCall, error)
Get(ctx context.Context, callID int64) (domain.GroupCall, bool, error)
GetBySlug(ctx context.Context, slug string) (domain.GroupCall, bool, error)
GetByInviteMessage(ctx context.Context, userID int64, msgID int) (domain.GroupCall, domain.GroupCallInvite, bool, error)
Join(ctx context.Context, req domain.JoinGroupCallRequest) (domain.GroupCallMutation, error)
Leave(ctx context.Context, callID, userID int64, now int) (domain.GroupCallMutation, error)
RemoveConferenceParticipants(ctx context.Context, req domain.RemoveConferenceCallParticipantsRequest) (domain.RemoveConferenceCallParticipantsResult, error)
Discard(ctx context.Context, callID int64, now int) (domain.GroupCall, []domain.GroupCallParticipant, error)
Touch(ctx context.Context, callID, userID int64, now int) (activeSSRCs []int64, joined bool, err error)
Participant(ctx context.Context, callID, userID int64) (domain.GroupCallParticipant, bool, error)
Participants(ctx context.Context, callID int64, offset string, limit int) (domain.GroupCallParticipantPage, error)
UpdateParticipant(ctx context.Context, callID, userID int64, update domain.GroupCallParticipantUpdate) (domain.GroupCallMutation, bool, error)
SetTitle(ctx context.Context, callID int64, title string) (domain.GroupCall, bool, error)
SetJoinMuted(ctx context.Context, callID int64, joinMuted bool) (domain.GroupCall, bool, error)
SetStartedMessageID(ctx context.Context, callID int64, msgID int) error
SweepStale(ctx context.Context, checkOlderThan, now, limit int) ([]domain.GroupCallMutation, error)
ResetAllParticipants(ctx context.Context, now int) ([]domain.GroupCall, error)
NextRaiseHandRating(ctx context.Context, callID int64) (int64, error)
SetParticipantOverride(ctx context.Context, callID, setterUserID, targetUserID int64, override domain.GroupCallParticipantOverride, clear bool) error
ParticipantOverride(ctx context.Context, callID, setterUserID, targetUserID int64) (domain.GroupCallParticipantOverride, bool, error)
CreateConferenceInvite(ctx context.Context, invite domain.GroupCallInvite) (domain.GroupCallInvite, error)
SetConferenceInviteStatus(ctx context.Context, callID, inviteeUserID int64, msgID int, status domain.GroupCallInviteStatus, now int) (domain.GroupCallInvite, bool, error)
ConferenceRecipients(ctx context.Context, callID int64) ([]int64, error)
AppendChainBlock(ctx context.Context, block domain.GroupCallChainBlock) (domain.GroupCallChainBlock, error)
ChainBlocks(ctx context.Context, callID int64, subChainID, offset, limit int) (domain.GroupCallChainBlockPage, error)
}
// LiveStreamsService 抽象直播媒体面app/livestreamRTMP ingest + 切段 ring
// nil = 直播媒体面未启用(信令仍可用,观众停留在"等待推流"占位)。
type LiveStreamsService interface {
// StreamChannels 返回 channel 当前直播时间轴;无活跃推流返回空。
StreamChannels(channelID int64) []domain.LiveStreamChannel
// StreamPart 按 time_ms/scale 取一段打包好的 tgcalls broadcast part。
StreamPart(channelID int64, timeMs int64, scale int) ([]byte, error)
// DropChannel 断开该 channel 的推流会话并清空缓冲discard/revoke
DropChannel(channelID int64)
}
// PollsService 抽象 poll 权威态的发送时创建与投票人列表messages.getPollVotes
type PollsService interface {
CreatePoll(ctx context.Context, def domain.PollDefinition) error
GetPollDefinition(ctx context.Context, pollID int64) (domain.PollDefinition, bool, error)
ListPollVotes(ctx context.Context, req domain.PollVotesListRequest) (domain.PollVotesList, error)
}