重构代码结构与认证体系,集成异步任务消费者
This commit is contained in:
552
pkg/env/env.go
vendored
552
pkg/env/env.go
vendored
@@ -1,274 +1,54 @@
|
||||
package env
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"platform/pkg/u"
|
||||
"slices"
|
||||
"strconv"
|
||||
|
||||
"github.com/gofiber/fiber/v2/log"
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
// region app
|
||||
|
||||
const (
|
||||
RunModeDev = "debug"
|
||||
RunModeDev = "development"
|
||||
RunModeProd = "production"
|
||||
)
|
||||
|
||||
var (
|
||||
RunMode = RunModeDev
|
||||
TradeExpire = 30 * 60 // 交易过期时间,单位秒
|
||||
)
|
||||
RunMode = RunModeProd
|
||||
LogLevel = slog.LevelDebug
|
||||
TradeExpire = 30 * 60 // 交易过期时间,单位秒
|
||||
SessionAccessExpire = 60 * 60 * 2 // 默认 2 小时
|
||||
SessionRefreshExpire = 60 * 60 * 24 * 7 // 默认 7 天
|
||||
DebugHttpDump = false // 是否打印请求和响应的原始数据
|
||||
DebugExternalChange = true // 是否实际执行外部非幂等接口调用,在开发调试时可以关闭,避免对外部数据产生影响
|
||||
|
||||
func loadApp() {
|
||||
_RunMode := os.Getenv("RUN_MODE")
|
||||
switch _RunMode {
|
||||
case RunModeDev, RunModeProd:
|
||||
RunMode = _RunMode
|
||||
case "":
|
||||
break
|
||||
default:
|
||||
panic("环境变量 RUN_MODE 的值只能是 " + RunModeDev + " 或 " + RunModeProd)
|
||||
}
|
||||
|
||||
_TradeExpire := os.Getenv("TRADE_EXPIRE")
|
||||
if _TradeExpire != "" {
|
||||
value, err := strconv.Atoi(_TradeExpire)
|
||||
if err != nil {
|
||||
panic("环境变量 TRADE_EXPIRE 的值不是数字")
|
||||
}
|
||||
TradeExpire = value
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region auth
|
||||
|
||||
var (
|
||||
SessionAccessExpire = 60 * 60 * 2 // 2小时
|
||||
SessionRefreshExpire = 60 * 60 * 24 * 7 // 7天
|
||||
)
|
||||
|
||||
func loadAuth() {
|
||||
_SessionAccessExpire := os.Getenv("SESSION_ACCESS_EXPIRE")
|
||||
if _SessionAccessExpire != "" {
|
||||
value, err := strconv.Atoi(_SessionAccessExpire)
|
||||
if err != nil {
|
||||
panic("环境变量 SESSION_ACCESS_EXPIRE 的值不是数字")
|
||||
}
|
||||
SessionAccessExpire = value
|
||||
}
|
||||
|
||||
_SessionRefreshExpire := os.Getenv("SESSION_REFRESH_EXPIRE")
|
||||
if _SessionRefreshExpire != "" {
|
||||
value, err := strconv.Atoi(_SessionRefreshExpire)
|
||||
if err != nil {
|
||||
panic("环境变量 SESSION_REFRESH_EXPIRE 的值不是数字")
|
||||
}
|
||||
SessionRefreshExpire = value
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region db
|
||||
|
||||
var (
|
||||
DbHost = "localhost"
|
||||
DbPort = "5432"
|
||||
DbName string
|
||||
DbUserName string
|
||||
DbPassword string
|
||||
)
|
||||
|
||||
func loadDb() {
|
||||
_DbHost := os.Getenv("DB_HOST")
|
||||
if _DbHost != "" {
|
||||
DbHost = _DbHost
|
||||
}
|
||||
RedisHost = "localhost"
|
||||
RedisPort = "6379"
|
||||
RedisPassword = ""
|
||||
|
||||
_DbPort := os.Getenv("DB_PORT")
|
||||
if _DbPort != "" {
|
||||
DbPort = _DbPort
|
||||
}
|
||||
|
||||
_DbName := os.Getenv("DB_NAME")
|
||||
if _DbName != "" {
|
||||
DbName = _DbName
|
||||
} else {
|
||||
panic("环境变量 DB_NAME 的值不能为空")
|
||||
}
|
||||
|
||||
_DbUserName := os.Getenv("DB_USERNAME")
|
||||
if _DbUserName != "" {
|
||||
DbUserName = _DbUserName
|
||||
} else {
|
||||
panic("环境变量 DB_USERNAME 的值不能为空")
|
||||
}
|
||||
|
||||
_DbPassword := os.Getenv("DB_PASSWORD")
|
||||
if _DbPassword != "" {
|
||||
DbPassword = _DbPassword
|
||||
} else {
|
||||
panic("环境变量 DB_PASSWORD 的值不能为空")
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region redis
|
||||
|
||||
var (
|
||||
RedisHost = "localhost"
|
||||
RedisPort = "6379"
|
||||
RedisDb = 0
|
||||
RedisPass = ""
|
||||
)
|
||||
|
||||
func loadRedis() {
|
||||
_RedisHost := os.Getenv("REDIS_HOST")
|
||||
if _RedisHost != "" {
|
||||
RedisHost = _RedisHost
|
||||
}
|
||||
|
||||
_RedisPort := os.Getenv("REDIS_PORT")
|
||||
if _RedisPort != "" {
|
||||
RedisPort = _RedisPort
|
||||
}
|
||||
|
||||
_RedisDb := os.Getenv("REDIS_DB")
|
||||
if _RedisDb != "" {
|
||||
atoi, err := strconv.Atoi(_RedisDb)
|
||||
if err != nil {
|
||||
panic("环境变量 REDIS_DB 的值不是数字")
|
||||
}
|
||||
RedisDb = atoi
|
||||
}
|
||||
|
||||
_RedisPass := os.Getenv("REDIS_PASS")
|
||||
if _RedisPass != "" {
|
||||
RedisPass = _RedisPass
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region log
|
||||
|
||||
var (
|
||||
LogLevel = slog.LevelDebug
|
||||
)
|
||||
|
||||
func loadLog() {
|
||||
_LogLevel := os.Getenv("LOG_LEVEL")
|
||||
switch _LogLevel {
|
||||
case "debug":
|
||||
LogLevel = slog.LevelDebug
|
||||
case "info":
|
||||
LogLevel = slog.LevelInfo
|
||||
case "warn":
|
||||
LogLevel = slog.LevelWarn
|
||||
case "error":
|
||||
LogLevel = slog.LevelError
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region remote
|
||||
|
||||
var (
|
||||
BaiyinAddr = "http://103.139.212.110:9989"
|
||||
BaiyinTokenUrl string
|
||||
)
|
||||
|
||||
var (
|
||||
IdenCallbackUrl string
|
||||
IdenAccessKey string
|
||||
IdenSecretKey string
|
||||
)
|
||||
|
||||
func loadRemote() {
|
||||
_BaiyinAddr := os.Getenv("BAIYIN_ADDR")
|
||||
if _BaiyinAddr != "" {
|
||||
BaiyinAddr = _BaiyinAddr
|
||||
}
|
||||
|
||||
_BaiyinTokenUrl := os.Getenv("BAIYIN_TOKEN_URL")
|
||||
if _BaiyinTokenUrl == "" {
|
||||
panic("环境变量 BAIYIN_TOKEN_URL 的值不能为空")
|
||||
}
|
||||
BaiyinTokenUrl = _BaiyinTokenUrl
|
||||
|
||||
_IdenCallbackUrl := os.Getenv("IDEN_CALLBACK_URL")
|
||||
if _IdenCallbackUrl == "" {
|
||||
panic("环境变量 IDEN_CALLBACK_URL 的值不能为空")
|
||||
}
|
||||
IdenCallbackUrl = _IdenCallbackUrl
|
||||
|
||||
_IdenAccessKey := os.Getenv("IDEN_ACCESS_KEY")
|
||||
if _IdenAccessKey == "" {
|
||||
panic("环境变量 IDEN_ACCESS_KEY 的值不能为空")
|
||||
}
|
||||
IdenAccessKey = _IdenAccessKey
|
||||
|
||||
_IdenSecretKey := os.Getenv("IDEN_SECRET_KEY")
|
||||
if _IdenSecretKey == "" {
|
||||
panic("环境变量 IDEN_SECRET_KEY 的值不能为空")
|
||||
}
|
||||
IdenSecretKey = _IdenSecretKey
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region alipay
|
||||
|
||||
var (
|
||||
AlipayAppId string
|
||||
AlipayAppPrivateKey string
|
||||
AlipayPublicKey string
|
||||
AlipayApiCert string
|
||||
AlipayProduction = false
|
||||
)
|
||||
|
||||
func loadAlipay() {
|
||||
AlipayAppId = os.Getenv("ALIPAY_APP_ID")
|
||||
if AlipayAppId == "" {
|
||||
panic("环境变量 ALIPAY_APP_ID 的值不能为空")
|
||||
}
|
||||
|
||||
AlipayAppPrivateKey = os.Getenv("ALIPAY_APP_PRIVATE_KEY")
|
||||
if AlipayAppPrivateKey == "" {
|
||||
panic("环境变量 ALIPAY_APP_PRIVATE_KEY 的值不能为空")
|
||||
}
|
||||
|
||||
AlipayPublicKey = os.Getenv("ALIPAY_PUBLIC_KEY")
|
||||
if AlipayPublicKey == "" {
|
||||
panic("环境变量 ALIPAY_PUBLIC_KEY 的值不能为空")
|
||||
}
|
||||
|
||||
AlipayApiCert = os.Getenv("ALIPAY_API_CERT")
|
||||
if AlipayApiCert == "" {
|
||||
panic("环境变量 ALIPAY_API_CERT 的值不能为空")
|
||||
}
|
||||
|
||||
_AlipayProduction := os.Getenv("ALIPAY_PRODUCTION")
|
||||
if _AlipayProduction != "" {
|
||||
value, err := strconv.ParseBool(_AlipayProduction)
|
||||
if err != nil {
|
||||
panic("环境变量 ALIPAY_PRODUCTION 的值不是布尔值")
|
||||
}
|
||||
AlipayProduction = value
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region wechatpay
|
||||
|
||||
var (
|
||||
WechatPayAppId string
|
||||
WechatPayMchId string
|
||||
WechatPayMchPrivateKeySerial string
|
||||
@@ -277,185 +57,21 @@ var (
|
||||
WechatPayPublicKey string
|
||||
WechatPayApiCert string
|
||||
WechatPayCallbackUrl string
|
||||
)
|
||||
|
||||
func loadWechatPay() {
|
||||
|
||||
WechatPayAppId = os.Getenv("WECHATPAY_APP_ID")
|
||||
if WechatPayAppId == "" {
|
||||
panic("环境变量 WECHATPAY_APP_ID 的值不能为空")
|
||||
}
|
||||
|
||||
WechatPayMchId = os.Getenv("WECHATPAY_MCH_ID")
|
||||
if WechatPayMchId == "" {
|
||||
panic("环境变量 WECHATPAY_MCH_ID 的值不能为空")
|
||||
}
|
||||
|
||||
WechatPayMchPrivateKeySerial = os.Getenv("WECHATPAY_MCH_PRIVATE_KEY_SERIAL")
|
||||
if WechatPayMchPrivateKeySerial == "" {
|
||||
panic("环境变量 WECHATPAY_MCH_PRIVATE_KEY_SERIAL 的值不能为空")
|
||||
}
|
||||
|
||||
WechatPayMchPrivateKey = os.Getenv("WECHATPAY_MCH_PRIVATE_KEY")
|
||||
if WechatPayMchPrivateKey == "" {
|
||||
panic("环境变量 WECHATPAY_MCH_PRIVATE_KEY 的值不能为空")
|
||||
}
|
||||
|
||||
WechatPayPublicKeyId = os.Getenv("WECHATPAY_PUBLIC_KEY_ID")
|
||||
if WechatPayPublicKeyId == "" {
|
||||
panic("环境变量 WECHATPAY_PUBLIC_KEY_ID 的值不能为空")
|
||||
}
|
||||
|
||||
WechatPayPublicKey = os.Getenv("WECHATPAY_PUBLIC_KEY")
|
||||
if WechatPayPublicKey == "" {
|
||||
panic("环境变量 WECHATPAY_PUBLIC_KEY 的值不能为空")
|
||||
}
|
||||
|
||||
WechatPayApiCert = os.Getenv("WECHATPAY_API_CERT")
|
||||
if WechatPayApiCert == "" {
|
||||
panic("环境变量 WECHATPAY_API_CERT 的值不能为空")
|
||||
}
|
||||
|
||||
WechatPayCallbackUrl = os.Getenv("WECHATPAY_CALLBACK_URL")
|
||||
if WechatPayCallbackUrl == "" {
|
||||
panic("环境变量 WECHATPAY_CALLBACK_URL 的值不能为空")
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region aliyun
|
||||
|
||||
var (
|
||||
AliyunAccessKey string
|
||||
AliyunAccessKeySecret string
|
||||
AliyunSmsSignature string
|
||||
AliyunSmsTemplateLogin string
|
||||
)
|
||||
|
||||
func loadAliyun() {
|
||||
AliyunAccessKey = os.Getenv("ALIYUN_ACCESS_KEY")
|
||||
if AliyunAccessKey == "" {
|
||||
panic("环境变量 ALIYUN_ACCESS_KEY 的值不能为空")
|
||||
}
|
||||
|
||||
AliyunAccessKeySecret = os.Getenv("ALIYUN_ACCESS_KEY_SECRET")
|
||||
if AliyunAccessKeySecret == "" {
|
||||
panic("环境变量 ALIYUN_ACCESS_KEY_SECRET 的值不能为空")
|
||||
}
|
||||
|
||||
AliyunSmsSignature = os.Getenv("ALIYUN_SMS_SIGNATURE")
|
||||
if AliyunSmsSignature == "" {
|
||||
panic("环境变量 ALIYUN_SMS_SIGNATURE 的值不能为空")
|
||||
}
|
||||
|
||||
AliyunSmsTemplateLogin = os.Getenv("ALIYUN_SMS_TEMPLATE_LOGIN")
|
||||
if AliyunSmsTemplateLogin == "" {
|
||||
panic("环境变量 ALIYUN_SMS_TEMPLATE_LOGIN 的值不能为空")
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region 商福通
|
||||
|
||||
var (
|
||||
SftPayEnable = false
|
||||
SftPayAppId string
|
||||
SftPayRouteId string
|
||||
SftPayAppPrivateKey string
|
||||
SftPayPublicKey string
|
||||
SftReturnUrl *string
|
||||
SftNotifyUrl *string
|
||||
SftReturnUrl string
|
||||
SftNotifyUrl string
|
||||
)
|
||||
|
||||
func loadSftPay() {
|
||||
var value string
|
||||
|
||||
value = os.Getenv("SFTPAY_ENABLE")
|
||||
if value != "" {
|
||||
enabled, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
panic("环境变量 SFTPAY_ENABLE 的值不是布尔值")
|
||||
}
|
||||
SftPayEnable = enabled
|
||||
}
|
||||
|
||||
value = os.Getenv("SFTPAY_APP_ID")
|
||||
if value == "" {
|
||||
panic("环境变量 ALIYUN_SMS_TEMPLATE_LOGIN 的值不能为空")
|
||||
} else {
|
||||
SftPayAppId = value
|
||||
}
|
||||
|
||||
value = os.Getenv("SFTPAY_ROUTE_ID")
|
||||
if value != "" {
|
||||
SftPayRouteId = value
|
||||
}
|
||||
|
||||
value = os.Getenv("SFTPAY_APP_PRIVATE_KEY")
|
||||
if value == "" {
|
||||
panic("环境变量 SFTPAY_APP_PRIVATE_KEY 的值不能为空")
|
||||
} else {
|
||||
SftPayAppPrivateKey = value
|
||||
}
|
||||
|
||||
value = os.Getenv("SFTPAY_PUBLIC_KEY")
|
||||
if value == "" {
|
||||
panic("环境变量 SFTPAY_PUBLIC_KEY 的值不能为空")
|
||||
} else {
|
||||
SftPayPublicKey = value
|
||||
}
|
||||
|
||||
value = os.Getenv("SFTPAY_RETURN_URL")
|
||||
if value != "" {
|
||||
SftReturnUrl = &value
|
||||
} else {
|
||||
SftReturnUrl = nil
|
||||
}
|
||||
|
||||
value = os.Getenv("SFTPAY_NOTIFY_URL")
|
||||
if value != "" {
|
||||
SftNotifyUrl = &value
|
||||
} else {
|
||||
SftNotifyUrl = nil
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region debug
|
||||
|
||||
var (
|
||||
// DebugHttpDump 是否打印请求和响应的原始数据
|
||||
DebugHttpDump = false
|
||||
// DebugExternalChange 是否实际执行非幂等外部接口的调用。
|
||||
// 例如外部数据修改接口,在内部接口调试时可以关闭,避免对外部数据产生影响
|
||||
DebugExternalChange = true
|
||||
)
|
||||
|
||||
func loadDebug() {
|
||||
debugHttpDump := os.Getenv("DEBUG_HTTP_DUMP")
|
||||
if debugHttpDump != "" {
|
||||
value, err := strconv.ParseBool(debugHttpDump)
|
||||
if err != nil {
|
||||
panic("环境变量 DEBUG_HTTP_DUMP 的值不是布尔值")
|
||||
}
|
||||
DebugHttpDump = value
|
||||
}
|
||||
|
||||
debugExternalChange := os.Getenv("DEBUG_EXTERNAL_CHANGE")
|
||||
if debugExternalChange != "" {
|
||||
value, err := strconv.ParseBool(debugExternalChange)
|
||||
if err != nil {
|
||||
panic("环境变量 DEBUG_EXTERNAL_CHANGE 的值不是布尔值")
|
||||
}
|
||||
DebugExternalChange = value
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
func Init() {
|
||||
err := godotenv.Load()
|
||||
if err != nil {
|
||||
@@ -464,15 +80,129 @@ func Init() {
|
||||
log.Debug("✔ 加载本地环境变量")
|
||||
}
|
||||
|
||||
loadApp()
|
||||
loadAuth()
|
||||
loadDb()
|
||||
loadRedis()
|
||||
loadLog()
|
||||
loadDebug()
|
||||
loadRemote()
|
||||
loadAlipay()
|
||||
loadWechatPay()
|
||||
loadAliyun()
|
||||
loadSftPay()
|
||||
// 收集所有错误
|
||||
var errs []error
|
||||
|
||||
errs = append(errs, parse(&RunMode, "RUN_MODE", true, &[]string{RunModeDev, RunModeProd}))
|
||||
errs = append(errs, parse(&LogLevel, "LOG_LEVEL", true, nil, func(value string) (slog.Level, error) {
|
||||
switch value {
|
||||
case "debug":
|
||||
return slog.LevelDebug, nil
|
||||
case "info":
|
||||
return slog.LevelInfo, nil
|
||||
case "warn":
|
||||
return slog.LevelWarn, nil
|
||||
case "error":
|
||||
return slog.LevelError, nil
|
||||
default:
|
||||
return slog.LevelInfo, fmt.Errorf("无效的日志级别: %s", value)
|
||||
}
|
||||
}))
|
||||
|
||||
errs = append(errs, parse(&TradeExpire, "TRADE_EXPIRE", true, nil))
|
||||
errs = append(errs, parse(&SessionAccessExpire, "SESSION_ACCESS_EXPIRE", true, nil))
|
||||
errs = append(errs, parse(&SessionRefreshExpire, "SESSION_REFRESH_EXPIRE", true, nil))
|
||||
errs = append(errs, parse(&DebugHttpDump, "DEBUG_HTTP_DUMP", true, nil))
|
||||
errs = append(errs, parse(&DebugExternalChange, "DEBUG_EXTERNAL_CHANGE", true, nil))
|
||||
|
||||
errs = append(errs, parse(&DbHost, "DB_HOST", true, nil))
|
||||
errs = append(errs, parse(&DbPort, "DB_PORT", true, nil))
|
||||
errs = append(errs, parse(&DbName, "DB_NAME", false, nil))
|
||||
errs = append(errs, parse(&DbUserName, "DB_USERNAME", false, nil))
|
||||
errs = append(errs, parse(&DbPassword, "DB_PASSWORD", false, nil))
|
||||
|
||||
errs = append(errs, parse(&RedisHost, "REDIS_HOST", true, nil))
|
||||
errs = append(errs, parse(&RedisPort, "REDIS_PORT", true, nil))
|
||||
errs = append(errs, parse(&RedisPassword, "REDIS_PASS", true, nil))
|
||||
|
||||
errs = append(errs, parse(&BaiyinAddr, "BAIYIN_ADDR", true, nil))
|
||||
errs = append(errs, parse(&BaiyinTokenUrl, "BAIYIN_TOKEN_URL", false, nil))
|
||||
|
||||
errs = append(errs, parse(&IdenCallbackUrl, "IDEN_CALLBACK_URL", false, nil))
|
||||
errs = append(errs, parse(&IdenAccessKey, "IDEN_ACCESS_KEY", false, nil))
|
||||
errs = append(errs, parse(&IdenSecretKey, "IDEN_SECRET_KEY", false, nil))
|
||||
|
||||
errs = append(errs, parse(&AlipayAppId, "ALIPAY_APP_ID", false, nil))
|
||||
errs = append(errs, parse(&AlipayAppPrivateKey, "ALIPAY_APP_PRIVATE_KEY", false, nil))
|
||||
errs = append(errs, parse(&AlipayPublicKey, "ALIPAY_PUBLIC_KEY", false, nil))
|
||||
errs = append(errs, parse(&AlipayApiCert, "ALIPAY_API_CERT", false, nil))
|
||||
errs = append(errs, parse(&AlipayProduction, "ALIPAY_PRODUCTION", true, nil))
|
||||
|
||||
errs = append(errs, parse(&WechatPayAppId, "WECHATPAY_APP_ID", false, nil))
|
||||
errs = append(errs, parse(&WechatPayMchId, "WECHATPAY_MCH_ID", false, nil))
|
||||
errs = append(errs, parse(&WechatPayMchPrivateKeySerial, "WECHATPAY_MCH_PRIVATE_KEY_SERIAL", false, nil))
|
||||
errs = append(errs, parse(&WechatPayMchPrivateKey, "WECHATPAY_MCH_PRIVATE_KEY", false, nil))
|
||||
errs = append(errs, parse(&WechatPayPublicKeyId, "WECHATPAY_PUBLIC_KEY_ID", false, nil))
|
||||
errs = append(errs, parse(&WechatPayPublicKey, "WECHATPAY_PUBLIC_KEY", false, nil))
|
||||
errs = append(errs, parse(&WechatPayApiCert, "WECHATPAY_API_CERT", false, nil))
|
||||
errs = append(errs, parse(&WechatPayCallbackUrl, "WECHATPAY_CALLBACK_URL", false, nil))
|
||||
|
||||
errs = append(errs, parse(&AliyunAccessKey, "ALIYUN_ACCESS_KEY", false, nil))
|
||||
errs = append(errs, parse(&AliyunAccessKeySecret, "ALIYUN_ACCESS_KEY_SECRET", false, nil))
|
||||
errs = append(errs, parse(&AliyunSmsSignature, "ALIYUN_SMS_SIGNATURE", false, nil))
|
||||
errs = append(errs, parse(&AliyunSmsTemplateLogin, "ALIYUN_SMS_TEMPLATE_LOGIN", false, nil))
|
||||
|
||||
errs = append(errs, parse(&SftPayEnable, "SFTPAY_ENABLE", true, nil))
|
||||
errs = append(errs, parse(&SftPayAppId, "SFTPAY_APP_ID", false, nil))
|
||||
errs = append(errs, parse(&SftPayRouteId, "SFTPAY_ROUTE_ID", true, nil))
|
||||
errs = append(errs, parse(&SftPayAppPrivateKey, "SFTPAY_APP_PRIVATE_KEY", false, nil))
|
||||
errs = append(errs, parse(&SftPayPublicKey, "SFTPAY_PUBLIC_KEY", false, nil))
|
||||
errs = append(errs, parse(&SftReturnUrl, "SFTPAY_RETURN_URL", true, nil))
|
||||
errs = append(errs, parse(&SftNotifyUrl, "SFTPAY_NOTIFY_URL", true, nil))
|
||||
|
||||
// 统一处理错误
|
||||
if err := u.CombineErrors(errs); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func parse[T comparable](ptr *T, key string, inited bool, enum *[]string, convOpt ...func(value string) (T, error)) error {
|
||||
value := os.Getenv(key)
|
||||
|
||||
// 处理空值
|
||||
if value == "" {
|
||||
if inited {
|
||||
return nil
|
||||
} else {
|
||||
return fmt.Errorf("环境变量 %s 未设置", key)
|
||||
}
|
||||
}
|
||||
|
||||
// 处理枚举映射
|
||||
if enum != nil {
|
||||
valid := slices.Contains(*enum, value)
|
||||
if !valid {
|
||||
return fmt.Errorf("环境变量 %s 的值 '%s' 必须是 %v 之一", key, value, *enum)
|
||||
}
|
||||
}
|
||||
|
||||
// 根据指针类型进行赋值和类型转换
|
||||
switch p := any(ptr).(type) {
|
||||
case *string:
|
||||
*p = value
|
||||
case *int:
|
||||
intValue, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("环境变量 %s 的值 '%s' 不是有效的整数: %v", key, value, err)
|
||||
}
|
||||
*p = intValue
|
||||
case *bool:
|
||||
boolValue, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("环境变量 %s 的值 '%s' 不是有效的布尔值: %v", key, value, err)
|
||||
}
|
||||
*p = boolValue
|
||||
default:
|
||||
if len(convOpt) == 0 {
|
||||
return fmt.Errorf("环境变量 %s 的值 '%s' 无法赋值到目标类型", key, value)
|
||||
}
|
||||
conv := convOpt[0]
|
||||
convertedValue, err := conv(value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("环境变量 %s 的值 '%s' 转换失败: %v", key, value, err)
|
||||
}
|
||||
*ptr = convertedValue
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user