update
This commit is contained in:
@ -22,6 +22,10 @@ type Config struct {
|
||||
Upload UploadConfig `yaml:"upload"`
|
||||
CORS CORSConfig `yaml:"cors"`
|
||||
ClientSign ClientSignConfig `yaml:"client_sign"`
|
||||
// Ingest 爬虫上报接口的 HMAC 验签配置(服务端到服务端,密钥不下发前端)。
|
||||
Ingest IngestConfig `yaml:"ingest"`
|
||||
// Qiniu 七牛云对象存储配置(爬虫入库图片上传目标)。
|
||||
Qiniu QiniuConfig `yaml:"qiniu"`
|
||||
|
||||
// loadedFrom 记录实际生效的配置文件绝对路径,仅用于启动日志。
|
||||
// 小写不导出,yml 无法覆盖它。
|
||||
@ -44,6 +48,10 @@ type ServerConfig struct {
|
||||
// 通过环境变量 SSG_TOKEN 注入,切勿加 PUBLIC_ 前缀以免进入前端 bundle。
|
||||
SSGToken string `yaml:"ssg_token"`
|
||||
|
||||
// BackstagePort 是管理后台(Backstage)端口,承载后台 UI 与(后续)爬虫 ingest 内部接口。
|
||||
// 与对外公开 Port / SSGPort 物理隔离,可独立绑定与限流;为空时兜底 "8092"。
|
||||
BackstagePort string `yaml:"backstage_port"`
|
||||
|
||||
// HashIDSecret 是「公开 ID 混淆」的部署级盐值。
|
||||
// 公开接口对外只暴露编码后的无序串(如 xK9mP2)而非自增主键,防止爬虫顺序枚举;
|
||||
// 该盐值决定编码结果,不同部署应使用不同随机串,避免被反向推导。
|
||||
@ -60,9 +68,9 @@ type DatabaseConfig struct {
|
||||
Name string `yaml:"name"`
|
||||
Charset string `yaml:"charset"`
|
||||
LogLevel string `yaml:"log_level"`
|
||||
MaxIdleConns int `yaml:"max_idle_conns"`
|
||||
MaxOpenConns int `yaml:"max_open_conns"`
|
||||
ConnMaxLifetime int `yaml:"conn_max_lifetime"`
|
||||
MaxIdleConns int `yaml:"max_idle_conns"`
|
||||
MaxOpenConns int `yaml:"max_open_conns"`
|
||||
ConnMaxLifetime int `yaml:"conn_max_lifetime"`
|
||||
// ConnMaxIdleTime 空闲连接回收时间(秒)。必须 < MySQL wait_timeout,否则 MySQL 回收空闲
|
||||
// 连接后,连接池仍持有死连接,下一次查询会报 "invalid connection" / "bad connection"。
|
||||
ConnMaxIdleTime int `yaml:"conn_max_idle_time"`
|
||||
@ -106,6 +114,48 @@ type CORSConfig struct {
|
||||
MaxAge int `yaml:"max_age"`
|
||||
}
|
||||
|
||||
// IngestConfig 爬虫上报接口(:8092 /admin/internal/ingest)的 HMAC 验签配置。
|
||||
//
|
||||
// 爬虫与后台通过共享同一 INGEST_SECRET 对请求做 HMAC-SHA256 签名,
|
||||
// 接口因此可安全暴露(含多节点爬虫场景),无需回环绑定。
|
||||
// 密钥必须走环境变量 INGEST_SECRET 注入,切勿加 PUBLIC_ 前缀以免进入前端 bundle。
|
||||
type IngestConfig struct {
|
||||
// Enabled 开关:false 时 ingest 接口返回 503(尚未配置密钥),便于灰度。
|
||||
Enabled bool `yaml:"enabled"`
|
||||
// Secret 签名密钥,须与爬虫端完全一致;为空则等同于禁用。
|
||||
Secret string `yaml:"secret"`
|
||||
// TTLSeconds 时间戳容忍窗口(秒),默认 300(±5 分钟)。
|
||||
TTLSeconds int `yaml:"ttl_seconds"`
|
||||
}
|
||||
|
||||
// QiniuConfig 七牛云对象存储配置(爬虫入库图片上传目标)。
|
||||
//
|
||||
// worker 下载走秀/街拍图片后,若 Enabled=true 则直传七牛 bucket,
|
||||
// 库里只存 key(base_url 由本配置持有,渲染时再拼);失败再兜底写本地 uploads。
|
||||
// - AK/SK 须与七牛控制台一致;生产经环境变量 QINIU_AK / QINIU_SK 注入。
|
||||
// - Zone 必须匹配 bucket 创建区域,否则上传失败:z0=华东 z1=华北 z2=华南 na0=北美 as0=新加坡。
|
||||
// - BaseURL 为 bucket 绑定的公开访问域名(如 https://cdn.toom-studio.com),用于拼出图片 URL。
|
||||
// - StyleNormal 普通图七牛命名样式名(见 imgurl 包):详情页对免费/未登录用户拼
|
||||
// base_url/key-StyleNormal;须与七牛控制台创建的样式名完全一致。
|
||||
type QiniuConfig struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
AK string `yaml:"ak"`
|
||||
SK string `yaml:"sk"`
|
||||
Bucket string `yaml:"bucket"`
|
||||
Zone string `yaml:"zone"`
|
||||
BaseURL string `yaml:"base_url"`
|
||||
// StyleNormal 普通图七牛命名样式名(如 free 或 free.webp)。
|
||||
StyleNormal string `yaml:"style_normal"`
|
||||
// StyleVip VIP 高清七牛命名样式名(如 vip 或 vip.webp)。VIP tier 走此样式。
|
||||
StyleVip string `yaml:"style_vip"`
|
||||
// LocalBase 本地兜底图片前缀(通常空;前端用 toAbs 拼 host)。仅当静态服务不在同域时有用。
|
||||
LocalBase string `yaml:"local_base"`
|
||||
// SignTTLNormal 普通/压缩图(含命名样式 -free)的私有空间下载签名过期秒;长过期便于 SSG 静态页与 CDN 缓存。
|
||||
SignTTLNormal int64 `yaml:"sign_ttl_normal"`
|
||||
// SignTTLHD VIP 高清原图签名过期秒;短过期使泄漏窗口小。
|
||||
SignTTLHD int64 `yaml:"sign_ttl_hd"`
|
||||
}
|
||||
|
||||
// ClientSignConfig 公开接口「前端 JS 签名」配置。
|
||||
//
|
||||
// 给 /runway-looks(列表)与 /brands 两个批量查询接口加一层请求签名校验,
|
||||
@ -134,6 +184,7 @@ func defaultConfig() *Config {
|
||||
ShutdownTimeout: 10,
|
||||
SSGPort: "8091",
|
||||
SSGToken: "",
|
||||
BackstagePort: "8092",
|
||||
HashIDSecret: "",
|
||||
},
|
||||
Database: DatabaseConfig{
|
||||
@ -169,6 +220,21 @@ func defaultConfig() *Config {
|
||||
Secret: "",
|
||||
TTLSeconds: 30,
|
||||
},
|
||||
Ingest: IngestConfig{
|
||||
Enabled: false,
|
||||
Secret: "",
|
||||
TTLSeconds: 300,
|
||||
},
|
||||
Qiniu: QiniuConfig{
|
||||
Enabled: false,
|
||||
Zone: "z1",
|
||||
BaseURL: "",
|
||||
StyleNormal: "free",
|
||||
StyleVip: "vip",
|
||||
LocalBase: "",
|
||||
SignTTLNormal: 31536000,
|
||||
SignTTLHD: 3600,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,6 +294,7 @@ func (c *Config) applyEnv() {
|
||||
envStr("GIN_MODE", &c.Server.Mode)
|
||||
envStr("SSG_PORT", &c.Server.SSGPort)
|
||||
envStr("SSG_TOKEN", &c.Server.SSGToken)
|
||||
envStr("BACKSTAGE_PORT", &c.Server.BackstagePort)
|
||||
envStr("HASHID_SECRET", &c.Server.HashIDSecret)
|
||||
|
||||
envStr("DB_HOST", &c.Database.Host)
|
||||
@ -252,6 +319,22 @@ func (c *Config) applyEnv() {
|
||||
|
||||
envStr("UPLOAD_DIR", &c.Upload.Dir)
|
||||
envStr("UPLOAD_URL_PREFIX", &c.Upload.URLPrefix)
|
||||
|
||||
envBool("INGEST_ENABLED", &c.Ingest.Enabled)
|
||||
envStr("INGEST_SECRET", &c.Ingest.Secret)
|
||||
envInt("INGEST_TTL", &c.Ingest.TTLSeconds)
|
||||
|
||||
envBool("QINIU_ENABLED", &c.Qiniu.Enabled)
|
||||
envStr("QINIU_AK", &c.Qiniu.AK)
|
||||
envStr("QINIU_SK", &c.Qiniu.SK)
|
||||
envStr("QINIU_BUCKET", &c.Qiniu.Bucket)
|
||||
envStr("QINIU_ZONE", &c.Qiniu.Zone)
|
||||
envStr("QINIU_BASE_URL", &c.Qiniu.BaseURL)
|
||||
envStr("QINIU_STYLE_NORMAL", &c.Qiniu.StyleNormal)
|
||||
envStr("QINIU_STYLE_VIP", &c.Qiniu.StyleVip)
|
||||
envStr("QINIU_LOCAL_BASE", &c.Qiniu.LocalBase)
|
||||
envInt64("QINIU_SIGN_TTL_NORMAL", &c.Qiniu.SignTTLNormal)
|
||||
envInt64("QINIU_SIGN_TTL_HD", &c.Qiniu.SignTTLHD)
|
||||
}
|
||||
|
||||
// normalize 兜底与校验:修正非法值,避免运行期出现难以定位的问题。
|
||||
@ -262,6 +345,9 @@ func (c *Config) normalize() {
|
||||
if c.Server.SSGPort == "" {
|
||||
c.Server.SSGPort = "8091"
|
||||
}
|
||||
if c.Server.BackstagePort == "" {
|
||||
c.Server.BackstagePort = "8092"
|
||||
}
|
||||
switch c.Server.Mode {
|
||||
case "debug", "release", "test":
|
||||
default:
|
||||
@ -313,6 +399,14 @@ func envInt(key string, dst *int) {
|
||||
}
|
||||
}
|
||||
|
||||
func envInt64(key string, dst *int64) {
|
||||
if v := strings.TrimSpace(os.Getenv(key)); v != "" {
|
||||
if n, err := strconv.ParseInt(v, 10, 64); err == nil {
|
||||
*dst = n
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func envBool(key string, dst *bool) {
|
||||
if v := strings.TrimSpace(strings.ToLower(os.Getenv(key))); v != "" {
|
||||
*dst = v == "1" || v == "true" || v == "yes"
|
||||
|
||||
Reference in New Issue
Block a user