258 lines
3.8 KiB
Go
258 lines
3.8 KiB
Go
package syncer
|
||
|
||
import (
|
||
"fmt"
|
||
|
||
"strings"
|
||
|
||
"time"
|
||
|
||
"xk-hy-transit-go/internal/applog"
|
||
|
||
"xk-hy-transit-go/internal/config"
|
||
|
||
"xk-hy-transit-go/internal/fileauth"
|
||
|
||
"xk-hy-transit-go/internal/hy"
|
||
|
||
"xk-hy-transit-go/internal/xkapi"
|
||
)
|
||
|
||
// ConfigSnapshot 当前 Runner 配置快照(明文仅进程内使用,Web 层需脱敏)。
|
||
|
||
type ConfigSnapshot struct {
|
||
Cloud xkapi.ConfigResponse
|
||
|
||
CloudOK bool
|
||
|
||
CloudFetchError string
|
||
|
||
RefreshedAt time.Time
|
||
|
||
Local config.Config
|
||
|
||
EffectiveOrgan hy.OrganConfig
|
||
|
||
EffectiveAppKey string
|
||
|
||
EffectiveSecret string
|
||
|
||
EffectiveAesKey string
|
||
|
||
EffectiveFileBucket string
|
||
|
||
UploadToken string
|
||
|
||
UploadTokenSource string
|
||
|
||
CloudUploadToken string
|
||
|
||
FileUploadURL string
|
||
}
|
||
|
||
func firstNonEmpty(values ...string) string {
|
||
|
||
for _, v := range values {
|
||
|
||
if strings.TrimSpace(v) != "" {
|
||
|
||
return strings.TrimSpace(v)
|
||
|
||
}
|
||
|
||
}
|
||
|
||
return ""
|
||
|
||
}
|
||
|
||
func (r *Runner) applyCloudConfig(conf *xkapi.ConfigResponse) {
|
||
|
||
if conf == nil {
|
||
|
||
return
|
||
|
||
}
|
||
|
||
r.organ = hy.OrganConfig{
|
||
|
||
UnitID: conf.UnitID,
|
||
|
||
OrganID: conf.OrganID,
|
||
|
||
OrganName: conf.OrganName,
|
||
}
|
||
|
||
r.cloudUploadToken = conf.UploadToken
|
||
|
||
r.fileUploadURL = resolveFileUploadURL(r.cfg, conf.FileUploadURL)
|
||
|
||
r.hyAppKey = firstNonEmpty(conf.AppKey, r.cfg.HyAppKey)
|
||
|
||
r.hyAppSecret = firstNonEmpty(conf.AppSecret, r.cfg.HyAppSecret)
|
||
|
||
r.hyAesKey = firstNonEmpty(conf.AesKey, r.cfg.HyAesKey)
|
||
|
||
r.fileBucket = firstNonEmpty(conf.FileBucket, r.cfg.HyFileBucket)
|
||
|
||
r.lastCloud = *conf
|
||
|
||
r.lastCloudOK = true
|
||
|
||
r.lastConfigErr = nil
|
||
|
||
r.configRefreshedAt = time.Now()
|
||
|
||
if err := r.refreshUploadTokenLocked(); err != nil {
|
||
|
||
r.uploadToken = ""
|
||
|
||
applog.Appf("warning: generate uploadToken failed: %v", err)
|
||
|
||
}
|
||
|
||
}
|
||
|
||
// refreshUploadToken 按 FileAuth.java upload profile 重新生成 uploadToken(scope=仅 bucket)。
|
||
|
||
func (r *Runner) refreshUploadToken() error {
|
||
|
||
r.configMu.Lock()
|
||
|
||
defer r.configMu.Unlock()
|
||
|
||
return r.refreshUploadTokenLocked()
|
||
|
||
}
|
||
|
||
func (r *Runner) refreshUploadTokenLocked() error {
|
||
|
||
key := strings.TrimSpace(r.hyAppKey)
|
||
|
||
secret := strings.TrimSpace(r.hyAppSecret)
|
||
|
||
bucket := strings.TrimSpace(r.fileBucket)
|
||
|
||
if key == "" || secret == "" || bucket == "" {
|
||
|
||
return fmt.Errorf("appKey/appSecret/fileBucket 未配置(检查 xk-api HY_APP_KEY、HY_APP_SECRET、HY_FILE_BUCKET)")
|
||
|
||
}
|
||
|
||
tok, err := fileauth.CreateUploadToken(key, secret, bucket, 0)
|
||
|
||
if err != nil {
|
||
|
||
return err
|
||
|
||
}
|
||
|
||
r.uploadToken = tok
|
||
|
||
return nil
|
||
|
||
}
|
||
|
||
// ReloadCloudConfig 从 xk-api GET /supervise/config 刷新机构、凭证与 uploadToken。
|
||
|
||
func (r *Runner) ReloadCloudConfig() error {
|
||
|
||
r.configMu.Lock()
|
||
|
||
defer r.configMu.Unlock()
|
||
|
||
conf, err := r.xk.Config()
|
||
|
||
if err != nil {
|
||
|
||
r.lastCloudOK = false
|
||
|
||
r.lastConfigErr = err
|
||
|
||
applog.Appf("reload cloud config failed: %v", err)
|
||
|
||
return err
|
||
|
||
}
|
||
|
||
r.applyCloudConfig(conf)
|
||
|
||
if strings.TrimSpace(r.uploadToken) == "" {
|
||
|
||
applog.Appf("warning: uploadToken empty after config reload")
|
||
|
||
}
|
||
|
||
applog.Appf("cloud config reloaded organID=%s appKey=%s…", conf.OrganID, previewKey(r.hyAppKey))
|
||
|
||
return nil
|
||
|
||
}
|
||
|
||
// ConfigSnapshot 返回当前配置快照(读锁)。
|
||
|
||
func (r *Runner) ConfigSnapshot() ConfigSnapshot {
|
||
|
||
r.configMu.RLock()
|
||
|
||
defer r.configMu.RUnlock()
|
||
|
||
snap := ConfigSnapshot{
|
||
|
||
Cloud: r.lastCloud,
|
||
|
||
CloudOK: r.lastCloudOK,
|
||
|
||
RefreshedAt: r.configRefreshedAt,
|
||
|
||
Local: r.cfg,
|
||
|
||
EffectiveOrgan: r.organ,
|
||
|
||
EffectiveAppKey: r.hyAppKey,
|
||
|
||
EffectiveSecret: r.hyAppSecret,
|
||
|
||
EffectiveAesKey: r.hyAesKey,
|
||
|
||
EffectiveFileBucket: r.fileBucket,
|
||
|
||
UploadToken: r.uploadToken,
|
||
|
||
UploadTokenSource: "local-fileauth-java",
|
||
|
||
CloudUploadToken: r.cloudUploadToken,
|
||
|
||
FileUploadURL: r.fileUploadURL,
|
||
}
|
||
|
||
if r.lastConfigErr != nil {
|
||
|
||
snap.CloudFetchError = r.lastConfigErr.Error()
|
||
|
||
}
|
||
|
||
return snap
|
||
|
||
}
|
||
|
||
func previewKey(s string) string {
|
||
|
||
s = strings.TrimSpace(s)
|
||
|
||
if len(s) <= 12 {
|
||
|
||
if s == "" {
|
||
|
||
return "(empty)"
|
||
|
||
}
|
||
|
||
return s
|
||
|
||
}
|
||
|
||
return s[:8] + "…"
|
||
|
||
}
|