Files
flvx/go-gost/x/config/persist.go
T

96 lines
2.3 KiB
Go

package config
import (
"bytes"
"encoding/json"
"fmt"
"os"
"path/filepath"
"sync"
)
var (
persistPath string
persistMu sync.Mutex
persistEnable bool
)
// SetPersistPath sets the file path where runtime config changes will be
// automatically persisted. Call this once during agent startup before any
// OnUpdate mutations occur.
func SetPersistPath(path string) {
persistMu.Lock()
defer persistMu.Unlock()
persistPath = path
}
func PersistPath() string {
persistMu.Lock()
defer persistMu.Unlock()
return persistPath
}
// EnablePersist turns on automatic persistence. Call this after the initial
// config has been loaded (e.g. after program.Start) so that startup loading
// does not trigger redundant disk writes.
func EnablePersist() {
persistMu.Lock()
defer persistMu.Unlock()
persistEnable = true
}
// persist writes the current global config to the configured file atomically.
func persist() error {
persistMu.Lock()
defer persistMu.Unlock()
path := persistPath
enabled := persistEnable
if !enabled || path == "" {
return nil
}
cfg := Global()
if cfg == nil {
return nil
}
var buf bytes.Buffer
enc := json.NewEncoder(&buf)
enc.SetIndent("", " ")
if err := enc.Encode(cfg); err != nil {
fmt.Printf("⚠️ config persist: marshal failed: %v\n", err)
return fmt.Errorf("config persist: marshal failed: %w", err)
}
// Atomic write: write to temp file then rename
dir := filepath.Dir(path)
tmp, err := os.CreateTemp(dir, ".gost-*.tmp")
if err != nil {
fmt.Printf("⚠️ config persist: create temp file failed: %v\n", err)
return fmt.Errorf("config persist: create temp file failed: %w", err)
}
tmpName := tmp.Name()
if _, err := tmp.Write(buf.Bytes()); err != nil {
tmp.Close()
os.Remove(tmpName)
fmt.Printf("⚠️ config persist: write failed: %v\n", err)
return fmt.Errorf("config persist: write failed: %w", err)
}
if err := tmp.Close(); err != nil {
os.Remove(tmpName)
fmt.Printf("⚠️ config persist: close temp file failed: %v\n", err)
return fmt.Errorf("config persist: close temp file failed: %w", err)
}
if err := os.Rename(tmpName, path); err != nil {
os.Remove(tmpName)
fmt.Printf("⚠️ config persist: rename failed: %v\n", err)
return fmt.Errorf("config persist: rename failed: %w", err)
}
fmt.Printf("💾 节点配置已持久化到 %s\n", path)
return nil
}