package services import ( "encoding/json" "errors" "fmt" "os" "path/filepath" "slices" ) type Server struct { ID string `json:"id"` Name string `json:"name"` Host string `json:"host"` } type Config struct { Servers []Server `json:"servers"` SelectedServerID string `json:"selectedServerId"` } type ConfigService struct { path string config Config } func NewConfigService() (*ConfigService, error) { configDir, err := os.UserConfigDir() if err != nil { return nil, fmt.Errorf("get config dir: %w", err) } dir := filepath.Join(configDir, "tailscale-vpn") if err := os.MkdirAll(dir, 0o700); err != nil { return nil, fmt.Errorf("create config dir: %w", err) } path := filepath.Join(dir, "settings.json") if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) { if err := os.WriteFile(path, []byte(`{"servers":[]}`), 0o600); err != nil { return nil, fmt.Errorf("create config file: %w", err) } } data, err := os.ReadFile(path) if err != nil { return nil, fmt.Errorf("read config file: %w", err) } var cfg Config if err := json.Unmarshal(data, &cfg); err != nil { return nil, fmt.Errorf("parse config: %w", err) } return &ConfigService{path: path, config: cfg}, nil } func (s *ConfigService) GetServers() []Server { return s.config.Servers } func (s *ConfigService) GetServer(id string) (Server, bool) { for _, srv := range s.config.Servers { if srv.ID == id { return srv, true } } return Server{}, false } func (s *ConfigService) AddServer(name, host string) error { srv := Server{ ID: host, Name: name, Host: host, } s.config.Servers = append(s.config.Servers, srv) return s.Save() } func (s *ConfigService) RemoveServer(id string) error { s.config.Servers = slices.DeleteFunc(s.config.Servers, func(srv Server) bool { return srv.ID == id }) return s.Save() } func (s *ConfigService) GetSelectedServer() (Server, bool) { for _, srv := range s.config.Servers { if srv.ID == s.config.SelectedServerID { return srv, true } } return Server{}, false } func (s *ConfigService) SetSelectedServer(id string) error { for _, srv := range s.config.Servers { if srv.ID == id { s.config.SelectedServerID = id return s.Save() } } return fmt.Errorf("server not found") } func (s *ConfigService) UpdateServer(id, name, host string) error { for i, srv := range s.config.Servers { if srv.ID == id { s.config.Servers[i].Name = name s.config.Servers[i].Host = host s.config.Servers[i].ID = host return s.Save() } } return fmt.Errorf("server not found") } func (s *ConfigService) Save() error { data, err := json.MarshalIndent(s.config, "", " ") if err != nil { return fmt.Errorf("marshal config: %w", err) } if err := os.WriteFile(s.path, data, 0o600); err != nil { return fmt.Errorf("write config: %w", err) } return nil }