From 85cfb18ddda8a842d613dc0bc8e33e9af02d1a6c Mon Sep 17 00:00:00 2001 From: Virgil Date: Sat, 4 Apr 2026 05:48:01 +0000 Subject: [PATCH] AX: clarify cache paths and remote command examples --- cmd/mining/cmd/doctor.go | 40 ++++++++++++++++++------------------ cmd/mining/cmd/remote.go | 44 ++++++++++++++++++++-------------------- cmd/mining/cmd/update.go | 22 ++++++++++---------- 3 files changed, 53 insertions(+), 53 deletions(-) diff --git a/cmd/mining/cmd/doctor.go b/cmd/mining/cmd/doctor.go index 61bd9b0..f188390 100644 --- a/cmd/mining/cmd/doctor.go +++ b/cmd/mining/cmd/doctor.go @@ -15,12 +15,12 @@ import ( const installationCachePointerFileName = ".installed-miners" -// validateConfigPath("/home/alice/.config/lethean-desktop/miners/config.json") returns nil. -// validateConfigPath("/tmp/config.json") rejects paths outside XDG_CONFIG_HOME. -func validateConfigPath(configPath string) error { +// validateCacheFilePath("/home/alice/.config/lethean-desktop/miners/config.json") returns nil. +// validateCacheFilePath("/tmp/config.json") rejects paths outside XDG_CONFIG_HOME. +func validateCacheFilePath(cacheFilePath string) error { expectedBase := filepath.Join(xdg.ConfigHome, "lethean-desktop") - cleanPath := filepath.Clean(configPath) + cleanPath := filepath.Clean(cacheFilePath) if !strings.HasPrefix(cleanPath, expectedBase+string(os.PathSeparator)) && cleanPath != expectedBase { return fmt.Errorf("invalid config path: must be within %s", expectedBase) @@ -29,7 +29,7 @@ func validateConfigPath(configPath string) error { return nil } -// doctor refreshes the miner installation cache and writes the refreshed summary on disk. +// doctorCmd adds `doctor` so `mining doctor` refreshes the miner cache and prints the installed miner summary. var doctorCmd = &cobra.Command{ Use: "doctor", Short: "Check and refresh the status of installed miners", @@ -42,7 +42,7 @@ var doctorCmd = &cobra.Command{ if err := updateDoctorCache(); err != nil { return fmt.Errorf("failed to run doctor check: %w", err) } - // loadAndDisplayCache() prints the refreshed miner summary after updateDoctorCache(). + // loadAndDisplayCache() prints the refreshed miner summary after `mining doctor` refreshes the cache. _, err := loadAndDisplayCache() return err }, @@ -55,30 +55,30 @@ func loadAndDisplayCache() (bool, error) { } signpostPath := filepath.Join(homeDir, installationCachePointerFileName) - // os.Stat(signpostPath) returns os.ErrNotExist when no cache has been written yet. + // os.Stat("/home/alice/.installed-miners") returns os.ErrNotExist before the first `mining install xmrig` run. if _, err := os.Stat(signpostPath); os.IsNotExist(err) { fmt.Println("No cached data found. Run 'install' for a miner first.") return false, nil // loadAndDisplayCache returns false until install writes the first cache file. } - configPathBytes, err := os.ReadFile(signpostPath) + cachePointerBytes, err := os.ReadFile(signpostPath) if err != nil { return false, fmt.Errorf("could not read signpost file: %w", err) } - configPath := strings.TrimSpace(string(configPathBytes)) + cacheFilePath := strings.TrimSpace(string(cachePointerBytes)) - // validateConfigPath("/home/alice/.config/lethean-desktop/miners/config.json") blocks path traversal outside XDG_CONFIG_HOME. - if err := validateConfigPath(configPath); err != nil { + // validateCacheFilePath("/home/alice/.config/lethean-desktop/miners/config.json") blocks path traversal outside XDG_CONFIG_HOME. + if err := validateCacheFilePath(cacheFilePath); err != nil { return false, fmt.Errorf("security error: %w", err) } - cacheBytes, err := os.ReadFile(configPath) + cacheBytes, err := os.ReadFile(cacheFilePath) if err != nil { if os.IsNotExist(err) { fmt.Println("No cached data found. Run 'install' for a miner first.") return false, nil } - return false, fmt.Errorf("could not read cache file from %s: %w", configPath, err) + return false, fmt.Errorf("could not read cache file from %s: %w", cacheFilePath, err) } var systemInfo mining.SystemInfo @@ -109,22 +109,22 @@ func loadAndDisplayCache() (bool, error) { } func saveResultsToCache(systemInfo *mining.SystemInfo) error { - cacheRelativePath := filepath.Join("lethean-desktop", "miners") - configDir, err := xdg.ConfigFile(cacheRelativePath) + cacheDirectoryRelativePath := filepath.Join("lethean-desktop", "miners") + cacheDirectoryPath, err := xdg.ConfigFile(cacheDirectoryRelativePath) if err != nil { return fmt.Errorf("could not get config directory: %w", err) } - if err := os.MkdirAll(configDir, 0755); err != nil { + if err := os.MkdirAll(cacheDirectoryPath, 0755); err != nil { return fmt.Errorf("could not create config directory: %w", err) } - configPath := filepath.Join(configDir, "config.json") + cacheFilePath := filepath.Join(cacheDirectoryPath, "config.json") data, err := json.MarshalIndent(systemInfo, "", " ") if err != nil { return fmt.Errorf("could not marshal cache data: %w", err) } - if err := os.WriteFile(configPath, data, 0600); err != nil { + if err := os.WriteFile(cacheFilePath, data, 0600); err != nil { return fmt.Errorf("could not write cache file: %w", err) } @@ -133,11 +133,11 @@ func saveResultsToCache(systemInfo *mining.SystemInfo) error { return fmt.Errorf("could not get home directory for signpost: %w", err) } signpostPath := filepath.Join(homeDir, installationCachePointerFileName) - if err := os.WriteFile(signpostPath, []byte(configPath), 0600); err != nil { + if err := os.WriteFile(signpostPath, []byte(cacheFilePath), 0600); err != nil { return fmt.Errorf("could not write signpost file: %w", err) } - fmt.Printf("\n(Cache updated at %s)\n", configPath) + fmt.Printf("\n(Cache updated at %s)\n", cacheFilePath) return nil } diff --git a/cmd/mining/cmd/remote.go b/cmd/mining/cmd/remote.go index 2459a64..7ea5ac5 100644 --- a/cmd/mining/cmd/remote.go +++ b/cmd/mining/cmd/remote.go @@ -17,14 +17,14 @@ var ( remoteControllerErr error ) -// remote status, remote start, remote stop, remote logs, remote connect, remote disconnect, and remote ping live under this command group. +// remote status peer-19f3, remote start peer-19f3 --type xmrig, and remote ping peer-19f3 --count 4 live under this command group. var remoteCmd = &cobra.Command{ Use: "remote", Short: "Control remote mining nodes", Long: `Send commands to remote worker nodes and retrieve their status.`, } -// remote status a1b2c3d4e5f6 prints stats for one peer, while `remote status` prints the whole fleet. +// remote status peer-19f3 prints stats for one peer, while `remote status` prints the whole fleet. var remoteStatusCmd = &cobra.Command{ Use: "status [peer-id]", Short: "Get mining status from remote peers", @@ -36,7 +36,7 @@ var remoteStatusCmd = &cobra.Command{ } if len(args) > 0 { - // Get stats from specific peer + // remote status peer-19f3 shows that peer's stats. peerID := args[0] peer := findPeerByPartialID(peerID) if peer == nil { @@ -50,7 +50,7 @@ var remoteStatusCmd = &cobra.Command{ printPeerStats(peer, stats) } else { - // Get stats from all peers + // remote status peer-19f3 shows one peer, while `remote status` shows the fleet. allStats := remoteController.GetAllStats() if len(allStats) == 0 { fmt.Println("No connected peers.") @@ -78,7 +78,7 @@ var remoteStatusCmd = &cobra.Command{ }, } -// remote start a1b2c3d4e5f6 --type xmrig --profile default starts a miner on the selected peer. +// remote start peer-19f3 --type xmrig --profile default starts a miner on the selected peer. var remoteStartCmd = &cobra.Command{ Use: "start ", Short: "Start miner on remote peer", @@ -112,7 +112,7 @@ var remoteStartCmd = &cobra.Command{ }, } -// remote stop a1b2c3d4e5f6 xmrig-1 stops a named miner on the selected peer. +// remote stop peer-19f3 xmrig-main stops a named miner on the selected peer. var remoteStopCmd = &cobra.Command{ Use: "stop [miner-name]", Short: "Stop miner on remote peer", @@ -151,7 +151,7 @@ var remoteStopCmd = &cobra.Command{ }, } -// remote logs a1b2c3d4e5f6 xmrig-1 prints the first 100 log lines for the remote miner. +// remote logs peer-19f3 xmrig-main prints the first 100 log lines for the remote miner. var remoteLogsCmd = &cobra.Command{ Use: "logs ", Short: "Get console logs from remote miner", @@ -187,7 +187,7 @@ var remoteLogsCmd = &cobra.Command{ }, } -// remote connect a1b2c3d4e5f6 opens a WebSocket connection to the peer. +// remote connect peer-19f3 opens a WebSocket connection to the peer. var remoteConnectCmd = &cobra.Command{ Use: "connect ", Short: "Connect to a remote peer", @@ -215,7 +215,7 @@ var remoteConnectCmd = &cobra.Command{ }, } -// remote disconnect a1b2c3d4e5f6 closes the active peer connection. +// remote disconnect peer-19f3 closes the active peer connection. var remoteDisconnectCmd = &cobra.Command{ Use: "disconnect ", Short: "Disconnect from a remote peer", @@ -243,7 +243,7 @@ var remoteDisconnectCmd = &cobra.Command{ }, } -// remote ping a1b2c3d4e5f6 --count 4 averages four ping samples. +// remote ping peer-19f3 --count 4 averages four ping samples. var remotePingCmd = &cobra.Command{ Use: "ping ", Short: "Ping a remote peer", @@ -296,34 +296,34 @@ var remotePingCmd = &cobra.Command{ func init() { rootCmd.AddCommand(remoteCmd) - // remoteCmd.AddCommand(remoteStatusCmd) // exposes `remote status ` + // remoteCmd.AddCommand(remoteStatusCmd) // remote status peer-19f3 prints one peer, while `remote status` prints the fleet. remoteCmd.AddCommand(remoteStatusCmd) - // remoteCmd.AddCommand(remoteStartCmd) // exposes `remote start --type xmrig --profile default` + // remoteCmd.AddCommand(remoteStartCmd) // remote start peer-19f3 --type xmrig --profile default launches a miner. remoteCmd.AddCommand(remoteStartCmd) remoteStartCmd.Flags().StringP("profile", "p", "", "Profile ID to use for starting the miner") remoteStartCmd.Flags().StringP("type", "t", "", "Miner type, for example xmrig or tt-miner") - // remoteCmd.AddCommand(remoteStopCmd) // exposes `remote stop --miner xmrig-1` + // remoteCmd.AddCommand(remoteStopCmd) // remote stop peer-19f3 xmrig-main stops the selected miner. remoteCmd.AddCommand(remoteStopCmd) remoteStopCmd.Flags().StringP("miner", "m", "", "Miner name to stop") - // remoteCmd.AddCommand(remoteLogsCmd) // exposes `remote logs ` + // remoteCmd.AddCommand(remoteLogsCmd) // remote logs peer-19f3 xmrig-main prints miner logs. remoteCmd.AddCommand(remoteLogsCmd) remoteLogsCmd.Flags().IntP("lines", "n", 100, "Number of log lines to retrieve") - // remoteCmd.AddCommand(remoteConnectCmd) // exposes `remote connect ` + // remoteCmd.AddCommand(remoteConnectCmd) // remote connect peer-19f3 opens the peer connection. remoteCmd.AddCommand(remoteConnectCmd) - // remoteCmd.AddCommand(remoteDisconnectCmd) // exposes `remote disconnect ` + // remoteCmd.AddCommand(remoteDisconnectCmd) // remote disconnect peer-19f3 closes the peer connection. remoteCmd.AddCommand(remoteDisconnectCmd) - // remoteCmd.AddCommand(remotePingCmd) // exposes `remote ping ` + // remoteCmd.AddCommand(remotePingCmd) // remote ping peer-19f3 --count 4 measures latency. remoteCmd.AddCommand(remotePingCmd) remotePingCmd.Flags().IntP("count", "c", 4, "Number of pings to send") } -// getController returns or creates the controller instance (thread-safe). +// getController() returns the cached controller after `node init` succeeds. func getController() (*node.Controller, error) { remoteControllerOnce.Do(func() { nodeManager, err := getNodeManager() @@ -350,20 +350,20 @@ func getController() (*node.Controller, error) { return remoteController, remoteControllerErr } -// findPeerByPartialID("a1b2c3") returns the peer whose ID starts with `a1b2c3`. +// findPeerByPartialID("peer-19f3") returns the peer whose ID starts with `peer-19f3`. func findPeerByPartialID(partialID string) *node.Peer { peerRegistry, err := getPeerRegistry() if err != nil { return nil } - // peerRegistry.GetPeer(partialID) tries the exact peer ID first. + // peerRegistry.GetPeer("peer-19f3") tries the exact peer ID first. peer := peerRegistry.GetPeer(partialID) if peer != nil { return peer } - // peerRegistry.ListPeers() falls back to partial IDs such as `a1b2c3`. + // peerRegistry.ListPeers() falls back to partial IDs such as `peer-19`. for _, p := range peerRegistry.ListPeers() { if strings.HasPrefix(p.ID, partialID) { return p @@ -377,7 +377,7 @@ func findPeerByPartialID(partialID string) *node.Peer { return nil } -// printPeerStats(peer, stats) formats the remote stats output for `remote status`. +// printPeerStats(peer, stats) formats the remote stats output for `remote status peer-19f3`. func printPeerStats(peer *node.Peer, stats *node.StatsPayload) { fmt.Printf("\n%s (%s)\n", peer.Name, peer.ID[:16]) fmt.Printf(" Address: %s\n", peer.Address) diff --git a/cmd/mining/cmd/update.go b/cmd/mining/cmd/update.go index 6a0cc44..f3d2710 100644 --- a/cmd/mining/cmd/update.go +++ b/cmd/mining/cmd/update.go @@ -13,17 +13,17 @@ import ( "github.com/spf13/cobra" ) -// validateUpdateConfigPath("/home/alice/.config/lethean-desktop/miners/config.json") // nil -func validateUpdateConfigPath(configPath string) error { +// validateUpdateCacheFilePath("/home/alice/.config/lethean-desktop/miners/config.json") returns nil. +func validateUpdateCacheFilePath(cacheFilePath string) error { expectedBase := filepath.Join(xdg.ConfigHome, "lethean-desktop") - cleanPath := filepath.Clean(configPath) + cleanPath := filepath.Clean(cacheFilePath) if !strings.HasPrefix(cleanPath, expectedBase+string(os.PathSeparator)) && cleanPath != expectedBase { return fmt.Errorf("invalid config path: must be within %s", expectedBase) } return nil } -// mining update checks cached miner versions and reports available upgrades. +// updateCmd adds `update` so `mining update` can compare the cached miner version against the latest release. var updateCmd = &cobra.Command{ Use: "update", Short: "Check for updates to installed miners", @@ -42,23 +42,23 @@ var updateCmd = &cobra.Command{ return nil } - configPathBytes, err := os.ReadFile(signpostPath) + cachePointerBytes, err := os.ReadFile(signpostPath) if err != nil { return fmt.Errorf("could not read signpost file: %w", err) } - configPath := strings.TrimSpace(string(configPathBytes)) + cacheFilePath := strings.TrimSpace(string(cachePointerBytes)) - // validateUpdateConfigPath("/home/alice/.config/lethean-desktop/miners/config.json") // blocks path traversal - if err := validateUpdateConfigPath(configPath); err != nil { + // validateUpdateCacheFilePath("/home/alice/.config/lethean-desktop/miners/config.json") blocks path traversal. + if err := validateUpdateCacheFilePath(cacheFilePath); err != nil { return fmt.Errorf("security error: %w", err) } - cacheBytes, err := os.ReadFile(configPath) + cacheBytes, err := os.ReadFile(cacheFilePath) if err != nil { - return fmt.Errorf("could not read cache file from %s: %w", configPath, err) + return fmt.Errorf("could not read cache file from %s: %w", cacheFilePath, err) } - // mining.SystemInfo{} // matches what doctor.go writes to the cache file + // mining.SystemInfo{} matches the JSON shape that `mining doctor` writes to /home/alice/.config/lethean-desktop/miners/config.json. var systemInfo mining.SystemInfo if err := json.Unmarshal(cacheBytes, &systemInfo); err != nil { return fmt.Errorf("could not parse cache file: %w", err)