Add companion application
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user