Files
datascape/cmd/companion/config.go
T
2026-05-08 20:47:02 +02:00

93 lines
2.2 KiB
Go

package main
import (
"encoding/json"
"errors"
"fmt"
"os"
"path/filepath"
"runtime"
)
const defaultPort = 17680
type config struct {
WikiRoot string `json:"wikiRoot"`
AllowedOrigins []string `json:"allowedOrigins"`
Port int `json:"port,omitempty"`
}
// configPath returns the platform-conventional config path.
//
// Windows: %APPDATA%\datascape\companion.json
// Linux: $XDG_CONFIG_HOME/datascape/companion.json
// (fallback ~/.config/datascape/companion.json)
func configPath() (string, error) {
if runtime.GOOS == "windows" {
appData := os.Getenv("APPDATA")
if appData == "" {
return "", errors.New("APPDATA not set")
}
return filepath.Join(appData, "datascape", "companion.json"), nil
}
if x := os.Getenv("XDG_CONFIG_HOME"); x != "" {
return filepath.Join(x, "datascape", "companion.json"), nil
}
home, err := os.UserHomeDir()
if err != nil {
return "", err
}
return filepath.Join(home, ".config", "datascape", "companion.json"), nil
}
// loadOrInitConfig reads the on-disk config, creating a default file if none
// exists. Returns the resolved config (with port defaulted) and the path.
func loadOrInitConfig() (*config, string, error) {
p, err := configPath()
if err != nil {
return nil, "", err
}
data, err := os.ReadFile(p)
if errors.Is(err, os.ErrNotExist) {
cfg := &config{AllowedOrigins: []string{}, Port: defaultPort}
if err := writeConfigFile(p, cfg); err != nil {
return nil, p, err
}
return cfg, p, nil
}
if err != nil {
return nil, p, err
}
var cfg config
if err := json.Unmarshal(data, &cfg); err != nil {
return nil, p, fmt.Errorf("parse config: %w", err)
}
if cfg.Port == 0 {
cfg.Port = defaultPort
}
if cfg.AllowedOrigins == nil {
cfg.AllowedOrigins = []string{}
}
return &cfg, p, nil
}
// writeConfigFile atomically writes cfg to p (write-temp + rename).
func writeConfigFile(p string, cfg *config) error {
if err := os.MkdirAll(filepath.Dir(p), 0755); err != nil {
return err
}
out := *cfg
if out.AllowedOrigins == nil {
out.AllowedOrigins = []string{}
}
data, err := json.MarshalIndent(out, "", " ")
if err != nil {
return err
}
tmp := p + ".tmp"
if err := os.WriteFile(tmp, data, 0644); err != nil {
return err
}
return os.Rename(tmp, p)
}