This commit is contained in:
toom1996
2026-09-13 00:52:35 +08:00
parent 10d8a96e8c
commit dbee704c95
44 changed files with 755 additions and 1148 deletions

View File

@ -24,8 +24,8 @@ type Config struct {
ClientSign ClientSignConfig `yaml:"client_sign"`
// Ingest 爬虫上报接口的 HMAC 验签配置(服务端到服务端,密钥不下发前端)。
Ingest IngestConfig `yaml:"ingest"`
// Qiniu 七牛云对象存储配置(爬虫入库图片上传目标)。
Qiniu QiniuConfig `yaml:"qiniu"`
// S4 缤纷云对象存储配置(S3 兼容,爬虫入库图片上传目标)。
S4 S4Config `yaml:"s4"`
// loadedFrom 记录实际生效的配置文件绝对路径,仅用于启动日志。
// 小写不导出,yml 无法覆盖它。
@ -120,40 +120,37 @@ type CORSConfig struct {
// 接口因此可安全暴露(含多节点爬虫场景),无需回环绑定。
// 密钥必须走环境变量 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 七牛云对象存储配置(爬虫入库图片上传目标)。
// S4Config 缤纷云 S4 对象存储配置(S3 兼容,爬虫入库图片上传目标)。
//
// worker 下载走秀/街拍图片后,若 Enabled=true 则直传七牛 bucket,
// worker 下载走秀/街拍图片后,若 Enabled=true 则直传 S4 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"`
//
// 图片质量模型(见 internal/pkg/imgurl,2026-09-11 调整):VIP 与免费用户同质量,
// 统一走 CoreIX 公开样式 StyleDisplay(如 high,key!style:high 匿名可访问);付费墙已取消。
// - AK/SK 为缤纷云子账户密钥(须有 PutObject/DeleteObject/GetObject 权限);
// 生产经环境变量 S4_AK / S4_SK 注入。
// - Endpoint 默认 https://s3.bitiful.net;Region 任意(如 cn-east-1)。
// - BaseURL 为对外访问域名;留空自动推导 https://<bucket>.s3.bitiful.net(须与 Endpoint 同 host)。
// - StyleDisplay 全量展示图 CoreIX 样式名(如 high,控制台建公开样式)或查询串(如 w=1080&q=80&fmt=webp)。
// - StyleThumb 列表缩略图 CoreIX 样式名(如 thumb,控制台建公开样式),仅用于「列表/卡片」等
// 小尺寸场景(列表封面、卡片图条、首页热门位),详情页与大图灯箱仍走 StyleDisplay,兼顾清晰度与流量。
// 留空时回落 StyleDisplay(无独立缩略图样式时行为与旧版一致,不报错)。
type S4Config struct {
Enabled bool `yaml:"enabled"`
AK string `yaml:"ak"`
SK string `yaml:"sk"`
Bucket string `yaml:"bucket"`
Endpoint string `yaml:"endpoint"`
Region string `yaml:"region"`
BaseURL string `yaml:"base_url"`
StyleDisplay string `yaml:"style_display"`
StyleThumb string `yaml:"style_thumb"`
}
// ClientSignConfig 公开接口「前端 JS 签名」配置。
@ -221,19 +218,16 @@ func defaultConfig() *Config {
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,
S4: S4Config{
Enabled: false,
Endpoint: "https://s3.bitiful.net",
Region: "cn-east-1",
BaseURL: "",
StyleDisplay: "high",
StyleThumb: "thumb",
},
}
}
@ -320,21 +314,20 @@ 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)
// 缤纷云 S4(兼容 S3):环境变量 S4_* 注入;旧 QINIU_* 仅作兼容回退,便于平滑切换
// (S4_* 优先,仅在 S4_* 为空时回退 QINIU_*)。
envBoolFirst(&c.S4.Enabled, "S4_ENABLED", "QINIU_ENABLED")
envStrFirst(&c.S4.AK, "S4_AK", "QINIU_AK")
envStrFirst(&c.S4.SK, "S4_SK", "QINIU_SK")
envStrFirst(&c.S4.Bucket, "S4_BUCKET", "QINIU_BUCKET")
envStr("S4_ENDPOINT", &c.S4.Endpoint)
envStr("S4_REGION", &c.S4.Region)
envStrFirst(&c.S4.BaseURL, "S4_BASE_URL", "QINIU_BASE_URL")
envStrFirst(&c.S4.StyleDisplay, "S4_STYLE_DISPLAY", "QINIU_STYLE_NORMAL")
envStr("S4_STYLE_THUMB", &c.S4.StyleThumb)
}
// normalize 兜底与校验:修正非法值,避免运行期出现难以定位的问题。
@ -391,17 +384,29 @@ func envStr(key string, dst *string) {
}
}
func envInt(key string, dst *int) {
if v := strings.TrimSpace(os.Getenv(key)); v != "" {
if n, err := strconv.Atoi(v); err == nil {
*dst = n
// envStrFirst 按顺序取第一个非空的环境变量写入 dst(前者优先),用于平滑切换旧变量名。
func envStrFirst(dst *string, keys ...string) {
for _, k := range keys {
if v := strings.TrimSpace(os.Getenv(k)); v != "" {
*dst = v
return
}
}
}
func envInt64(key string, dst *int64) {
// envBoolFirst 按顺序取第一个非空的环境变量写入 dst(前者优先)。
func envBoolFirst(dst *bool, keys ...string) {
for _, k := range keys {
if v := strings.TrimSpace(strings.ToLower(os.Getenv(k))); v != "" {
*dst = v == "1" || v == "true" || v == "yes"
return
}
}
}
func envInt(key string, dst *int) {
if v := strings.TrimSpace(os.Getenv(key)); v != "" {
if n, err := strconv.ParseInt(v, 10, 64); err == nil {
if n, err := strconv.Atoi(v); err == nil {
*dst = n
}
}