1package config
2
3import (
4 "encoding/json"
5 "os"
6 "path/filepath"
7 "runtime"
8 "sync"
9
10 "github.com/charmbracelet/catwalk/pkg/catwalk"
11)
12
13type ProviderClient interface {
14 GetProviders() ([]catwalk.Provider, error)
15}
16
17var (
18 providerOnce sync.Once
19 providerList []catwalk.Provider
20)
21
22// file to cache provider data
23func providerCacheFileData() string {
24 xdgDataHome := os.Getenv("XDG_DATA_HOME")
25 if xdgDataHome != "" {
26 return filepath.Join(xdgDataHome, appName, "providers.json")
27 }
28
29 // return the path to the main data directory
30 // for windows, it should be in `%LOCALAPPDATA%/crush/`
31 // for linux and macOS, it should be in `$HOME/.local/share/crush/`
32 if runtime.GOOS == "windows" {
33 localAppData := os.Getenv("LOCALAPPDATA")
34 if localAppData == "" {
35 localAppData = filepath.Join(os.Getenv("USERPROFILE"), "AppData", "Local")
36 }
37 return filepath.Join(localAppData, appName, "providers.json")
38 }
39
40 return filepath.Join(os.Getenv("HOME"), ".local", "share", appName, "providers.json")
41}
42
43func saveProvidersInCache(path string, providers []catwalk.Provider) error {
44 dir := filepath.Dir(path)
45 if err := os.MkdirAll(dir, 0o755); err != nil {
46 return err
47 }
48
49 data, err := json.MarshalIndent(providers, "", " ")
50 if err != nil {
51 return err
52 }
53
54 return os.WriteFile(path, data, 0o644)
55}
56
57func loadProvidersFromCache(path string) ([]catwalk.Provider, error) {
58 data, err := os.ReadFile(path)
59 if err != nil {
60 return nil, err
61 }
62
63 var providers []catwalk.Provider
64 err = json.Unmarshal(data, &providers)
65 return providers, err
66}
67
68func loadProviders(path string, client ProviderClient) ([]catwalk.Provider, error) {
69 providers, err := client.GetProviders()
70 if err != nil {
71 fallbackToCache, err := loadProvidersFromCache(path)
72 if err != nil {
73 return nil, err
74 }
75 providers = fallbackToCache
76 } else {
77 if err := saveProvidersInCache(path, providerList); err != nil {
78 return nil, err
79 }
80 }
81 return providers, nil
82}
83
84func Providers() ([]catwalk.Provider, error) {
85 return LoadProviders(catwalk.NewWithURL(catwalkURL))
86}
87
88func LoadProviders(client ProviderClient) ([]catwalk.Provider, error) {
89 var err error
90 providerOnce.Do(func() {
91 providerList, err = loadProviders(providerCacheFileData(), client)
92 })
93 if err != nil {
94 return nil, err
95 }
96 return providerList, nil
97}