summaryrefslogtreecommitdiff
path: root/internal/state
diff options
context:
space:
mode:
authorSergeiEU <39683682+SergeiEU@users.noreply.github.com>2026-04-01 10:17:15 +0400
committerSergeiEU <39683682+SergeiEU@users.noreply.github.com>2026-04-01 10:17:15 +0400
commit1bd203c5555046b7ee4fbfe2f822eb3d03571ad7 (patch)
treed8c85273ede547e03a5727bf185f5d07e87b4a08 /internal/state
downloadvpnem-1bd203c5555046b7ee4fbfe2f822eb3d03571ad7.tar.gz
vpnem-1bd203c5555046b7ee4fbfe2f822eb3d03571ad7.tar.bz2
vpnem-1bd203c5555046b7ee4fbfe2f822eb3d03571ad7.zip
Initial importHEADmain
Diffstat (limited to 'internal/state')
-rw-r--r--internal/state/state.go137
1 files changed, 137 insertions, 0 deletions
diff --git a/internal/state/state.go b/internal/state/state.go
new file mode 100644
index 0000000..83f77b1
--- /dev/null
+++ b/internal/state/state.go
@@ -0,0 +1,137 @@
+package state
+
+import (
+ "encoding/json"
+ "os"
+ "path/filepath"
+ "sync"
+ "time"
+)
+
+// AppState holds persistent client state.
+type AppState struct {
+ SelectedServer string `json:"selected_server"`
+ SelectedMode string `json:"selected_mode"`
+ LastSync time.Time `json:"last_sync"`
+ AutoConnect bool `json:"auto_connect"`
+ EnabledRuleSets map[string]bool `json:"enabled_rule_sets,omitempty"`
+ CustomBypass []string `json:"custom_bypass_processes,omitempty"`
+}
+
+// Store manages persistent state on disk.
+type Store struct {
+ mu sync.Mutex
+ path string
+ data AppState
+}
+
+// NewStore creates a state store at the given path.
+func NewStore(dataDir string) *Store {
+ return &Store{
+ path: filepath.Join(dataDir, "state.json"),
+ data: AppState{
+ SelectedMode: "Комбо (приложения + Re-filter)",
+ AutoConnect: false,
+ },
+ }
+}
+
+// Load reads state from disk. Returns default state if file doesn't exist.
+func (s *Store) Load() error {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+
+ data, err := os.ReadFile(s.path)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return nil
+ }
+ return err
+ }
+ return json.Unmarshal(data, &s.data)
+}
+
+// Save writes state to disk.
+func (s *Store) Save() error {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+
+ if err := os.MkdirAll(filepath.Dir(s.path), 0o755); err != nil {
+ return err
+ }
+
+ data, err := json.MarshalIndent(s.data, "", " ")
+ if err != nil {
+ return err
+ }
+ return os.WriteFile(s.path, data, 0o644)
+}
+
+// Get returns a copy of the current state.
+func (s *Store) Get() AppState {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ return s.data
+}
+
+// SetServer updates the selected server.
+func (s *Store) SetServer(tag string) {
+ s.mu.Lock()
+ s.data.SelectedServer = tag
+ s.mu.Unlock()
+}
+
+// SetMode updates the selected routing mode.
+func (s *Store) SetMode(mode string) {
+ s.mu.Lock()
+ s.data.SelectedMode = mode
+ s.mu.Unlock()
+}
+
+// SetLastSync records the last sync time.
+func (s *Store) SetLastSync(t time.Time) {
+ s.mu.Lock()
+ s.data.LastSync = t
+ s.mu.Unlock()
+}
+
+// SetAutoConnect updates the auto-connect setting.
+func (s *Store) SetAutoConnect(v bool) {
+ s.mu.Lock()
+ s.data.AutoConnect = v
+ s.mu.Unlock()
+}
+
+// SetRuleSetEnabled enables/disables an optional rule-set.
+func (s *Store) SetRuleSetEnabled(tag string, enabled bool) {
+ s.mu.Lock()
+ if s.data.EnabledRuleSets == nil {
+ s.data.EnabledRuleSets = make(map[string]bool)
+ }
+ s.data.EnabledRuleSets[tag] = enabled
+ s.mu.Unlock()
+}
+
+// IsRuleSetEnabled checks if a rule-set is enabled.
+func (s *Store) IsRuleSetEnabled(tag string) bool {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ if s.data.EnabledRuleSets == nil {
+ return false
+ }
+ return s.data.EnabledRuleSets[tag]
+}
+
+// SetCustomBypass sets custom bypass processes.
+func (s *Store) SetCustomBypass(processes []string) {
+ s.mu.Lock()
+ s.data.CustomBypass = processes
+ s.mu.Unlock()
+}
+
+// GetCustomBypass returns custom bypass processes.
+func (s *Store) GetCustomBypass() []string {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ return append([]string{}, s.data.CustomBypass...)
+}