package config import ( "encoding/json" "fmt" "os" "path/filepath" "strings" "sync" ) // APIKeys holds external service credentials. type APIKeys struct { TPDBAPIKey string `json:"tpdb_api_key"` AEAPIKey string `json:"ae_api_key"` StashDBAPIKey string `json:"stashdb_api_key"` StashDBEndpoint string `json:"stashdb_endpoint"` } const apiKeysFile = "config/api_keys.json" var ( keysMu sync.RWMutex cached *APIKeys ) // GetAPIKeys returns the configured API keys, preferring the persisted file, falling back to environment variables. func GetAPIKeys() APIKeys { keysMu.RLock() if cached != nil { defer keysMu.RUnlock() return *cached } keysMu.RUnlock() keys := APIKeys{} // Try file first. if b, err := os.ReadFile(apiKeysFile); err == nil { _ = json.Unmarshal(b, &keys) } // Fallback to env if fields are empty. if keys.TPDBAPIKey == "" { keys.TPDBAPIKey = os.Getenv("TPDB_API_KEY") } if keys.AEAPIKey == "" { keys.AEAPIKey = os.Getenv("AE_API_KEY") } if keys.StashDBAPIKey == "" { keys.StashDBAPIKey = os.Getenv("STASHDB_API_KEY") } if keys.StashDBEndpoint == "" { keys.StashDBEndpoint = os.Getenv("STASHDB_ENDPOINT") } if keys.StashDBEndpoint == "" { keys.StashDBEndpoint = "https://stashdb.org/graphql" } keysMu.Lock() cached = &keys keysMu.Unlock() return keys } // SaveAPIKeys persists API keys to disk (config/api_keys.json) and updates cache. func SaveAPIKeys(keys APIKeys) error { keysMu.Lock() defer keysMu.Unlock() // Normalize whitespace. keys.TPDBAPIKey = strings.TrimSpace(keys.TPDBAPIKey) keys.AEAPIKey = strings.TrimSpace(keys.AEAPIKey) keys.StashDBAPIKey = strings.TrimSpace(keys.StashDBAPIKey) keys.StashDBEndpoint = strings.TrimSpace(keys.StashDBEndpoint) if keys.StashDBEndpoint == "" { keys.StashDBEndpoint = "https://stashdb.org/graphql" } if err := os.MkdirAll(filepath.Dir(apiKeysFile), 0o755); err != nil { return fmt.Errorf("create config dir: %w", err) } data, err := json.MarshalIndent(keys, "", " ") if err != nil { return fmt.Errorf("marshal keys: %w", err) } if err := os.WriteFile(apiKeysFile, data, 0o600); err != nil { return fmt.Errorf("write keys file: %w", err) } cached = &keys return nil }