Map entries to mod times from the beginning

This commit is contained in:
2024-05-16 14:39:33 -04:00
parent 6fc91e0c70
commit c92d938c3d
3 changed files with 62 additions and 46 deletions
+1 -1
View File
@@ -50,4 +50,4 @@ 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> TODO remove from config file // deviceID = <device id>
+53 -37
View File
@@ -10,6 +10,12 @@ import (
"strings" "strings"
) )
// global constants used only in this file
const (
ansiUpload = "\033[38;5;4m"
ansiDownload = "\033[38;5;2m"
)
// getSSHOutput runs a command over SSH and returns the output // getSSHOutput runs a command over SSH and returns the output
// currently only supports password-less key-based authentication TODO add password support, still require key // currently only supports password-less key-based authentication TODO add password support, still require key
func getSSHOutput(cmd string, manualSync bool) string { func getSSHOutput(cmd string, manualSync bool) string {
@@ -92,19 +98,19 @@ func getSSHOutput(cmd string, manualSync bool) string {
return outputString return outputString
} }
// getRemoteDataFromClient returns lists of remote entries, mod times, folders, and deletions (four separate lists) // 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) ([]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", manualSync)
// split output into slice based on occurrences of "\x1f" // split output into slice based on occurrences of "\x1d"
outputSlice := strings.Split(output, "\x1f") outputSlice := strings.Split(output, "\x1d")
// re-form the lists TODO handle error for index out of bounds (occurs if reading deletions directory on server fails) // re-form the lists TODO handle error for index out of bounds (occurs if reading deletions directory on server fails)
entries := strings.Split(outputSlice[0], "\n")[1:] entries := strings.Split(outputSlice[0], "\x1f")[1:]
modsStrings := strings.Split(outputSlice[1], "\n")[1:] modsStrings := strings.Split(outputSlice[1], "\x1f")[1:]
folders := strings.Split(outputSlice[2], "\n")[2:] folders := strings.Split(outputSlice[2], "\x1f")[1:]
deletions := strings.Split(outputSlice[3], "\n")[1:] deletions := strings.Split(outputSlice[3], "\x1f")[1:]
// convert the mod times to int64 // convert the mod times to int64
var mods []int64 var mods []int64
@@ -113,49 +119,59 @@ func getRemoteDataFromClient(manualSync bool) ([]string, []int64, []string, []st
mods = append(mods, mod) mods = append(mods, mod)
} }
return entries, mods, folders, deletions // map remote entries to their modification times
entryModMap := make(map[string]int64)
for i, entry := range entries {
entryModMap[entry] = mods[i]
}
return entryModMap, folders, deletions
} }
// getLocalData returns lists of local entries and mod times (two separate lists) // getLocalData returns a map of local entries to their modification times
func getLocalData() ([]string, []int64) { func getLocalData() map[string]int64 {
// get a list of all entries // get a list of all entries
fileList, _ := WalkEntryDir() entries, _ := WalkEntryDir()
// get a list of all entry modification times // get a list of all entry modification times
modList := getModTimes(fileList) modList := getModTimes(entries)
// map the entries to their modification times
entryModMap := make(map[string]int64)
for i, entry := range entries {
entryModMap[entry] = modList[i]
}
// return the lists // return the lists
return fileList, modList return entryModMap
} }
// syncLists syncs entries between the client and server based on modification times // syncLists syncs entries between the client and server based on modification times
func syncLists(entries [2][]string, modTimes [2][]int64) { // using maps means that syncing will be done in an arbitrary order, but it is a worthy tradeoff for speed and simplicity
// create a map of all server entries to their mod times func syncLists(localEntryModMap, remoteEntryModMap map[string]int64) {
serverMap := make(map[string]int64)
for i, entry := range entries[1] {
serverMap[entry] = modTimes[1][i]
}
// iterate over client entries // iterate over client entries
for i, entry := range entries[0] { for entry, localModTime := range localEntryModMap {
// check if the entry is present in serverMap // check if the entry is present in the server map
if serverModTime, present := serverMap[entry]; present { if remoteModTime, present := remoteEntryModMap[entry]; present {
// entry exists on both client and server, compare mod times // entry exists on both client and server, compare mod times
if serverModTime > modTimes[0][i] { if remoteModTime > localModTime {
fmt.Println(ansiDownload+entry+backend.AnsiReset, "is newer on server, downloading...")
// TODO entry is newer on server, download // TODO entry is newer on server, download
} else if serverModTime < modTimes[0][i] { } else if remoteModTime < localModTime {
fmt.Println(ansiUpload+entry+backend.AnsiReset, "is newer on client, uploading...")
// TODO entry is newer on client, upload // TODO entry is newer on client, upload
} }
// remove entry from serverMap (process of elimination) // remove entry from remoteEntryModMap (process of elimination)
delete(serverMap, entry) delete(remoteEntryModMap, entry)
} else { } else {
// TODO entry does not exist on sever, upload fmt.Println(ansiUpload+entry+backend.AnsiReset, "does not exist on server, uploading...")
// TODO entry does not exist on server, upload
} }
} }
// iterate over remaining entries in serverMap // iterate over remaining entries in remoteEntryModMap
for entry := range serverMap { for entry := range remoteEntryModMap {
fmt.Println(entry) // TODO placeholder fmt.Println(ansiDownload+entry+backend.AnsiReset, "does not exist on server, downloading...")
// TODO entry does not exist on client, download // TODO entry does not exist on client, download
} }
} }
@@ -163,16 +179,16 @@ func syncLists(entries [2][]string, modTimes [2][]int64) {
// 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
remoteEntries, remoteMods, remoteFolders, remoteDeletions := getRemoteDataFromClient(manualSync) remoteEntryModMap, remoteFolders, remoteDeletions := getRemoteDataFromClient(manualSync)
fmt.Println(remoteEntries, remoteMods, remoteFolders, remoteDeletions) // TODO placeholder fmt.Println(remoteFolders, remoteDeletions) // TODO placeholder
// TODO sync deletions and folders // TODO sync deletions and folders
// fetch local lists // fetch local lists
localEntries, localMods := getLocalData() localEntryModMap := getLocalData()
fmt.Println(localEntries, localMods) // TODO placeholder
// TODO sync new and updated entries // sync new and updated entries
syncLists(localEntryModMap, remoteEntryModMap)
// exit program after successful sync // exit program after successful sync
os.Exit(0) os.Exit(0)
+8 -8
View File
@@ -7,7 +7,7 @@ import (
) )
// GetRemoteDataFromServer prints to stdout the remote entries, mod times, folders, and deletions // GetRemoteDataFromServer prints to stdout the remote entries, mod times, folders, and deletions
// lists in output are separated by "\x1f" // lists in output are separated by "\x1d"
// output is meant to be captured over SSH for interpretation by the client // output is meant to be captured over SSH for interpretation by the client
func GetRemoteDataFromServer() { func GetRemoteDataFromServer() {
entryList, dirList := WalkEntryDir() entryList, dirList := WalkEntryDir()
@@ -20,19 +20,19 @@ func GetRemoteDataFromServer() {
// print the lists to stdout // print the lists to stdout
for _, entry := range entryList { for _, entry := range entryList {
fmt.Print("\n" + entry) fmt.Print("\x1f" + entry)
} }
fmt.Print("\x1f") fmt.Print("\x1d")
for _, mod := range modList { for _, mod := range modList {
fmt.Print("\n") fmt.Print("\x1f")
fmt.Print(mod) fmt.Print(mod)
} }
fmt.Print("\x1f") fmt.Print("\x1d")
for _, dir := range dirList { for _, dir := range dirList {
fmt.Print("\n" + dir) fmt.Print("\x1f" + dir)
} }
fmt.Print("\x1f") fmt.Print("\x1d")
for _, deletion := range deletionsList { for _, deletion := range deletionsList {
fmt.Print("\n" + deletion.Name()) fmt.Print("\x1f" + deletion.Name())
} }
} }