Initial open source release

This commit is contained in:
A 2026-06-04 01:37:39 +08:00
commit 74992e893f
377 changed files with 118084 additions and 0 deletions

127
internal/config/config.go Normal file
View file

@ -0,0 +1,127 @@
// Package config 负责 telesrv 运行配置的加载与校验。
package config
import (
"os"
"strconv"
"time"
)
// Config 是 telesrv 的运行配置。
type Config struct {
// ListenAddr 是 MTProto TCP 监听地址。
// 需与 TDesktop patch 指向的自建 DC 地址/端口一致(记录于 docs/tdesktop-patch-notes.md
ListenAddr string
// AdvertiseIP 是写入 help.getConfig DCOptions 的对外可达 IP客户端据此连接本 DC
AdvertiseIP string
// RSAKeyPath 是 server RSA 私钥的 PEM 路径;不存在时自动生成。
RSAKeyPath string
// DC 是本 server 的 DC ID。
DC int
// PostgresDSN 是业务数据auth_key / user / authorization 等)持久化的 PostgreSQL 连接串。
// 依赖由 deploy/docker-compose.yml 启动;职责划分见 docs/persistence-layer.md。
PostgresDSN string
// PostgresMaxConns 是 pgxpool 最大连接数。<=0 用 pgx 默认max(4, NumCPU),生产偏小)。
// 需覆盖发送事务 + outbox worker 并发 + RPC 读,过小会在高并发下排队(表现为尾延迟突刺)。
PostgresMaxConns int
// PostgresMinConns 是启动时预热的 pgxpool 连接数,降低 TDesktop 冷启动并发 RPC 的建连等待。
PostgresMinConns int
// RedisAddr 是高频易失态验证码、限流计数、update 队列)的 Redis 地址。
RedisAddr string
// RedisPassword 是 Redis 密码;开发默认空。
RedisPassword string
// RedisDB 是 Redis 逻辑库编号。
RedisDB int
// DevAuthCode 是开发固定验证码;生产短信/风控不在当前范围内。
DevAuthCode string
// LangPackSeedDir 是 TDesktop 语言包 .strings 种子目录。
LangPackSeedDir string
// BlobDir 是本地磁盘 blob backend 根目录(媒体文件字节内容)。
BlobDir string
// StickerSeedDir 是 reaction / sticker 资源种子目录(导入到 documents/sticker_sets + blob
StickerSeedDir string
// StickerSeedMaxSets 限制导入的常规贴纸集数量(避免启动时导入过多包),<=0 表示不限。
StickerSeedMaxSets int
// OutboxWorkers 是并发 claim 的 outbox worker 数。worker 间用 FOR UPDATE SKIP LOCKED 互不重叠。
// 开发默认偏保守,避免 TDesktop 启动风暴下多个 worker 同扫分区父表触发 PG lock/shared-memory 压力;
// 压测或生产可按硬件用 TELESRV_OUTBOX_WORKERS 调高。
OutboxWorkers int
// OutboxBatch 是 transactional outbox worker 每次 claim 的最大条数。
// 调大提升吞吐、增大单批 PG/推送压力;调小降低延迟抖动。配套压测见 docs/message-module.md。
OutboxBatch int
// OutboxInterval 是 outbox worker 两次 claim 之间的轮询间隔。
OutboxInterval time.Duration
// OutboxLeaseTimeout 是 'dispatching' 行被判定为租约过期、允许其它 worker 重新 claim 的时长。
// 取值需大于单批投递耗时,否则会重复推送;过大则 worker 崩溃后积压恢复变慢。
OutboxLeaseTimeout time.Duration
// OutboundPushTimeout 是 best-effort updates 推送等待 outbound 队列接受的最长时间。
OutboundPushTimeout time.Duration
// UpdateEventRetention 是 durable update log 保留期;只清理已被水位/state 覆盖的事件。
UpdateEventRetention time.Duration
// RetentionInterval 是 retention worker 的运行间隔。
RetentionInterval time.Duration
// RetentionBatch 是单次 retention 最多删除的行数。
RetentionBatch int
}
// Load 从环境变量读取配置并填充默认值。第一阶段不做严格校验。
func Load() (Config, error) {
cfg := Config{
ListenAddr: envOr("TELESRV_LISTEN", "0.0.0.0:2398"),
AdvertiseIP: envOr("TELESRV_ADVERTISE_IP", "127.0.0.1"),
RSAKeyPath: envOr("TELESRV_RSA_KEY", "data/server_rsa.pem"),
DC: envIntOr("TELESRV_DC", 2),
PostgresDSN: envOr("TELESRV_POSTGRES_DSN", "postgres://telesrv:telesrv@localhost:5432/telesrv?sslmode=disable"),
PostgresMaxConns: envIntOr("TELESRV_POSTGRES_MAX_CONNS", 50),
PostgresMinConns: envIntOr("TELESRV_POSTGRES_MIN_CONNS", 16),
RedisAddr: envOr("TELESRV_REDIS_ADDR", "localhost:6399"),
RedisPassword: envOr("TELESRV_REDIS_PASSWORD", ""),
RedisDB: envIntOr("TELESRV_REDIS_DB", 0),
DevAuthCode: envOr("TELESRV_DEV_AUTH_CODE", "12345"),
LangPackSeedDir: envOr("TELESRV_LANGPACK_SEED_DIR", "data/langpack"),
BlobDir: envOr("TELESRV_BLOB_DIR", "data/blobs"),
StickerSeedDir: envOr("TELESRV_STICKER_SEED_DIR", "data/sticker-seed"),
StickerSeedMaxSets: envIntOr("TELESRV_STICKER_SEED_MAX_SETS", 40),
OutboxWorkers: envIntOr("TELESRV_OUTBOX_WORKERS", 2),
OutboxBatch: envIntOr("TELESRV_OUTBOX_BATCH", 100),
OutboxInterval: envDurationOr("TELESRV_OUTBOX_INTERVAL", 200*time.Millisecond),
OutboxLeaseTimeout: envDurationOr("TELESRV_OUTBOX_LEASE_TIMEOUT", 30*time.Second),
OutboundPushTimeout: envDurationOr("TELESRV_OUTBOUND_PUSH_TIMEOUT", 200*time.Millisecond),
UpdateEventRetention: envDurationOr("TELESRV_UPDATE_EVENT_RETENTION", 168*time.Hour),
RetentionInterval: envDurationOr("TELESRV_RETENTION_INTERVAL", time.Hour),
RetentionBatch: envIntOr("TELESRV_RETENTION_BATCH", 10000),
}
return cfg, nil
}
func envOr(key, def string) string {
if v := os.Getenv(key); v != "" {
return v
}
return def
}
func envIntOr(key string, def int) int {
if v := os.Getenv(key); v != "" {
if n, err := strconv.Atoi(v); err == nil {
return n
}
}
return def
}
// envDurationOr 读取 time.ParseDuration 格式(如 "200ms"、"30s")的时长配置;解析失败回退默认值。
func envDurationOr(key string, def time.Duration) time.Duration {
if v := os.Getenv(key); v != "" {
if d, err := time.ParseDuration(v); err == nil {
return d
}
}
return def
}