Merge remote-tracking branch 'upstream/main' into merge-gramsrv-0e2fcdf9
This commit is contained in:
commit
b443ff0c73
277 changed files with 30747 additions and 1551 deletions
|
|
@ -49,6 +49,7 @@ import (
|
|||
"telesrv/internal/app/stargifts"
|
||||
"telesrv/internal/app/stars"
|
||||
storiesapp "telesrv/internal/app/stories"
|
||||
telegramloginapp "telesrv/internal/app/telegramlogin"
|
||||
themesapp "telesrv/internal/app/themes"
|
||||
translationapp "telesrv/internal/app/translation"
|
||||
"telesrv/internal/app/updates"
|
||||
|
|
@ -69,6 +70,7 @@ import (
|
|||
"telesrv/internal/store/memory"
|
||||
"telesrv/internal/store/postgres"
|
||||
"telesrv/internal/store/redisstore"
|
||||
"telesrv/internal/telegramloginhttp"
|
||||
"telesrv/internal/turnsrv"
|
||||
"telesrv/internal/web"
|
||||
)
|
||||
|
|
@ -346,12 +348,60 @@ func run(logger *zap.Logger) error {
|
|||
}
|
||||
defer pool.Close()
|
||||
|
||||
var telegramLoginService *telegramloginapp.Service
|
||||
var telegramLoginIDTokens *telegramloginapp.IDTokenIssuer
|
||||
var telegramLoginHTTPHandler http.Handler
|
||||
if cfg.TelegramLoginEnabled {
|
||||
codeSealer, err := telegramloginapp.LoadCodeSealer(cfg.TelegramLoginCodeKeysFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("load telegram login code keys: %w", err)
|
||||
}
|
||||
clientSecretPepper, err := telegramloginapp.LoadClientSecretPepper(cfg.TelegramLoginSecretPepperFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("load telegram login client-secret pepper: %w", err)
|
||||
}
|
||||
signingKeys, err := telegramloginapp.LoadSigningKeyRing(cfg.TelegramLoginSigningKeysFile, time.Now)
|
||||
if err != nil {
|
||||
return fmt.Errorf("load telegram login signing keys: %w", err)
|
||||
}
|
||||
telegramLoginService, err = telegramloginapp.NewService(postgres.NewTelegramLoginStore(pool), codeSealer, telegramloginapp.Config{
|
||||
Issuer: cfg.TelegramLoginIssuer, AppScheme: cfg.PublicAppScheme, AppLinkBase: cfg.PublicAppLinkBase,
|
||||
AllowHTTP: cfg.TelegramLoginAllowHTTP,
|
||||
ClientSecretPepper: clientSecretPepper,
|
||||
SupportedSigningAlgorithms: signingKeys.ActiveAlgorithms(),
|
||||
RequestTTL: cfg.TelegramLoginRequestTTL, CodeTTL: cfg.TelegramLoginCodeTTL,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("initialize telegram login service: %w", err)
|
||||
}
|
||||
telegramLoginIDTokens, err = telegramloginapp.NewIDTokenIssuer(signingKeys, telegramloginapp.IDTokenIssuerConfig{
|
||||
Issuer: cfg.TelegramLoginIssuer, TTL: cfg.TelegramLoginIDTokenTTL, AllowHTTP: cfg.TelegramLoginAllowHTTP,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("initialize telegram login ID-token issuer: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
rdb, err := redisstore.Open(ctx, cfg.RedisAddr, cfg.RedisPassword, cfg.RedisDB)
|
||||
if err != nil {
|
||||
return fmt.Errorf("connect redis: %w", err)
|
||||
}
|
||||
defer func() { _ = rdb.Close() }()
|
||||
logger.Info("持久化依赖就绪", zap.String("redis", cfg.RedisAddr))
|
||||
if cfg.TelegramLoginEnabled {
|
||||
telegramLoginHTTPHandler, err = telegramloginhttp.NewHandler(telegramloginhttp.Config{
|
||||
Service: telegramLoginService, Tokens: telegramLoginIDTokens,
|
||||
Limiter: redisstore.NewRateLimiter(rdb), AppName: cfg.PublicAppName,
|
||||
Logger: logger.Named("telegram-login-http"), TrustedProxyCIDRs: cfg.TelegramLoginTrustedProxyCIDRs,
|
||||
AllowHTTP: cfg.TelegramLoginAllowHTTP,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("initialize telegram login HTTP provider: %w", err)
|
||||
}
|
||||
logger.Info("Telegram Login/OIDC provider enabled",
|
||||
zap.String("issuer", telegramLoginIDTokens.Issuer()),
|
||||
zap.Strings("signing_algorithms", telegramLoginIDTokens.SupportedAlgorithms()))
|
||||
}
|
||||
|
||||
authKeyStore := postgres.NewAuthKeyStore(pool)
|
||||
userStore := postgres.NewUserStore(pool)
|
||||
|
|
@ -510,6 +560,7 @@ func run(logger *zap.Logger) error {
|
|||
contactsService := contacts.NewService(contactStore, userStore).Configure(
|
||||
contacts.WithPhotoProvider(cachedPhotos),
|
||||
contacts.WithPrivacyEvaluator(privacyService),
|
||||
contacts.WithAccountFreezeProvider(adminService),
|
||||
contacts.WithReadModelVersions(readModelVersionStore),
|
||||
)
|
||||
if seeded, err := langPackService.SeedDirectory(ctx, cfg.LangPackSeedDir); err != nil {
|
||||
|
|
@ -603,6 +654,7 @@ func run(logger *zap.Logger) error {
|
|||
botsapp.WithUserCache(userCache),
|
||||
botsapp.WithStickerSetCreator(filesService),
|
||||
botsapp.WithUserStickerSets(accountService),
|
||||
botsapp.WithTelegramLogin(telegramLoginService),
|
||||
botsapp.WithPublicBaseURL(cfg.PublicBaseURL))
|
||||
groupCallStore := postgres.NewGroupCallStore(pool)
|
||||
groupCallsService := groupcallsapp.NewService(groupCallStore, groupcallsapp.WithPublicBaseURL(cfg.PublicBaseURL))
|
||||
|
|
@ -718,13 +770,14 @@ func run(logger *zap.Logger) error {
|
|||
passkeyapp.WithAllowedOrigins(cfg.PasskeyAllowedOrigins))
|
||||
// 自定义云主题(Create a New Theme):主题目录与每用户已安装列表均持久化到 postgres。
|
||||
themeService := themesapp.NewService(postgres.NewThemeStore(pool))
|
||||
usersService := users.NewService(userStore, users.WithBaseUserCache(userCache), users.WithContactStore(contactStore), users.WithPhotoProvider(cachedPhotos), users.WithPrivacyEvaluator(privacyService))
|
||||
usersService := users.NewService(userStore, users.WithBaseUserCache(userCache), users.WithContactStore(contactStore), users.WithPhotoProvider(cachedPhotos), users.WithPrivacyEvaluator(privacyService), users.WithAccountFreezeProvider(adminService))
|
||||
aiComposeService := aiapp.NewService(aiComposeStore, newAIComposeOptions(cfg, rateLimiter, usersService.PremiumActive, logger)...)
|
||||
botsService.SetAIChatGenerator(aiComposeService)
|
||||
dialogsService := dialogs.NewService(dialogStore, channelStore).Configure(
|
||||
dialogs.WithContactStore(contactStore),
|
||||
dialogs.WithPhotoProvider(cachedPhotos),
|
||||
dialogs.WithPrivacyEvaluator(privacyService),
|
||||
dialogs.WithAccountFreezeProvider(adminService),
|
||||
dialogs.WithPremiumChecker(usersService.PremiumActive),
|
||||
dialogs.WithReadModelVersions(readModelVersionStore),
|
||||
)
|
||||
|
|
@ -749,6 +802,7 @@ func run(logger *zap.Logger) error {
|
|||
messageapp.WithContactStore(contactStore),
|
||||
messageapp.WithPhotoProvider(cachedPhotos),
|
||||
messageapp.WithPrivacyEvaluator(privacyService),
|
||||
messageapp.WithAccountFreezeProvider(adminService),
|
||||
messageapp.WithReadModelVersions(readModelVersionStore),
|
||||
messageapp.WithBotResponder(botsService),
|
||||
messageapp.WithSendPermissionChecker(adminService),
|
||||
|
|
@ -787,6 +841,7 @@ func run(logger *zap.Logger) error {
|
|||
auth.WithEmailSignup(cfg.EmailSignupEnable),
|
||||
auth.WithEmailSignupPhonePrefixes(cfg.EmailSignupPhonePrefixes))
|
||||
updatesService := updates.NewService(updateStateStore, updateEventStore, updates.WithLogger(logger.Named("app").Named("updates")))
|
||||
rpc.SetModerationWarnings(cfg.ScamWarning, cfg.FakeWarning)
|
||||
router := rpc.New(rpc.Config{
|
||||
DC: cfg.DC,
|
||||
IP: cfg.AdvertiseIP,
|
||||
|
|
@ -805,6 +860,8 @@ func run(logger *zap.Logger) error {
|
|||
GroupCallMaxParticipants: cfg.GroupCallMaxParticipants,
|
||||
RtmpIngestURL: cfg.LiveStreamRtmpURL,
|
||||
PublicBaseURL: cfg.PublicBaseURL,
|
||||
PublicAppScheme: cfg.PublicAppScheme,
|
||||
PublicAppLinkBase: cfg.PublicAppLinkBase,
|
||||
// PFS temp→perm 解析缓存:显式撤销会清缓存并断开连接,re-bind 即时失效;
|
||||
// 配置 TTL 只承担跨进程/异常失效兜底,避免大连接数周期性打满 PG。
|
||||
TempKeyResolveCacheTTL: cfg.TempKeyResolveCacheTTL,
|
||||
|
|
@ -826,6 +883,7 @@ func run(logger *zap.Logger) error {
|
|||
EphemeralPush: ephemeralStore,
|
||||
EphemeralReports: ephemeralReportStore,
|
||||
Users: usersService,
|
||||
TelegramLogin: telegramLoginRPCDependency(telegramLoginService),
|
||||
Updates: updatesService,
|
||||
BootstrapUpdates: bootstrapUpdateStore,
|
||||
BotAPIUpdates: botAPIUpdateStore,
|
||||
|
|
@ -885,12 +943,16 @@ func run(logger *zap.Logger) error {
|
|||
Stars: starsService,
|
||||
StarsNotifier: router,
|
||||
UserNotifier: router,
|
||||
FreezeNotifier: router,
|
||||
Channels: channelsService,
|
||||
ChannelNotifier: router,
|
||||
Messages: messagesService,
|
||||
Gifts: giftsService,
|
||||
Photos: filesService,
|
||||
StickerSets: filesService,
|
||||
GiftGranter: router,
|
||||
Bots: botsService,
|
||||
Emoji: filesService,
|
||||
})
|
||||
// bot session 撤销、在线通知与 @ChatBot 流式草稿推送经 router 实现(需 tg.* 边界),
|
||||
// router 创建后注入。
|
||||
|
|
@ -905,6 +967,7 @@ func run(logger *zap.Logger) error {
|
|||
).Run(ctx)
|
||||
go rpc.NewBootstrapUpdateDispatcher(router, logger.Named("rpc").Named("bootstrap")).Run(ctx)
|
||||
go rpc.NewScheduledDispatcher(router, logger.Named("rpc").Named("scheduled")).Run(ctx)
|
||||
go rpc.NewSuggestedPostDispatcher(router, logger.Named("rpc").Named("suggested-post")).Run(ctx)
|
||||
go rpc.NewExpiryDispatcher(router, logger.Named("rpc").Named("expiry")).Run(ctx)
|
||||
go rpc.NewPhoneExpiryDispatcher(router, logger.Named("rpc").Named("phone-expiry"), cfg.CallExpiryInterval).Run(ctx)
|
||||
go rpc.NewGroupCallSweepDispatcher(router, logger.Named("rpc").Named("groupcall-sweep"), cfg.GroupCallSweepInterval, cfg.GroupCallCheckTTL).Run(ctx)
|
||||
|
|
@ -914,6 +977,10 @@ func run(logger *zap.Logger) error {
|
|||
go activeSessions.RunPendingSweeper(ctx, time.Minute)
|
||||
go router.RunPremiumSweeper(ctx, cfg.PremiumSweepInterval, cfg.PremiumSweepBatch)
|
||||
go router.RunAccountLifecycle(ctx, time.Minute, 500)
|
||||
go router.RunAccountFreezeNotifications(ctx, time.Minute, 500)
|
||||
if telegramLoginService != nil {
|
||||
go runTelegramLoginRetention(ctx, telegramLoginService, cfg.TelegramLoginRetention, cfg.TelegramLoginSweepInterval, cfg.TelegramLoginSweepBatch, logger.Named("telegram-login-retention"))
|
||||
}
|
||||
go func() {
|
||||
interval := cfg.StarGiftSweepInterval
|
||||
if interval <= 0 {
|
||||
|
|
@ -953,6 +1020,7 @@ func run(logger *zap.Logger) error {
|
|||
Addr: cfg.PublicLinkWebAddr,
|
||||
PublicBaseURL: cfg.PublicBaseURL,
|
||||
AppScheme: cfg.PublicAppScheme,
|
||||
AppLinkBase: cfg.PublicAppLinkBase,
|
||||
WebBaseURL: cfg.PublicWebBaseURL,
|
||||
AppName: cfg.PublicAppName,
|
||||
DownloadURL: cfg.PublicDownloadURL,
|
||||
|
|
@ -963,6 +1031,7 @@ func run(logger *zap.Logger) error {
|
|||
Photos: filesService,
|
||||
UniqueGifts: giftsService,
|
||||
GiftWithdrawals: giftsService,
|
||||
TelegramLogin: telegramLoginHTTPHandler,
|
||||
}, logger.Named("public-web")); err != nil {
|
||||
return fmt.Errorf("start public Web: %w", err)
|
||||
}
|
||||
|
|
@ -1014,3 +1083,49 @@ func run(logger *zap.Logger) error {
|
|||
// public listener so no seed/prewarm work can run after port 2398 is exposed.
|
||||
return srv.ListenAndServe(ctx, cfg.ListenAddr)
|
||||
}
|
||||
|
||||
// telegramLoginRPCDependency preserves a disabled Telegram Login service as a
|
||||
// nil interface. Assigning the nil *Service directly to rpc.Deps would create a
|
||||
// non-nil interface with a nil concrete pointer and bypass Router availability
|
||||
// checks.
|
||||
func telegramLoginRPCDependency(service *telegramloginapp.Service) rpc.TelegramLoginService {
|
||||
if service == nil {
|
||||
return nil
|
||||
}
|
||||
return service
|
||||
}
|
||||
|
||||
func runTelegramLoginRetention(ctx context.Context, service *telegramloginapp.Service, retention, interval time.Duration, batch int, logger *zap.Logger) {
|
||||
run := func() {
|
||||
var total int64
|
||||
// Bound one tick even when a deployment accumulated years of stale data;
|
||||
// subsequent ticks continue without monopolizing the database pool.
|
||||
for range 10 {
|
||||
deleted, err := service.DeleteExpiredArtifacts(ctx, time.Now().UTC().Add(-retention), batch)
|
||||
if err != nil {
|
||||
if ctx.Err() == nil {
|
||||
logger.Warn("telegram_login_retention_failed", zap.Error(err))
|
||||
}
|
||||
return
|
||||
}
|
||||
total += deleted
|
||||
if deleted < int64(batch) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if total > 0 {
|
||||
logger.Info("telegram_login_retention_completed", zap.Int64("deleted", total))
|
||||
}
|
||||
}
|
||||
run()
|
||||
ticker := time.NewTicker(interval)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
run()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue