1package common
2
3import (
4 "errors"
5 "fmt"
6 "io/fs"
7 "os"
8 "os/user"
9 "path/filepath"
10 "runtime"
11
12 "github.com/bnema/gordon/pkg/parser"
13)
14
15type Config struct {
16 General GeneralConfig `yaml:"General"`
17 Http HttpConfig `yaml:"Http"`
18 Admin AdminConfig `yaml:"Admin"`
19 ContainerEngine ContainerEngineConfig `yaml:"ContainerEngine"`
20 Build BuildConfig `yaml:"-"`
21}
22
23type BuildConfig struct {
24 RunEnv string `yaml:"-"` // come from env
25 BuildVersion string `yaml:"-"` // come from build ldflags
26}
27
28type AdminConfig struct {
29 Path string `yaml:"path"`
30}
31
32type GeneralConfig struct {
33 StorageDir string `yaml:"storageDir"`
34 Token string `yaml:"token"`
35}
36type HttpConfig struct {
37 Port string `yaml:"port"`
38 Domain string `yaml:"domain"`
39 SubDomain string `yaml:"subDomain"`
40 BackendURL string `yaml:"backendURL"`
41 Https bool `yaml:"https"`
42}
43
44type ContainerEngineConfig struct {
45 Sock string `yaml:"dockersock"`
46 PodmanSock string `yaml:"podmansock"`
47 Podman bool `yaml:"podman"`
48 Network string `yaml:"network"`
49}
50
51// Default values
52var (
53 sock = "/var/run/docker.sock"
54 podmansock = "/run/user/1000/podman/podman.sock"
55)
56
57func isMaybeRunningInDocker() bool { // Thanks Pocketbase
58 _, err := os.Stat("/.dockerenv")
59 return err == nil
60}
61
62func getConfigDir() (string, error) {
63 usr, err := user.Current()
64 if err != nil {
65 return "", fmt.Errorf("error getting user's home directory: %w", err)
66 }
67
68 if isMaybeRunningInDocker() {
69 return ".", nil // The directory where the binary is located
70 }
71
72 var configDir string
73 if runtime.GOOS == "windows" {
74 configDir = filepath.Join(usr.HomeDir, "AppData", "Roaming", "Gordon")
75 } else {
76 configDir = filepath.Join(usr.HomeDir, ".config", "Gordon")
77 }
78 return configDir, nil
79}
80
81func readAndUnmarshalConfig(fs fs.FS, filePath string, config *Config) error {
82 err := parser.ParseYAMLFile(fs, filePath, config)
83 if err != nil {
84 return fmt.Errorf("error reading and unmarshaling configuration file: %w", err)
85 }
86 return nil
87}
88
89func (config *Config) LoadConfig() (*Config, error) {
90 configDir, err := getConfigDir()
91 if err != nil {
92 return nil, fmt.Errorf("error getting configuration directory: %w", err)
93 }
94
95 configFilePath := filepath.Join(configDir, "config.yml")
96
97 _, err = os.Stat(configFilePath)
98 if errors.Is(err, fs.ErrNotExist) {
99 fmt.Printf("Config file not found, creating it at %s\n", configFilePath)
100
101 // Create config dir if it doesn't exist
102 err = os.MkdirAll(configDir, 0755)
103 if err != nil {
104 return nil, fmt.Errorf("error creating configuration directory: %w", err)
105 }
106
107 // Create config file with the default values of ContainerEngineConfig
108 config = &Config{
109 ContainerEngine: ContainerEngineConfig{
110 Sock: sock,
111 PodmanSock: podmansock,
112 Podman: ReadUserInput("Are you using podman ? (y/n)") == "y",
113 },
114 }
115
116 err = config.SaveConfig()
117 if err != nil {
118 return nil, fmt.Errorf("error saving new configuration: %w", err)
119 }
120 return config, nil
121 }
122
123 if err != nil {
124 return nil, fmt.Errorf("error checking configuration file: %w", err)
125 }
126
127 err = readAndUnmarshalConfig(os.DirFS(configDir), "config.yml", config)
128 if err != nil {
129 return nil, err
130 }
131
132 // Load run env
133 config.Build.RunEnv = os.Getenv("RUN_ENV")
134
135 if config.Build.RunEnv == "" {
136 config.Build.RunEnv = "prod"
137 }
138
139 return config, nil
140}
141
142func (config *Config) SaveConfig() error {
143 configDir, err := getConfigDir()
144 if err != nil {
145 return fmt.Errorf("error getting configuration directory: %w", err)
146 }
147 configFilePath := filepath.Join(configDir, "config.yml")
148
149 err = parser.WriteYAMLFile(configFilePath, config)
150 if err != nil {
151 return fmt.Errorf("error writing configuration file: %w", err)
152 }
153
154 fmt.Printf("Configuration saved to %s\n", configFilePath)
155 return nil
156}
157
158func (config *Config) GetToken() (string, error) {
159 token := config.General.Token
160 if token == "" {
161 return "", fmt.Errorf("no token found in config.yml")
162 }
163
164 return token, nil
165
166}
167
168// GetBuildVersion returns the build version
169func (config *BuildConfig) GetBuildVersion() string {
170 return config.BuildVersion
171}
172
173// GetRunEnv returns the run environment
174func (config *BuildConfig) GetRunEnv() string {
175 return config.RunEnv
176}