package dataReport import ( "encoding/json" "fmt" "hkdj-web-server/pub/common/log" "hkdj-web-server/pub/redis" "net/http" "strings" "sync" "time" "github.com/robfig/cron/v3" ) const ( sdkConfigAPIProd = "https://api.dc-server.cc/sdk/getAvailableDomainList" sdkConfigAPIDev = "https://dcapi.dc-dev.cc/sdk/getAvailableDomainList" sdkConfigCacheKey = "report:sdk:domain_config" sdkConfigCacheTTL = 30 * time.Minute sdkConfigFetchInterval = "0 */10 * * * *" ) var ( sdkConfigAPIURL = sdkConfigAPIProd // 默认正式环境,Init时会根据RunMod覆盖 sdkConfigCron *cron.Cron sdkConfigOnce sync.Once sdkConfigMu sync.RWMutex sdkDomainConfig string sdkConfigUpdatedAt time.Time ) type sdkConfigResponse struct { Code int `json:"code"` Msg string `json:"msg"` Data string `json:"data"` } // StartSDKConfigCron 定时拉取 SDK 域名配置串,服务端只缓存并原样透传。 func StartSDKConfigCron() { sdkConfigOnce.Do(func() { if err := RefreshSDKDomainConfig(); err != nil { log.Error("RefreshSDKDomainConfig first run fail", log.E(err)) } sdkConfigCron = cron.New(cron.WithSeconds()) if _, err := sdkConfigCron.AddFunc(sdkConfigFetchInterval, func() { if err := RefreshSDKDomainConfig(); err != nil { log.Error("RefreshSDKDomainConfig cron fail", log.E(err)) } }); err != nil { log.Error("StartSDKConfigCron AddFunc fail", log.E(err)) return } sdkConfigCron.Start() }) } func StopSDKConfigCron() { if sdkConfigCron == nil { return } ctx := sdkConfigCron.Stop() <-ctx.Done() } func RefreshSDKDomainConfig() error { data, err := fetchSDKDomainConfig(sdkConfigAPIURL, &http.Client{Timeout: 5 * time.Second}) if err != nil { return err } setSDKDomainConfig(data) if redis.Client() == nil { return nil } return redis.Set(sdkConfigCacheKey, data, sdkConfigCacheTTL) } func GetSDKDomainConfig() string { if redis.Client() != nil { data, err := redis.Get(sdkConfigCacheKey) if err != nil { log.Error("GetSDKDomainConfig redis get fail", log.E(err)) } else if data != nil && *data != "" { setSDKDomainConfig(*data) return *data } } sdkConfigMu.RLock() defer sdkConfigMu.RUnlock() return sdkDomainConfig } func setSDKDomainConfig(data string) { sdkConfigMu.Lock() defer sdkConfigMu.Unlock() sdkDomainConfig = data sdkConfigUpdatedAt = time.Now() } func fetchSDKDomainConfig(apiURL string, client *http.Client) (string, error) { req, err := http.NewRequest(http.MethodGet, apiURL, nil) if err != nil { return "", err } req.Header.Set("Accept", "application/json") resp, err := client.Do(req) if err != nil { return "", err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return "", fmt.Errorf("sdk config http status: %d", resp.StatusCode) } var result sdkConfigResponse if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return "", err } if result.Code != 0 { return "", fmt.Errorf("sdk config code: %d, msg: %s", result.Code, result.Msg) } if strings.TrimSpace(result.Data) == "" { return "", fmt.Errorf("sdk config data is empty") } return result.Data, nil }