mirror of
https://github.com/rwinkhart/libmutton.git
synced 2026-08-31 06:16:35 -04:00
Implement initial server-side shearing logic
This commit is contained in:
@@ -50,4 +50,3 @@ func ReadConfig(readKeys []string, missingValueError string) []string {
|
|||||||
// sshPort = <remote ssh port>
|
// sshPort = <remote ssh port>
|
||||||
// sshIdentity = <ssh private key identity file path>
|
// sshIdentity = <ssh private key identity file path>
|
||||||
// netPinEnabled = <true/false>
|
// netPinEnabled = <true/false>
|
||||||
// deviceID = <device id>
|
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ func dirInit() {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// create config directory
|
// create config directory w/devices subdirectory
|
||||||
err = os.MkdirAll(ConfigDir, 0700)
|
err = os.MkdirAll(ConfigDir+"/devices", 0700)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(AnsiError + "Failed to create \"" + ConfigDir + "\":" + err.Error() + AnsiReset)
|
fmt.Println(AnsiError + "Failed to create \"" + ConfigDir + "\":" + err.Error() + AnsiReset)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ func dirInit() {
|
|||||||
fmt.Println(AnsiError + "Failed to create \"" + EntryRoot + "\":" + err.Error() + AnsiReset)
|
fmt.Println(AnsiError + "Failed to create \"" + EntryRoot + "\":" + err.Error() + AnsiReset)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
os.MkdirAll(ConfigDir+"\\devices", 0700)
|
||||||
}
|
}
|
||||||
|
|
||||||
// textEditorFallback returns FallbackEditor
|
// textEditorFallback returns FallbackEditor
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
package backend
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Shear(targetLocation string) {
|
|
||||||
// TODO If in online mode, remove from server and add to shear list
|
|
||||||
TargetIsFile(targetLocation, true, 0) // needed because os.RemoveAll does not return an error if target does not exist
|
|
||||||
err := os.RemoveAll(targetLocation)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(AnsiError + "Failed to remove target: " + err.Error() + AnsiReset)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
+15
-6
@@ -12,8 +12,9 @@ import (
|
|||||||
|
|
||||||
// global constants used only in this file
|
// global constants used only in this file
|
||||||
const (
|
const (
|
||||||
ansiUpload = "\033[38;5;4m"
|
ansiDelete = "\033[38;5;1m"
|
||||||
ansiDownload = "\033[38;5;2m"
|
ansiDownload = "\033[38;5;2m"
|
||||||
|
ansiUpload = "\033[38;5;4m"
|
||||||
)
|
)
|
||||||
|
|
||||||
// getSSHOutput runs a command over SSH and returns the output
|
// getSSHOutput runs a command over SSH and returns the output
|
||||||
@@ -54,7 +55,7 @@ func getSSHOutput(cmd string, manualSync bool) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// read known hosts file
|
// read known hosts file
|
||||||
hostKeyCallback, err := knownhosts.New(backend.Home + "/.ssh/known_hosts")
|
hostKeyCallback, err := knownhosts.New(backend.Home + backend.PathSeparator + ".ssh" + backend.PathSeparator + "known_hosts")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(backend.AnsiError + "Sync failed - Unable to read known hosts file:" + err.Error() + backend.AnsiReset)
|
fmt.Println(backend.AnsiError + "Sync failed - Unable to read known hosts file:" + err.Error() + backend.AnsiReset)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
@@ -101,7 +102,7 @@ func getSSHOutput(cmd string, manualSync bool) string {
|
|||||||
// getRemoteDataFromClient returns a map of remote entries to their modification times, a list of remote folders, and a list of queued deletions
|
// getRemoteDataFromClient returns a map of remote entries to their modification times, a list of remote folders, and a list of queued deletions
|
||||||
func getRemoteDataFromClient(manualSync bool) (map[string]int64, []string, []string) {
|
func getRemoteDataFromClient(manualSync bool) (map[string]int64, []string, []string) {
|
||||||
// get remote output over SSH
|
// get remote output over SSH
|
||||||
output := getSSHOutput("libmuttonserver", manualSync)
|
output := getSSHOutput("libmuttonserver fetch", manualSync)
|
||||||
|
|
||||||
// split output into slice based on occurrences of "\x1d"
|
// split output into slice based on occurrences of "\x1d"
|
||||||
outputSlice := strings.Split(output, "\x1d")
|
outputSlice := strings.Split(output, "\x1d")
|
||||||
@@ -176,13 +177,21 @@ func syncLists(localEntryModMap, remoteEntryModMap map[string]int64) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func deletionSync(deletions []string) {
|
||||||
|
for _, deletion := range deletions {
|
||||||
|
fmt.Println(ansiDelete+deletion+backend.AnsiReset, "has been sheared, removing...")
|
||||||
|
//os.RemoveAll(backend.EntryRoot + deletion) TODO uncomment after testing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// RunJob runs the SSH sync job
|
// RunJob runs the SSH sync job
|
||||||
func RunJob(manualSync bool) {
|
func RunJob(manualSync bool) {
|
||||||
// fetch remote lists
|
// fetch remote lists
|
||||||
remoteEntryModMap, remoteFolders, remoteDeletions := getRemoteDataFromClient(manualSync)
|
remoteEntryModMap, remoteFolders, deletions := getRemoteDataFromClient(manualSync)
|
||||||
fmt.Println(remoteFolders, remoteDeletions) // TODO placeholder
|
fmt.Println(remoteFolders) // TODO placeholder
|
||||||
|
|
||||||
// TODO sync deletions and folders
|
// sync deletions
|
||||||
|
deletionSync(deletions)
|
||||||
|
|
||||||
// fetch local lists
|
// fetch local lists
|
||||||
localEntryModMap := getLocalData()
|
localEntryModMap := getLocalData()
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WalkEntryDir walks the entry directory and returns lists of all files and directories found (two separate lists)
|
// WalkEntryDir walks the entry directory and returns lists of all files and directories found (two separate lists)
|
||||||
@@ -56,3 +57,47 @@ func getModTimes(entryList []string) []int64 {
|
|||||||
|
|
||||||
return modList
|
return modList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shear removes the target file or directory from the system
|
||||||
|
// if running on the server, it will also add the target to the deletions list
|
||||||
|
// if running on the client, it will call the server to add the target to the deletions list
|
||||||
|
func Shear(targetLocationIncomplete string, deviceID string) {
|
||||||
|
// get the full targetLocation path and remove the target
|
||||||
|
targetLocationComplete := backend.TargetLocationFormat(targetLocationIncomplete[1:])
|
||||||
|
backend.TargetIsFile(targetLocationComplete, true, 0) // needed because os.RemoveAll does not return an error if target does not exist
|
||||||
|
err := os.RemoveAll(targetLocationComplete)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(backend.AnsiError + "Failed to remove local target: " + err.Error() + backend.AnsiReset)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// read the devices directory
|
||||||
|
var deviceIDList []os.DirEntry
|
||||||
|
deviceIDList, err = os.ReadDir(backend.ConfigDir + backend.PathSeparator + "devices")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(backend.AnsiError + "Failed to read the devices directory: " + err.Error() + backend.AnsiReset)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the sheared target (incomplete, vanity) to the deletions list
|
||||||
|
if deviceID != "" { // if running on the server...
|
||||||
|
for _, device := range deviceIDList {
|
||||||
|
if device.Name() != deviceID {
|
||||||
|
_, err = os.Create(backend.ConfigDir + backend.PathSeparator + "deletions" + backend.PathSeparator + device.Name() + "\x1d" + strings.ReplaceAll(targetLocationIncomplete, backend.PathSeparator, "\x1e"))
|
||||||
|
if err != nil {
|
||||||
|
// do not print error as there is currently no way of seeing server-side errors
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
backend.ReadConfig([]string{"sshUser"}, "0") // exits if value does not exist (indicates offline mode)
|
||||||
|
// if running on the client in online mode...
|
||||||
|
// determine client device ID (to send to server, avoids creating a deletion file for the client device)
|
||||||
|
deviceID = deviceIDList[0].Name()
|
||||||
|
// below: deviceID and targetLocationIncomplete are separated by \x1d, path separators are replaced with \x1e, and spaces are replaced with \x1f
|
||||||
|
getSSHOutput("libmuttonserver shear "+deviceID+"\x1d"+strings.ReplaceAll(strings.ReplaceAll(targetLocationIncomplete, backend.PathSeparator, "\x1e"), " ", "\x1f"), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ import (
|
|||||||
func GetRemoteDataFromServer() {
|
func GetRemoteDataFromServer() {
|
||||||
entryList, dirList := WalkEntryDir()
|
entryList, dirList := WalkEntryDir()
|
||||||
modList := getModTimes(entryList)
|
modList := getModTimes(entryList)
|
||||||
deletionsList, err := os.ReadDir(backend.ConfigDir + "/deletions")
|
deletionsList, err := os.ReadDir(backend.ConfigDir + backend.PathSeparator + "deletions")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(backend.AnsiError + "Failed to read the deletions directory: " + err.Error() + backend.AnsiReset)
|
fmt.Println(backend.AnsiError + "Failed to read the deletions directory: " + err.Error() + backend.AnsiReset)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
|||||||
Reference in New Issue
Block a user