6da6964451
- Go/Gin/GORM + 纯 Go SQLite(无 cgo) - Channel 多渠道接口:支付宝当面付(precreate)/电脑网站支付(page.pay) 已实现,微信占位 - 多商户 merchants 表,回调验签+金额核对+幂等+查单兜底 - 收款页/结果页/二维码端点;docs/ 设计文档与部署 Runbook - 密钥走环境变量/Bitwarden,不入库 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
82 lines
3.1 KiB
Go
82 lines
3.1 KiB
Go
package config
|
||
|
||
import (
|
||
"log"
|
||
"strings"
|
||
|
||
"github.com/spf13/viper"
|
||
)
|
||
|
||
type Config struct {
|
||
Server ServerConfig
|
||
Database DatabaseConfig
|
||
AlipaySandbox AlipaySandboxConfig `mapstructure:"alipay_sandbox"`
|
||
QuerySync QuerySyncConfig `mapstructure:"query_sync"`
|
||
}
|
||
|
||
type ServerConfig struct {
|
||
Port string `mapstructure:"port"`
|
||
Mode string `mapstructure:"mode"` // debug | release
|
||
BaseURL string `mapstructure:"base_url"` // 拼 notify_url / return_url 的公网根地址;沙箱回调需公网可达(内网穿透)
|
||
}
|
||
|
||
type DatabaseConfig struct {
|
||
Driver string `mapstructure:"driver"` // sqlite | mysql
|
||
DSN string `mapstructure:"dsn"` // sqlite 为文件路径;mysql 为完整 DSN
|
||
}
|
||
|
||
// AlipaySandboxConfig 启动时据此 upsert 一个支付宝(沙箱)商户,方便开箱联调。
|
||
// 生产/多商户请改为通过管理接口或 seed 写入 merchants 表。
|
||
type AlipaySandboxConfig struct {
|
||
Enabled bool `mapstructure:"enabled"`
|
||
Production bool `mapstructure:"production"` // false=沙箱网关;true=正式网关(真钱)
|
||
MerchantCode string `mapstructure:"merchant_code"` // 业务标识,如 yanmei
|
||
MerchantName string `mapstructure:"merchant_name"`
|
||
AppID string `mapstructure:"app_id"`
|
||
AppPrivateKey string `mapstructure:"app_private_key"` // 应用私钥(PKCS1/PKCS8 皆可,无 PEM 头亦可)
|
||
AlipayPublicKey string `mapstructure:"alipay_public_key"` // 支付宝公钥(公钥模式)
|
||
}
|
||
|
||
// QuerySyncConfig 兜底主动查单:定时把待支付订单拿去 alipay.trade.query 核对,防回调丢失。
|
||
type QuerySyncConfig struct {
|
||
Enabled bool `mapstructure:"enabled"`
|
||
IntervalSec int `mapstructure:"interval_sec"` // 轮询间隔(秒)
|
||
MaxAgeMin int `mapstructure:"max_age_min"` // 只查创建时间在该分钟数内的待支付单
|
||
}
|
||
|
||
var C Config
|
||
|
||
func Load() {
|
||
viper.SetConfigName("config")
|
||
viper.SetConfigType("yaml")
|
||
viper.AddConfigPath(".")
|
||
viper.AddConfigPath("./config")
|
||
|
||
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
||
viper.AutomaticEnv()
|
||
|
||
// 敏感项支持环境变量覆盖(部署时不写进 config.yaml)
|
||
_ = viper.BindEnv("alipay_sandbox.app_private_key", "ALIPAY_APP_PRIVATE_KEY")
|
||
_ = viper.BindEnv("alipay_sandbox.alipay_public_key", "ALIPAY_PUBLIC_KEY")
|
||
_ = viper.BindEnv("database.dsn", "DATABASE_DSN")
|
||
|
||
viper.SetDefault("server.port", "8080")
|
||
viper.SetDefault("server.mode", "debug")
|
||
viper.SetDefault("server.base_url", "http://localhost:8080")
|
||
viper.SetDefault("database.driver", "sqlite")
|
||
viper.SetDefault("database.dsn", "pay.db")
|
||
viper.SetDefault("alipay_sandbox.enabled", false)
|
||
viper.SetDefault("alipay_sandbox.merchant_code", "yanmei")
|
||
viper.SetDefault("alipay_sandbox.merchant_name", "演么测试商户")
|
||
viper.SetDefault("query_sync.enabled", true)
|
||
viper.SetDefault("query_sync.interval_sec", 30)
|
||
viper.SetDefault("query_sync.max_age_min", 30)
|
||
|
||
if err := viper.ReadInConfig(); err != nil {
|
||
log.Println("[config] 未找到 config.yaml,使用默认值 + 环境变量")
|
||
}
|
||
if err := viper.Unmarshal(&C); err != nil {
|
||
log.Fatalf("[config] 解析配置失败: %v", err)
|
||
}
|
||
}
|