93 lines
2.2 KiB
Go
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)
|
|
}
|