From 17117e2376f5a5f4a0167dfdb3b1ac8ce0ac843a Mon Sep 17 00:00:00 2001 From: chris bell Date: Fri, 5 Jun 2026 20:58:50 -0500 Subject: [PATCH] Can now set custom config path flag when starting daemon --- .gitignore | 2 ++ config.go | 8 +++++--- instance_config.go | 45 ++++++++++++++++++++++++++++++++++++++++ main.go | 51 +++++++++++++++++++++++++++------------------- 4 files changed, 82 insertions(+), 24 deletions(-) diff --git a/.gitignore b/.gitignore index c9d31a5..b7893aa 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ .direnv .cache .vscode +vssm +test/ \ No newline at end of file diff --git a/config.go b/config.go index 5e15c98..9b04b4d 100644 --- a/config.go +++ b/config.go @@ -9,6 +9,7 @@ import ( type AppConfig struct { Storage struct { + AppDataDir string `json:"app_data_dir"` InstallDir string `json:"install_dir"` InstancesDir string `json:"instances_dir"` BackupDir string `json:"backup_dir"` @@ -16,18 +17,18 @@ type AppConfig struct { } `json:"storage"` Daemon struct { - // UseNixOs bool `json:"use_nixos"` ListenAddress string `json:"listen_address"` } Instances map[string]VsServerConfigOptions `json:"instances"` } -func DefaultConfig() *AppConfig { +func CreateConfigWithDefaults(configPath string) *AppConfig { home, _ := os.UserHomeDir() basePath := filepath.Join(home, ".local", "share", "vssm") cfg := &AppConfig{} + cfg.Storage.AppDataDir = basePath cfg.Storage.InstallDir = filepath.Join(basePath, "installs") cfg.Storage.InstancesDir = filepath.Join(basePath, "instances") cfg.Storage.BackupDir = filepath.Join(basePath, "backups") @@ -42,7 +43,7 @@ func DefaultConfig() *AppConfig { func LoadOrCreateConfig(configPath string) (*AppConfig, error) { if _, err := os.Stat(configPath); os.IsNotExist(err) { - cfg := DefaultConfig() + cfg := CreateConfigWithDefaults(configPath) if err := os.MkdirAll(filepath.Dir(configPath), 0755); err != nil { return nil, fmt.Errorf("Failed to create config directory: %w", err) @@ -69,6 +70,7 @@ func LoadOrCreateConfig(configPath string) (*AppConfig, error) { } dirs := []string{ + cfg.Storage.AppDataDir, cfg.Storage.InstallDir, cfg.Storage.InstancesDir, cfg.Storage.BackupDir, diff --git a/instance_config.go b/instance_config.go index 1494ea5..a4d368d 100644 --- a/instance_config.go +++ b/instance_config.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "io" + "net/http" "os" "path/filepath" "strings" @@ -28,6 +29,10 @@ func PrepareInstanceConfig(templateVersion string, instanceConfigPath string, op func SyncInstanceConfig(templateVersion string, instanceConfigPath string, options VsServerConfigOptions, cfg *AppConfig) error { templatePath := filepath.Join(cfg.Storage.ConfigTemplatesDir, templateVersion, "serverconfig.json") + if err := ensureTemplateExists(templateVersion, templatePath, cfg); err != nil { + return fmt.Errorf("failed ensuring configuration template availability: %w", err) + } + if _, err := os.Stat(instanceConfigPath); os.IsNotExist(err) { if err := os.MkdirAll(filepath.Dir(instanceConfigPath), 0755); err != nil { return fmt.Errorf("failed creating instance directory tree: %w", err) @@ -91,3 +96,43 @@ func SyncInstanceConfig(templateVersion string, instanceConfigPath string, optio return os.WriteFile(instanceConfigPath, updatedData, 0644) } + +func ensureTemplateExists(version string, targetPath string, cfg *AppConfig) error { + if _, err := os.Stat(targetPath); err == nil { + return nil + } + + fmt.Printf("Template for version %s not found locally. Fetching remote layout from git server...\n", version) + + if err := os.MkdirAll(filepath.Dir(targetPath), 0755); err != nil { + return fmt.Errorf("failed to create local template cache directory: %w", err) + } + + remoteURL := fmt.Sprintf("https://git.bellsworne.tech/chrisbell/vssm_config_templates/raw/branch/main/%s/serverconfig.json", version) + + resp, err := http.Get(remoteURL) + if err != nil { + return fmt.Errorf("network error attempting to pull config template: %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode == http.StatusNotFound { + return fmt.Errorf("version template '%s' does not exist in the remote git repository asset tree", version) + } else if resp.StatusCode != http.StatusOK { + return fmt.Errorf("remote git mirror returned unexpected HTTP status: %s", resp.Status) + } + + out, err := os.Create(targetPath) + if err != nil { + return fmt.Errorf("failed creating cache file hook on system storage: %w", err) + } + defer out.Close() + + _, err = io.Copy(out, resp.Body) + if err != nil { + return fmt.Errorf("failed stream-writing network payload cache frame to disk: %w", err) + } + + fmt.Printf("Successfully cached configuration layout template for version %s\n", version) + return nil +} diff --git a/main.go b/main.go index 26de878..70cd0e1 100644 --- a/main.go +++ b/main.go @@ -3,6 +3,7 @@ package main import ( "bytes" "encoding/json" + "flag" "fmt" "io" "log" @@ -19,20 +20,28 @@ func main() { log.Fatalf("Could not locate user home dir: %v", err) } - configPath := filepath.Join(home, ".config", "vssm", "config.json") - cfg, err := LoadOrCreateConfig(configPath) - if err != nil { - log.Fatalf("Initialization failed: %v", err) - } + defaultConfigPath := filepath.Join(home, ".config", "vssm", "config.json") - if len(os.Args) < 2 { + configFlag := flag.String("config", defaultConfigPath, "Explicit path targeting a custom vssm config.json profile") + + flag.Usage = printUsage + flag.Parse() + + args := flag.Args() + if len(args) < 1 { printUsage() return } - subCommand := os.Args[1] + cfg, err := LoadOrCreateConfig(*configFlag) + if err != nil { + log.Fatalf("Initialization failed: %v", err) + } + + subCommand := args[0] switch subCommand { + case "daemon": fmt.Println("Initializing VS server manager background supervisor...") if err := StartDaemon(cfg); err != nil { @@ -40,33 +49,33 @@ func main() { } case "create": - if len(os.Args) < 4 { - log.Fatalf("Usage: go run . create ") + if len(args) < 3 { + log.Fatalf("Usage: vssm create ") } - name := os.Args[2] - version := os.Args[3] + name := args[1] + version := args[2] sendIPCRequest(cfg, "POST", fmt.Sprintf("/instances/create?name=%s&version=%s", url.QueryEscape(name), url.QueryEscape(version)), nil) case "start": - if len(os.Args) < 3 { - log.Fatalf("Usage: go run . start ") + if len(args) < 2 { + log.Fatalf("Usage: vssm start ") } - name := os.Args[2] + name := args[1] sendIPCRequest(cfg, "POST", fmt.Sprintf("/instances/start?name=%s", url.QueryEscape(name)), nil) case "stop": - if len(os.Args) < 3 { - log.Fatalf("Usage: go run . stop ") + if len(args) < 2 { + log.Fatalf("Usage: vssm stop ") } - name := os.Args[2] + name := args[1] sendIPCRequest(cfg, "POST", fmt.Sprintf("/instances/stop?name=%s", url.QueryEscape(name)), nil) case "cmd": - if len(os.Args) < 4 { - log.Fatalf("Usage: go run . cmd \"\"") + if len(args) < 4 { + log.Fatalf("Usage: vssm cmd \"\"") } - name := os.Args[2] - serverCmd := os.Args[3] + name := args[1] + serverCmd := args[2] payload := CommandPayload{Command: serverCmd} body, _ := json.Marshal(payload)