feat: 建立商品目录接入基础 (#132)

This commit is contained in:
chengma
2026-08-11 10:00:07 +08:00
parent b1a78f3e2f
commit 107ee5ce85
13 changed files with 631 additions and 7 deletions
+69 -2
View File
@@ -31,6 +31,8 @@ const (
databasePasswordEnv = "CMAUTOBUY_DB_PASSWORD"
databaseTLSModeEnv = "CMAUTOBUY_DB_TLS_MODE"
databaseTLSCAEnv = "CMAUTOBUY_DB_TLS_CA"
catalogSourceEnv = "CMAUTOBUY_CATALOG_SOURCE"
catalogTokenEnv = "CMAUTOBUY_CATALOG_TOKEN"
)
const (
@@ -52,6 +54,24 @@ type DatabaseConfig struct {
TLSCA string `yaml:"tls_ca"`
}
// CatalogIntegrationConfig 是第三方商品目录接口的独立身份配置。
// Token 只允许来自未提交的 config.yaml 或环境变量,String 永远不输出明文。
type CatalogIntegrationConfig struct {
Source string `yaml:"source"`
Token string `yaml:"token"`
}
func (c CatalogIntegrationConfig) String() string {
token := "(未启用)"
if c.Token != "" {
token = "****"
}
return fmt.Sprintf("CatalogIntegrationConfig{Source:%s Token:%s}", c.Source, token)
}
// Enabled 表示商品目录接口已经配置专用凭据。
func (c CatalogIntegrationConfig) Enabled() bool { return c.Token != "" }
// String 永远隐藏密码,防止排错时用 %v 把凭据写进日志。
func (c DatabaseConfig) String() string {
password := "(空)"
@@ -98,6 +118,47 @@ func LoadDatabaseFromEnv() (DatabaseConfig, error) {
return mergeDatabaseConfig(DatabaseConfig{})
}
// LoadCatalogIntegration 读取可选的商品目录接口配置。未配置 Token 时接口保持禁用,
// 不影响 Admin 其余页面和 Client 四接口启动。
func LoadCatalogIntegration() (CatalogIntegrationConfig, error) {
path, err := ConfigPath()
if err != nil {
return CatalogIntegrationConfig{}, fmt.Errorf("无法确定 config.yaml 应该在的位置: %w", err)
}
var cfg CatalogIntegrationConfig
raw, readErr := os.ReadFile(path)
if readErr == nil {
parsed, parseErr := parseConfig(raw, path)
if parseErr != nil {
return CatalogIntegrationConfig{}, parseErr
}
cfg = parsed.Integrations.Catalog
} else if !os.IsNotExist(readErr) {
return CatalogIntegrationConfig{}, fmt.Errorf("读取配置文件 %s 失败: %w", path, readErr)
}
return mergeCatalogIntegration(cfg)
}
func mergeCatalogIntegration(cfg CatalogIntegrationConfig) (CatalogIntegrationConfig, error) {
if value := strings.TrimSpace(os.Getenv(catalogSourceEnv)); value != "" {
cfg.Source = value
}
if value := os.Getenv(catalogTokenEnv); value != "" {
cfg.Token = value
}
cfg.Source = strings.TrimSpace(cfg.Source)
if cfg.Source == "" {
cfg.Source = "external"
}
if len(cfg.Source) > 64 {
return CatalogIntegrationConfig{}, fmt.Errorf("商品目录来源名称不能超过 64 个字符")
}
if cfg.Token != "" && len(cfg.Token) < 32 {
return CatalogIntegrationConfig{}, fmt.Errorf("%s 至少需要 32 个字符", catalogTokenEnv)
}
return cfg, nil
}
// mergeDatabaseConfig 把环境变量合并到文件配置上。环境变量只要非空,
// 就覆盖对应 YAML 字段,避免线上误读部署目录里遗留的本地配置。
func mergeDatabaseConfig(cfg DatabaseConfig) (DatabaseConfig, error) {
@@ -258,8 +319,14 @@ func (c SybConfig) String() string {
// Config 是 config.yaml 的顶层结构。
type Config struct {
Database DatabaseConfig `yaml:"database"`
Syb SybConfig `yaml:"syb"`
Database DatabaseConfig `yaml:"database"`
Syb SybConfig `yaml:"syb"`
Integrations IntegrationsConfig `yaml:"integrations"`
}
// IntegrationsConfig 收拢所有非 Client 的第三方数据接入配置。
type IntegrationsConfig struct {
Catalog CatalogIntegrationConfig `yaml:"catalog"`
}
// configFileName 是 config.yaml 相对 exe(或 go run 时相对工作目录)的文件名。