Files
xk-hy-transit-go/internal/logweb/configview.go

333 lines
6.6 KiB
Go
Raw Normal View History

2026-05-28 16:39:51 +08:00
package logweb
import (
"strings"
"time"
"xk-hy-transit-go/internal/config"
syncer "xk-hy-transit-go/internal/sync"
"xk-hy-transit-go/internal/xkapi"
)
// ConfigViewResponse Web 配置页 API 响应(敏感字段已脱敏)。
type ConfigViewResponse struct {
FetchedAt string `json:"fetchedAt"`
XkAPIBaseURL string `json:"xkApiBaseUrl"`
Cloud cloudConfigView `json:"cloud"`
LocalEnv localEnvView `json:"localEnv"`
Effective effectiveConfigView `json:"effective"`
Diagnostics []string `json:"diagnostics"`
CloudRaw map[string]any `json:"cloudRaw,omitempty"`
}
type cloudConfigView struct {
OrganID string `json:"organID"`
UnitID string `json:"unitID"`
OrganName string `json:"organName"`
HosCode string `json:"hosCode"`
HosName string `json:"hosName"`
FileBucket string `json:"fileBucket"`
FileUploadURL string `json:"fileUploadUrl"`
AppKeyPreview string `json:"appKeyPreview"`
AppSecretSet bool `json:"appSecretSet"`
AesKeySet bool `json:"aesKeySet"`
UploadTokenSet bool `json:"uploadTokenSet"`
UploadTokenPreview string `json:"uploadTokenPreview"`
RawError string `json:"rawError"`
}
type localEnvView struct {
HyAppKeyPreview string `json:"hyAppKeyPreview"`
HyAppSecretSet bool `json:"hyAppSecretSet"`
HyAesKeySet bool `json:"hyAesKeySet"`
HyFileBucket string `json:"hyFileBucket"`
FileUploadViaForward bool `json:"fileUploadViaForward"`
ForwardBaseURL string `json:"forwardBaseUrl"`
ForwardSharedSecretSet bool `json:"forwardSharedSecretSet"`
XkAPITokenSet bool `json:"xkApiTokenSet"`
}
type effectiveConfigView struct {
OrganID string `json:"organID"`
UnitID string `json:"unitID"`
OrganName string `json:"organName"`
AppKeyPreview string `json:"appKeyPreview"`
AppSecretSet bool `json:"appSecretSet"`
AesKeySet bool `json:"aesKeySet"`
FileBucket string `json:"fileBucket"`
UploadTokenSet bool `json:"uploadTokenSet"`
UploadTokenPreview string `json:"uploadTokenPreview"`
UploadTokenSource string `json:"uploadTokenSource"`
FileUploadURL string `json:"fileUploadURL"`
SourceNote string `json:"sourceNote"`
ConfigRefreshed string `json:"configRefreshedAt"`
}
func maskPreview(s string) string {
s = strings.TrimSpace(s)
if s == "" {
return ""
}
if len(s) <= 12 {
return s
}
return s[:8] + "****" + s[len(s)-4:]
}
func BuildConfigView(snap syncer.ConfigSnapshot, cfg config.Config) ConfigViewResponse {
cloud := snap.Cloud
localToken := strings.TrimSpace(snap.UploadToken)
cloudToken := strings.TrimSpace(snap.CloudUploadToken)
if cloudToken == "" {
cloudToken = strings.TrimSpace(cloud.UploadToken)
}
effectiveBucket := strings.TrimSpace(snap.EffectiveFileBucket)
view := ConfigViewResponse{
FetchedAt: time.Now().Format(time.RFC3339),
XkAPIBaseURL: cfg.XkAPIBaseURL,
Cloud: cloudConfigView{
OrganID: cloud.OrganID,
UnitID: cloud.UnitID,
OrganName: cloud.OrganName,
HosCode: cloud.HosCode,
HosName: cloud.HosName,
FileBucket: cloud.FileBucket,
FileUploadURL: cloud.FileUploadURL,
AppKeyPreview: maskPreview(cloud.AppKey),
AppSecretSet: strings.TrimSpace(cloud.AppSecret) != "",
AesKeySet: strings.TrimSpace(cloud.AesKey) != "",
UploadTokenSet: cloudToken != "",
UploadTokenPreview: maskPreview(cloudToken),
RawError: snap.CloudFetchError,
},
LocalEnv: localEnvView{
HyAppKeyPreview: maskPreview(cfg.HyAppKey),
HyAppSecretSet: strings.TrimSpace(cfg.HyAppSecret) != "",
HyAesKeySet: strings.TrimSpace(cfg.HyAesKey) != "",
HyFileBucket: cfg.HyFileBucket,
FileUploadViaForward: cfg.FileUploadViaForward,
ForwardBaseURL: cfg.ForwardBaseURL,
ForwardSharedSecretSet: strings.TrimSpace(cfg.ForwardSharedSecret) != "",
XkAPITokenSet: strings.TrimSpace(cfg.XkAPIToken) != "",
},
Effective: effectiveConfigView{
OrganID: snap.EffectiveOrgan.OrganID,
UnitID: snap.EffectiveOrgan.UnitID,
OrganName: snap.EffectiveOrgan.OrganName,
AppKeyPreview: maskPreview(snap.EffectiveAppKey),
AppSecretSet: strings.TrimSpace(snap.EffectiveSecret) != "",
AesKeySet: strings.TrimSpace(snap.EffectiveAesKey) != "",
FileBucket: effectiveBucket,
UploadTokenSet: localToken != "",
UploadTokenPreview: maskPreview(localToken),
UploadTokenSource: snap.UploadTokenSource,
FileUploadURL: snap.FileUploadURL,
2026-05-28 17:03:08 +08:00
SourceNote: "uploadTokenRunner 按 FileAuth.java 本地生成appKey/secret/bucket 云端非空优先",
2026-05-28 16:39:51 +08:00
ConfigRefreshed: formatTime(snap.RefreshedAt),
},
}
if !snap.CloudOK {
view.Diagnostics = append(view.Diagnostics, "无法连接 xk-api /supervise/config"+snap.CloudFetchError)
}
if effectiveBucket == "" {
view.Diagnostics = append(view.Diagnostics, "fileBucket 为空:请在 xk-api 配置 HY_FILE_BUCKET或 transit .env HY_FILE_BUCKET")
}
if !view.Effective.UploadTokenSet {
view.Diagnostics = append(view.Diagnostics, "本地 uploadToken 未生成:检查 HY_APP_KEY、HY_APP_SECRET、HY_FILE_BUCKET 后点「重新拉取」")
}
if cloudToken != "" && localToken != "" && cloudToken != localToken {
2026-05-28 17:03:08 +08:00
view.Diagnostics = append(view.Diagnostics, "云端预生成 uploadToken 与 Runner 本地 token 不一致(已使用本地 FileAuth.java以 Runner 为准)")
2026-05-28 16:39:51 +08:00
}
if cloud.AppKey != "" && cfg.HyAppKey != "" && cloud.AppKey != cfg.HyAppKey {
view.Diagnostics = append(view.Diagnostics, "云端 appKey 与 transit 本地 HY_APP_KEY 不一致,生效值以云端为准,请点「重新拉取」")
}
if view.Effective.AppKeyPreview == "" {
view.Diagnostics = append(view.Diagnostics, "生效 appKey 为空:请在 xk-api 或 transit .env 配置 HY_APP_KEY")
}
if cfg.FileUploadViaForward {
if view.LocalEnv.ForwardSharedSecretSet {
view.Diagnostics = append(view.Diagnostics, "PDF 经 forward 上传:请确认 forward .env 的 FORWARD_SHARED_SECRET 与 transit 一致")
}
view.Diagnostics = append(view.Diagnostics, "PDF 经 forward 上传:请确认 forward ALLOW_IPS 包含中转机 IP否则 HTTP 403 body=forbidden")
}
view.CloudRaw = redactCloudRaw(cloud)
return view
}
func formatTime(t time.Time) string {
if t.IsZero() {
return "-"
}
return t.Format(time.RFC3339)
}
func redactCloudRaw(c xkapi.ConfigResponse) map[string]any {
return map[string]any{
"organID": c.OrganID,
"unitID": c.UnitID,
"organName": c.OrganName,
"hosCode": c.HosCode,
"hosName": c.HosName,
"fileUploadUrl": c.FileUploadURL,
"fileBucket": c.FileBucket,
"appKey": maskPreview(c.AppKey),
"appSecret": boolLabel(c.AppSecret != ""),
"aesKey": boolLabel(c.AesKey != ""),
"uploadToken": maskPreview(c.UploadToken),
}
}
func boolLabel(set bool) string {
if set {
return "(已配置)"
}
return "(未配置)"
}