package config import ( "encoding/json" "fmt" "os" "path/filepath" ) // AutoConnectRule defines a rule for automatic device connection type AutoConnectRule struct { BusID string `json:"bus_id,omitempty"` VendorID string `json:"vendor_id,omitempty"` ProductID string `json:"product_id,omitempty"` ClientName string `json:"client_name,omitempty"` } // Config holds the client configuration type Config struct { RelayAddr string `json:"relay_addr"` // e.g. "ws://localhost:8443" or "wss://relay.example.com:8443" Hash string `json:"hash"` // SHA256 hash of 3 tokens Mode string `json:"mode"` // "share" or "use" Name string `json:"name"` // friendly name for this client WebPort int `json:"web_port"` // web UI port (default 8080) // Tokens (optional, stored for convenience - hash is what matters) Token1 string `json:"token1,omitempty"` Token2 string `json:"token2,omitempty"` Token3 string `json:"token3,omitempty"` // Auto-connect rules (use mode only) AutoConnect []AutoConnectRule `json:"auto_connect,omitempty"` } // DefaultConfig returns a config with sensible defaults func DefaultConfig() *Config { hostname, _ := os.Hostname() if hostname == "" { hostname = "unknown" } return &Config{ RelayAddr: "ws://localhost:8443", Mode: "use", Name: hostname, WebPort: 8080, } } // DefaultConfigPath returns the default config file path func DefaultConfigPath() string { home, err := os.UserHomeDir() if err != nil { return "usb-client.json" } return filepath.Join(home, ".usb-server", "config.json") } // Load reads config from a JSON file func Load(path string) (*Config, error) { data, err := os.ReadFile(path) if err != nil { return nil, fmt.Errorf("reading config: %w", err) } cfg := DefaultConfig() if err := json.Unmarshal(data, cfg); err != nil { return nil, fmt.Errorf("parsing config: %w", err) } return cfg, nil } // Save writes config to a JSON file func (c *Config) Save(path string) error { dir := filepath.Dir(path) if err := os.MkdirAll(dir, 0700); err != nil { return fmt.Errorf("creating config directory: %w", err) } data, err := json.MarshalIndent(c, "", " ") if err != nil { return fmt.Errorf("encoding config: %w", err) } if err := os.WriteFile(path, data, 0600); err != nil { return fmt.Errorf("writing config: %w", err) } return nil }