From 0b7ce10a78ef0a8601f28e40a4498ae726083de5 Mon Sep 17 00:00:00 2001 From: Randall Winkhart Date: Tue, 4 Jun 2024 15:09:57 -0400 Subject: [PATCH] Add initial support for reading stdin from the server binary --- src/backend/configParser.go | 2 +- src/sync/client.go | 18 +++++++++++------- src/sync/init.go | 4 ++-- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/backend/configParser.go b/src/backend/configParser.go index bc933df..4dd5801 100644 --- a/src/backend/configParser.go +++ b/src/backend/configParser.go @@ -13,7 +13,7 @@ import ( func ReadConfig(readKeys []string, missingValueError string) []string { cfg, err := ini.Load(ConfigPath) if err != nil { - fmt.Println(AnsiError + "Failed to load libmutton.ini" + AnsiReset) + fmt.Println(AnsiError + "Failed to load libmutton.ini: " + err.Error() + AnsiReset) os.Exit(1) } diff --git a/src/sync/client.go b/src/sync/client.go index 93941e8..051cbc7 100644 --- a/src/sync/client.go +++ b/src/sync/client.go @@ -99,8 +99,8 @@ func getSSHClient(manualSync bool) (*ssh.Client, string, bool) { } // GetSSHOutput runs a command over SSH and returns the output as a string -// TODO run getSSHClient() ONCE in RunJob and pass to each function that needs it (to avoid multiple connections), move defer to RunJob -func GetSSHOutput(cmd string, manualSync bool) string { +// TODO run getSSHClient() only ONCE (from RunJob) - this only saves re-creating the client, not re-establishing the connection, so it may not be worth it +func GetSSHOutput(cmd, stdin string, manualSync bool) string { sshClient, _, _ := getSSHClient(manualSync) defer sshClient.Close() @@ -111,8 +111,12 @@ func GetSSHOutput(cmd string, manualSync bool) string { os.Exit(1) } + // provide stdin data for session + sshSession.Stdin = strings.NewReader(stdin) + // run the provided command - output, err := sshSession.CombinedOutput(cmd) + var output []byte + output, err = sshSession.CombinedOutput(cmd) if err != nil { fmt.Println(backend.AnsiError+"Sync failed - Unable to run SSH command:", err.Error()+backend.AnsiReset) os.Exit(1) @@ -137,7 +141,7 @@ func getRemoteDataFromClient(manualSync bool) (map[string]int64, []string, []str os.Exit(0) // exit silently if the sync job was called automatically, as the user may just be in offline mode } } - output := GetSSHOutput("libmuttonserver fetch "+clientDeviceID[0].Name(), manualSync) + output := GetSSHOutput("libmuttonserver fetch "+clientDeviceID[0].Name(), "", manualSync) // split output into slice based on occurrences of "\x1d" outputSlice := strings.Split(output, "\x1d") @@ -373,7 +377,7 @@ func ShearRemoteFromClient(targetLocationIncomplete string) { // call the server to remotely shear the target and add it to the deletions list // deviceID and targetLocationIncomplete are separated by \x1d, path separators are replaced with \x1e, and spaces are replaced with \x1f TODO is there a need to combine deviceID and targetLocationIncomplete into one argument? - GetSSHOutput("libmuttonserver shear "+deviceID+"\x1d"+strings.ReplaceAll(strings.ReplaceAll(targetLocationIncomplete, backend.PathSeparator, "\x1e"), " ", "\x1f"), false) // TODO seems to already have Windows server support, perhaps copy this approach to AddFolderRemoteFromClient + GetSSHOutput("libmuttonserver shear "+deviceID+"\x1d"+strings.ReplaceAll(strings.ReplaceAll(targetLocationIncomplete, backend.PathSeparator, "\x1e"), " ", "\x1f"), "", false) // TODO seems to already have Windows server support, perhaps copy this approach to AddFolderRemoteFromClient os.Exit(0) // sync is not required after shearing since the target has already been removed from the local system } @@ -394,8 +398,8 @@ func deletionSync(deletions []string) { // AddFolderRemoteFromClient creates a new entry-containing directory on the local system and calls the server to create the folder remotely func AddFolderRemoteFromClient(targetLocationIncomplete string) { - AddFolderLocal(targetLocationIncomplete) // add the folder on the local system - GetSSHOutput("libmuttonserver addfolder "+strings.ReplaceAll(targetLocationIncomplete, " ", "\x1f"), false) // call the server to create the folder remotely TODO Windows server support + AddFolderLocal(targetLocationIncomplete) // add the folder on the local system + GetSSHOutput("libmuttonserver addfolder "+strings.ReplaceAll(targetLocationIncomplete, " ", "\x1f"), "", false) // call the server to create the folder remotely TODO Windows server support os.Exit(0) } diff --git a/src/sync/init.go b/src/sync/init.go index 00fa02e..090df6b 100644 --- a/src/sync/init.go +++ b/src/sync/init.go @@ -14,8 +14,8 @@ func DeviceIDGen() (string, string) { deviceIDPrefix, _ := os.Hostname() deviceIDSuffix := backend.StringGen(rand.Intn(48)+48, false, 0) // TODO consider using complex string generator and removing unsafe characters manually deviceID := deviceIDPrefix + "-" + deviceIDSuffix - os.Create(backend.ConfigDir + backend.PathSeparator + "devices" + backend.PathSeparator + deviceID) // TODO remove existing device ID file if it exists (from both client and server) - sshEntryRootSSHIsWindows := strings.Split(GetSSHOutput("libmuttonserver register "+deviceID, true), "\x1d") // register device ID with server and fetch remote EntryRoot and OS type; manualSync is true so the user is alerted if device ID registration fails + os.Create(backend.ConfigDir + backend.PathSeparator + "devices" + backend.PathSeparator + deviceID) // TODO remove existing device ID file if it exists (from both client and server) + sshEntryRootSSHIsWindows := strings.Split(GetSSHOutput("libmuttonserver register "+deviceID, "", true), "\x1d") // register device ID with server and fetch remote EntryRoot and OS type; manualSync is true so the user is alerted if device ID registration fails return sshEntryRootSSHIsWindows[0], sshEntryRootSSHIsWindows[1] }