143 lines
3.3 KiB
Go
143 lines
3.3 KiB
Go
package utils
|
|
|
|
import (
|
|
"crypto/md5"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"net/url"
|
|
"os"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/fsnotify/fsnotify"
|
|
"github.com/spf13/viper"
|
|
)
|
|
|
|
// 外部传入Nacos参数结构体
|
|
type NacosConfig struct {
|
|
Hosts []string
|
|
NamespaceId string
|
|
Group string
|
|
ConfigID string
|
|
}
|
|
|
|
var (
|
|
runViper = viper.New()
|
|
loadOnce sync.Once
|
|
nacosCfg NacosConfig
|
|
currentMd5 string
|
|
)
|
|
|
|
func GetConfig(key string) interface{} { return runViper.Get(key) }
|
|
func GetConfigString(key string) string { return runViper.GetString(key) }
|
|
func GetConfigInt(key string) int { return runViper.GetInt(key) }
|
|
func GetConfigInt64(key string) int64 { return runViper.GetInt64(key) }
|
|
func GetConfigBool(key string) bool { return runViper.GetBool(key) }
|
|
|
|
// 初始化入口
|
|
func InitConfig(cfg NacosConfig) {
|
|
loadOnce.Do(func() {
|
|
nacosCfg = cfg
|
|
|
|
if len(nacosCfg.Hosts) == 0 || nacosCfg.ConfigID == "" {
|
|
panic("nacos Hosts 与 ConfigID 不能为空")
|
|
}
|
|
|
|
// 尝试拉取远端配置
|
|
pullErr := fetchNacosAndSaveRunToml()
|
|
if pullErr != nil {
|
|
fmt.Printf("【警告】Nacos远程拉取失败: %v\n尝试加载本地run.toml缓存启动\n", pullErr)
|
|
}
|
|
|
|
// 加载配置,容错:无缓存文件不直接panic,打印提示
|
|
loadRunToml()
|
|
|
|
// 后台定时同步
|
|
startFixedIntervalSync()
|
|
})
|
|
}
|
|
|
|
// 标准URL解析,彻底解决重复拼接http://BUG
|
|
func getNacosBaseUrl() string {
|
|
addr := nacosCfg.Hosts[0]
|
|
// 判断开头有没有http/https协议
|
|
if strings.HasPrefix(addr, "http://") || strings.HasPrefix(addr, "https://") {
|
|
return addr
|
|
}
|
|
// 无协议强制加上 http://
|
|
return "http://" + addr
|
|
}
|
|
|
|
// 请求Nacos配置接口
|
|
func fetchNacosConfig() (content string, md5Str string, err error) {
|
|
baseUrl := getNacosBaseUrl()
|
|
fullUrl := fmt.Sprintf(
|
|
"%s/nacos/v1/cs/configs?dataId=%s&group=%s&tenant=%s",
|
|
baseUrl,
|
|
url.QueryEscape(nacosCfg.ConfigID),
|
|
url.QueryEscape(nacosCfg.Group),
|
|
url.QueryEscape(nacosCfg.NamespaceId),
|
|
)
|
|
|
|
body, err := Curl(fullUrl).Get("")
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
|
|
hash := md5.Sum([]byte(body))
|
|
md5Str = hex.EncodeToString(hash[:])
|
|
return body, md5Str, nil
|
|
}
|
|
|
|
// MD5比对写入本地文件
|
|
func fetchNacosAndSaveRunToml() error {
|
|
content, newMd5, err := fetchNacosConfig()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if currentMd5 == newMd5 {
|
|
return nil
|
|
}
|
|
|
|
err = os.WriteFile("run.toml", []byte(content), 0644)
|
|
if err != nil {
|
|
return fmt.Errorf("写入run.toml失败: %w", err)
|
|
}
|
|
currentMd5 = newMd5
|
|
fmt.Println("Nacos配置拉取成功,已缓存至本地run.toml")
|
|
return nil
|
|
}
|
|
|
|
// 加载本地配置,增加降级容错
|
|
func loadRunToml() {
|
|
runViper.SetConfigFile("run.toml")
|
|
err := runViper.ReadInConfig()
|
|
if err != nil {
|
|
fmt.Printf("run.toml本地缓存不存在: %v\n当前仅内置默认密钥、超时配置生效,数据库等远端配置缺失,服务无法正常运行\n", err)
|
|
return
|
|
}
|
|
|
|
runViper.WatchConfig()
|
|
runViper.OnConfigChange(func(e fsnotify.Event) {
|
|
fmt.Println("run.toml文件变更,自动重载配置")
|
|
_ = runViper.ReadInConfig()
|
|
})
|
|
}
|
|
|
|
// 5分钟定时同步远端配置
|
|
func startFixedIntervalSync() {
|
|
go func() {
|
|
ticker := time.NewTicker(5 * time.Minute)
|
|
defer ticker.Stop()
|
|
|
|
for range ticker.C {
|
|
err := fetchNacosAndSaveRunToml()
|
|
if err != nil {
|
|
fmt.Printf("定时同步Nacos异常: %v\n", err)
|
|
}
|
|
}
|
|
}()
|
|
}
|