provider.go

 1package config
 2
 3import (
 4	"encoding/json"
 5	"os"
 6	"path/filepath"
 7	"sync"
 8
 9	"github.com/charmbracelet/crush/internal/fur/client"
10	"github.com/charmbracelet/crush/internal/fur/provider"
11)
12
13var fur = client.New()
14
15var (
16	providerOnc  sync.Once // Ensures the initialization happens only once
17	providerList []provider.Provider
18	// UseMockProviders can be set to true in tests to avoid API calls
19	UseMockProviders bool
20)
21
22func providersPath() string {
23	return filepath.Join(baseDataPath(), "providers.json")
24}
25
26func saveProviders(providers []provider.Provider) error {
27	path := providersPath()
28	dir := filepath.Dir(path)
29	if err := os.MkdirAll(dir, 0o755); err != nil {
30		return err
31	}
32
33	data, err := json.MarshalIndent(providers, "", "  ")
34	if err != nil {
35		return err
36	}
37
38	return os.WriteFile(path, data, 0o644)
39}
40
41func loadProviders() ([]provider.Provider, error) {
42	path := providersPath()
43	data, err := os.ReadFile(path)
44	if err != nil {
45		return nil, err
46	}
47
48	var providers []provider.Provider
49	err = json.Unmarshal(data, &providers)
50	return providers, err
51}
52
53func Providers() []provider.Provider {
54	providerOnc.Do(func() {
55		// Use mock providers when testing
56		if UseMockProviders {
57			providerList = MockProviders()
58			return
59		}
60
61		// Try to get providers from upstream API
62		if providers, err := fur.GetProviders(); err == nil {
63			providerList = providers
64			// Save providers locally for future fallback
65			_ = saveProviders(providers)
66		} else {
67			// If upstream fails, try to load from local cache
68			if localProviders, localErr := loadProviders(); localErr == nil {
69				providerList = localProviders
70			} else {
71				// If both fail, return empty list
72				providerList = []provider.Provider{}
73			}
74		}
75	})
76	return providerList
77}
78
79// ResetProviders resets the provider cache. Useful for testing.
80func ResetProviders() {
81	providerOnc = sync.Once{}
82	providerList = nil
83}