mirror of
https://github.com/rwinkhart/MUTN.git
synced 2026-08-27 20:36:29 -04:00
Do not upload/download any entries if the client and server time are more than 30 seconds out of sync; appropriately warn the user
This commit is contained in:
+4
-3
@@ -3,12 +3,13 @@ package main
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"github.com/rwinkhart/MUTN/src/backend"
|
||||
"github.com/rwinkhart/MUTN/src/cli"
|
||||
"github.com/rwinkhart/MUTN/src/sync"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/rwinkhart/MUTN/src/backend"
|
||||
"github.com/rwinkhart/MUTN/src/cli"
|
||||
"github.com/rwinkhart/MUTN/src/sync"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
+26
-13
@@ -130,8 +130,8 @@ func GetSSHOutput(cmd, stdin string, manualSync bool) string {
|
||||
return outputString
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// getRemoteDataFromClient returns a map of remote entries to their modification times, a list of remote folders, a list of queued deletions, and the current server+client times as UNIX timestamps
|
||||
func getRemoteDataFromClient(manualSync bool) (map[string]int64, []string, []string, int64, int64) {
|
||||
// get remote output over SSH
|
||||
clientDeviceID, _ := os.ReadDir(backend.ConfigDir + backend.PathSeparator + "devices")
|
||||
if len(clientDeviceID) == 0 {
|
||||
@@ -142,20 +142,22 @@ func getRemoteDataFromClient(manualSync bool) (map[string]int64, []string, []str
|
||||
backend.Exit(0) // exit silently if the sync job was called automatically, as the user may just be in offline mode
|
||||
}
|
||||
}
|
||||
clientTime := time.Now().Unix() // get client time now to avoid accuracy issues caused by unpredictable sync time
|
||||
output := GetSSHOutput("libmuttonserver fetch", clientDeviceID[0].Name(), manualSync)
|
||||
|
||||
// split output into slice based on occurrences of FSSpace
|
||||
outputSlice := strings.Split(output, FSSpace)
|
||||
|
||||
// re-form the lists
|
||||
if len(outputSlice) != 4 { // ensure information from server is complete
|
||||
// parse output/re-form lists
|
||||
if len(outputSlice) != 5 { // ensure information from server is complete
|
||||
fmt.Println(backend.AnsiError + "Sync failed - Unable to fetch remote data; server returned an unexpected response" + backend.AnsiReset)
|
||||
os.Exit(1)
|
||||
}
|
||||
entries := strings.Split(outputSlice[0], FSMisc)[1:]
|
||||
modsStrings := strings.Split(outputSlice[1], FSMisc)[1:]
|
||||
folders := strings.Split(outputSlice[2], FSMisc)[1:]
|
||||
deletions := strings.Split(outputSlice[3], FSMisc)[1:]
|
||||
serverTime, _ := strconv.ParseInt(outputSlice[0], 10, 64)
|
||||
entries := strings.Split(outputSlice[1], FSMisc)[1:]
|
||||
modsStrings := strings.Split(outputSlice[2], FSMisc)[1:]
|
||||
folders := strings.Split(outputSlice[3], FSMisc)[1:]
|
||||
deletions := strings.Split(outputSlice[4], FSMisc)[1:]
|
||||
|
||||
// convert the mod times to int64
|
||||
var mods []int64
|
||||
@@ -170,7 +172,7 @@ func getRemoteDataFromClient(manualSync bool) (map[string]int64, []string, []str
|
||||
entryModMap[entry] = mods[i]
|
||||
}
|
||||
|
||||
return entryModMap, folders, deletions
|
||||
return entryModMap, folders, deletions, serverTime, clientTime
|
||||
}
|
||||
|
||||
// getLocalData returns a map of local entries to their modification times
|
||||
@@ -331,10 +333,18 @@ func sftpSync(downloadList, uploadList []string, manualSync bool) {
|
||||
|
||||
// syncLists determines which entries need to be downloaded and uploaded for synchronizations and calls sftpSync with this information
|
||||
// using maps means that syncing will be done in an arbitrary order, but it is a worthy tradeoff for speed and simplicity
|
||||
func syncLists(localEntryModMap, remoteEntryModMap map[string]int64, manualSync bool) {
|
||||
func syncLists(localEntryModMap, remoteEntryModMap map[string]int64, manualSync bool, serverTime int64, clientTime int64) {
|
||||
// initialize slices to store entries that need to be downloaded or uploaded
|
||||
var downloadList, uploadList []string
|
||||
|
||||
// ensure client and server times are synchronized
|
||||
var timeSynced = true
|
||||
timeDiff := serverTime - clientTime
|
||||
if timeDiff < -45 || timeDiff > 45 {
|
||||
timeSynced = false
|
||||
fmt.Print(backend.AnsiError + "Client and server times are out of sync.\n\nPlease ensure both clocks are correct before attempting to sync again.\n\nA dry sync output will be printed below (if any operations would have been performed). It is strongly recommended to review it and manually update the modification times as applicable to ensure the correct version of each entry is kept.\n\n" + backend.AnsiReset)
|
||||
}
|
||||
|
||||
// iterate over client entries
|
||||
for entry, localModTime := range localEntryModMap {
|
||||
// check if the entry is present in the server map
|
||||
@@ -362,9 +372,12 @@ func syncLists(localEntryModMap, remoteEntryModMap map[string]int64, manualSync
|
||||
}
|
||||
|
||||
// call sftpSync with the download and upload lists
|
||||
if max(len(downloadList), len(uploadList)) > 0 { // only call sftpSync if there are entries to download or upload
|
||||
if timeSynced && (max(len(downloadList), len(uploadList)) > 0) { // only call sftpSync if there are entries to download or upload
|
||||
fmt.Println() // add a gap between list-add messages and the actual sync messages from sftpSync
|
||||
sftpSync(downloadList, uploadList, manualSync)
|
||||
} else if !timeSynced {
|
||||
// do not call sftpSync if the client and server times are out of sync
|
||||
backend.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Println("Client is synchronized with server")
|
||||
@@ -445,7 +458,7 @@ func folderSync(folders []string) {
|
||||
// RunJob runs the SSH sync job
|
||||
func RunJob(manualSync bool) {
|
||||
// fetch remote lists
|
||||
remoteEntryModMap, remoteFolders, deletions := getRemoteDataFromClient(manualSync)
|
||||
remoteEntryModMap, remoteFolders, deletions, serverTime, clientTime := getRemoteDataFromClient(manualSync)
|
||||
|
||||
// sync folders
|
||||
folderSync(remoteFolders)
|
||||
@@ -457,7 +470,7 @@ func RunJob(manualSync bool) {
|
||||
localEntryModMap := getLocalData()
|
||||
|
||||
// sync new and updated entries
|
||||
syncLists(localEntryModMap, remoteEntryModMap, manualSync)
|
||||
syncLists(localEntryModMap, remoteEntryModMap, manualSync, serverTime, clientTime)
|
||||
|
||||
// exit program after successful sync
|
||||
backend.Exit(0)
|
||||
|
||||
+7
-2
@@ -2,9 +2,11 @@ package sync
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/rwinkhart/MUTN/src/backend"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/rwinkhart/MUTN/src/backend"
|
||||
)
|
||||
|
||||
// GetRemoteDataFromServer prints to stdout the remote entries, mod times, folders, and deletions
|
||||
@@ -19,9 +21,12 @@ func GetRemoteDataFromServer(clientDeviceID string) {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// print the lists to stdout
|
||||
// print the current UNIX timestamp to stdout
|
||||
fmt.Print(time.Now().Unix())
|
||||
|
||||
// print the lists to stdout
|
||||
// entry list
|
||||
fmt.Print(FSSpace)
|
||||
for _, entry := range entryList {
|
||||
fmt.Print(FSMisc + entry)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user