b5ab92a57e
来自 xhigh code review 的正确性/健壮性修复,覆盖全部五端: - server:鉴权 fail-closed、计量交叉校验与配额扣穿处理、WS 网关并发与关闭顺序、 billing 行锁、redis Lua 过期与设备槽刷新、config 解析 - desktop:会话 epoch 防串话、WS 重连与 401 处理、api 客户端复用、统一 usePoll 轮询 - android:握手时序、请求头封装、账户状态派生、按需重组 - ios:finalize 宽限、串行采集、错误文案服务端优先、删除死代码 CommitController Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
110 lines
3.0 KiB
Go
110 lines
3.0 KiB
Go
// Package config 环境变量配置(密钥经部署注入,本地开发用 .env.local / docker compose)。
|
||
package config
|
||
|
||
import (
|
||
"encoding/json"
|
||
"log/slog"
|
||
"os"
|
||
"strconv"
|
||
|
||
"dudu/server/pkg/protocol"
|
||
)
|
||
|
||
type Config struct {
|
||
Addr string // HTTP 监听地址
|
||
PostgresDSN string
|
||
RedisAddr string
|
||
RedisDB int
|
||
|
||
JWTSecret string
|
||
JWTTTLHours int
|
||
|
||
// 微信开放平台 / 商户号(申请中可留空,相关模块降级为 mock)
|
||
WechatWebAppID string
|
||
WechatWebSecret string
|
||
WechatMobileAppID string
|
||
WechatMobileSecret string
|
||
WxPayMchID string
|
||
WxPayCertSerial string
|
||
WxPayPrivateKeyPEM string
|
||
WxPayAPIv3Key string
|
||
WxPayNotifyURL string
|
||
|
||
// ASR
|
||
ASRProvider string // gummy | mock
|
||
DashScopeAPIKey string
|
||
|
||
// OSS(反馈图片)
|
||
OSSEndpoint string
|
||
OSSBucket string
|
||
OSSKeyID string
|
||
OSSKeySecret string
|
||
|
||
// AppLatest 启动时解析 APP_LATEST_JSON 一次(17G):平台→版本信息。
|
||
// 解析失败或未配置则为 nil/空,handler 据此返回 204,不 fail-fast。
|
||
AppLatest map[string]protocol.AppLatestResponse
|
||
}
|
||
|
||
func Load() Config {
|
||
return Config{
|
||
Addr: getenv("ADDR", ":8080"),
|
||
PostgresDSN: getenv("POSTGRES_DSN", "host=localhost user=dudu password=dudu dbname=dudu port=5432 sslmode=disable TimeZone=Asia/Shanghai"),
|
||
RedisAddr: getenv("REDIS_ADDR", "localhost:6379"),
|
||
RedisDB: getint("REDIS_DB", 0),
|
||
|
||
JWTSecret: getenv("JWT_SECRET", "dev-secret-change-me"),
|
||
JWTTTLHours: getint("JWT_TTL_HOURS", 24*7),
|
||
|
||
WechatWebAppID: os.Getenv("WECHAT_WEB_APPID"),
|
||
WechatWebSecret: os.Getenv("WECHAT_WEB_SECRET"),
|
||
WechatMobileAppID: os.Getenv("WECHAT_MOBILE_APPID"),
|
||
WechatMobileSecret: os.Getenv("WECHAT_MOBILE_SECRET"),
|
||
WxPayMchID: os.Getenv("WXPAY_MCHID"),
|
||
WxPayCertSerial: os.Getenv("WXPAY_CERT_SERIAL"),
|
||
WxPayPrivateKeyPEM: os.Getenv("WXPAY_PRIVATE_KEY_PEM"),
|
||
WxPayAPIv3Key: os.Getenv("WXPAY_APIV3_KEY"),
|
||
WxPayNotifyURL: os.Getenv("WXPAY_NOTIFY_URL"),
|
||
|
||
ASRProvider: getenv("ASR_PROVIDER", "mock"),
|
||
DashScopeAPIKey: os.Getenv("DASHSCOPE_API_KEY"),
|
||
|
||
OSSEndpoint: os.Getenv("OSS_ENDPOINT"),
|
||
OSSBucket: os.Getenv("OSS_BUCKET"),
|
||
OSSKeyID: os.Getenv("OSS_KEY_ID"),
|
||
OSSKeySecret: os.Getenv("OSS_KEY_SECRET"),
|
||
|
||
AppLatest: loadAppLatest(),
|
||
}
|
||
}
|
||
|
||
// loadAppLatest 启动时解析一次 APP_LATEST_JSON(17G)。失败仅告警并返回 nil,
|
||
// 不 fail-fast——未配置此项时服务仍需正常启动。
|
||
func loadAppLatest() map[string]protocol.AppLatestResponse {
|
||
raw := os.Getenv("APP_LATEST_JSON")
|
||
if raw == "" {
|
||
return nil
|
||
}
|
||
var all map[string]protocol.AppLatestResponse
|
||
if err := json.Unmarshal([]byte(raw), &all); err != nil {
|
||
slog.Warn("invalid APP_LATEST_JSON, app update disabled", "err", err)
|
||
return nil
|
||
}
|
||
return all
|
||
}
|
||
|
||
func getenv(k, def string) string {
|
||
if v := os.Getenv(k); v != "" {
|
||
return v
|
||
}
|
||
return def
|
||
}
|
||
|
||
func getint(k string, def int) int {
|
||
if v := os.Getenv(k); v != "" {
|
||
if n, err := strconv.Atoi(v); err == nil {
|
||
return n
|
||
}
|
||
}
|
||
return def
|
||
}
|