diff options
| author | sergei <sergei@em-sysadmin.xyz> | 2026-04-14 06:23:55 +0400 |
|---|---|---|
| committer | sergei <sergei@em-sysadmin.xyz> | 2026-04-14 06:23:55 +0400 |
| commit | 3d51aa455006903345f554a2dd90034993796114 (patch) | |
| tree | 62a7be2faf047f5eb7886feebc3b815556f03d7f /internal/control/state.go | |
| download | vpnem-3d51aa455006903345f554a2dd90034993796114.tar.gz vpnem-3d51aa455006903345f554a2dd90034993796114.tar.bz2 vpnem-3d51aa455006903345f554a2dd90034993796114.zip | |
- Multi-protocol VPS nodes (VLESS-REALITY + Hysteria2 + SOCKS5)
- Smart load balancing via recommendation API
- Windows/Linux client (Go + Wails + sing-box)
- Server API with RealIP detection and connection tracking
- Auto-deployment via vpnui control plane
- Silent Windows installer with UAC elevation
- Load-based server recommendation (no sticky sessions)
- Best Server one-click connection workflow
Diffstat (limited to 'internal/control/state.go')
| -rw-r--r-- | internal/control/state.go | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/internal/control/state.go b/internal/control/state.go new file mode 100644 index 0000000..7fc7827 --- /dev/null +++ b/internal/control/state.go @@ -0,0 +1,71 @@ +package control + +import ( + "encoding/json" + "errors" + "os" + "path/filepath" + "sort" + "time" +) + +type NodeState struct { + NodeID string `json:"node_id"` + BootstrapStatus string `json:"bootstrap_status"` + LastBootstrapAt *time.Time `json:"last_bootstrap_at,omitempty"` + LastHealthCheckAt *time.Time `json:"last_health_check_at,omitempty"` + LastDNSSyncAt *time.Time `json:"last_dns_sync_at,omitempty"` + PublicHost string `json:"public_host,omitempty"` + Services []ServiceStatus `json:"services,omitempty"` + Metadata map[string]any `json:"metadata,omitempty"` +} + +type ServiceStatus struct { + Type string `json:"type"` + Status string `json:"status"` + Port int `json:"port"` +} + +func LoadNodeState(dir, nodeID string) (*NodeState, error) { + data, err := os.ReadFile(filepath.Join(dir, nodeID+".json")) + if err != nil { + return nil, err + } + + var state NodeState + if err := json.Unmarshal(data, &state); err != nil { + return nil, err + } + return &state, nil +} + +func SaveNodeState(dir string, state NodeState) error { + if err := os.MkdirAll(dir, 0o755); err != nil { + return err + } + + sort.Slice(state.Services, func(i, j int) bool { + return state.Services[i].Type < state.Services[j].Type + }) + + data, err := json.MarshalIndent(state, "", " ") + if err != nil { + return err + } + data = append(data, '\n') + + tmpPath := filepath.Join(dir, state.NodeID+".json.tmp") + finalPath := filepath.Join(dir, state.NodeID+".json") + if err := os.WriteFile(tmpPath, data, 0o600); err != nil { + return err + } + return os.Rename(tmpPath, finalPath) +} + +func DeleteNodeState(dir, nodeID string) error { + err := os.Remove(filepath.Join(dir, nodeID+".json")) + if errors.Is(err, os.ErrNotExist) { + return nil + } + return err +} |
