mirror of
https://github.com/rwinkhart/libmutton.git
synced 2026-08-28 04:46:42 -04:00
Switch from SCP to SFTP for sync
This commit is contained in:
+55
-20
@@ -1,9 +1,8 @@
|
|||||||
package sync
|
package sync
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/bramvdbogaerde/go-scp"
|
"github.com/pkg/sftp"
|
||||||
"github.com/rwinkhart/MUTN/src/backend"
|
"github.com/rwinkhart/MUTN/src/backend"
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
"golang.org/x/crypto/ssh/knownhosts"
|
"golang.org/x/crypto/ssh/knownhosts"
|
||||||
@@ -117,32 +116,68 @@ func GetSSHOutput(cmd string, manualSync bool) string {
|
|||||||
return outputString
|
return outputString
|
||||||
}
|
}
|
||||||
|
|
||||||
// scpTransfer uploads or downloads an entry over SCP // TODO consider using goroutines for multithreaded syncs
|
// sftpTransfer uploads or downloads an entry over SFTP // TODO iterate over a map of operations to slices of entries, rather than repeatedly calling this function
|
||||||
// WARNING: does not close sshClient; it is left open for further operations
|
// WARNING: does not close sshClient; it is left open for further operations
|
||||||
// TODO does not yet support modification time preservation, needs https://github.com/bramvdbogaerde/go-scp/pull/81/commits
|
func sftpTransfer(sshClient *ssh.Client, entryName, sshUser string, download bool) {
|
||||||
func scpTransfer(sshClient *ssh.Client, entryName, sshUser string, download bool) {
|
// create an SFTP client
|
||||||
// create an SCP client TODO see if one can be passed in and reused
|
sftpClient, err := sftp.NewClient(sshClient)
|
||||||
scpClient, err := scp.NewClientBySSH(sshClient)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(backend.AnsiError+"Sync failed - Unable to establish SCP session:", err.Error()+backend.AnsiReset)
|
fmt.Println(backend.AnsiError+"Sync failed - Unable to establish SFTP session:", err.Error()+backend.AnsiReset)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
defer sftpClient.Close()
|
||||||
|
|
||||||
// upload or download the entry
|
// upload or download the entry
|
||||||
if download {
|
if download {
|
||||||
f, _ := os.Create(backend.EntryRoot + entryName)
|
// open remote file TODO fetch mod time and assign to downloaded file
|
||||||
defer f.Close()
|
var remoteFile *sftp.File
|
||||||
err = scpClient.CopyFromRemote(context.Background(), f, backend.PathSeparator+"home"+backend.PathSeparator+sshUser+bareEntryRoot+entryName) // TODO support remote home directories other than "/home/$USER" (maybe fetch home directory form server during init, transparently to the user)
|
remoteFile, err = sftpClient.Open("/home/" + sshUser + bareEntryRoot + entryName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(backend.AnsiError+"Sync failed - Unable to download entry:", entryName, err.Error()+backend.AnsiReset)
|
fmt.Println(backend.AnsiError+"Sync failed - Unable to open remote file:", err.Error()+backend.AnsiReset)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
defer remoteFile.Close()
|
||||||
|
|
||||||
|
// create local file
|
||||||
|
var localFile *os.File
|
||||||
|
localFile, err = os.Create(backend.EntryRoot + entryName)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(backend.AnsiError+"Sync failed - Unable to create local file:", err.Error()+backend.AnsiReset)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
defer localFile.Close()
|
||||||
|
|
||||||
|
// download the file
|
||||||
|
_, err = remoteFile.WriteTo(localFile)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(backend.AnsiError+"Sync failed - Unable to download remote file:", err.Error()+backend.AnsiReset)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
f, _ := os.Open(backend.EntryRoot + entryName)
|
// open local file TODO fetch mod time and assign to uploaded file
|
||||||
defer f.Close()
|
var localFile *os.File
|
||||||
err = scpClient.CopyFromFile(context.Background(), *f, backend.PathSeparator+"home"+backend.PathSeparator+sshUser+bareEntryRoot+entryName, "0600")
|
localFile, err = os.Open(backend.EntryRoot + entryName)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(backend.AnsiError+"Sync failed - Unable to open local file:", err.Error()+backend.AnsiReset)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
defer localFile.Close()
|
||||||
|
|
||||||
|
// create remote file
|
||||||
|
var remoteFile *sftp.File
|
||||||
|
remoteFile, err = sftpClient.Create("/home/" + sshUser + bareEntryRoot + entryName)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(backend.AnsiError+"Sync failed - Unable to create remote file:", err.Error()+backend.AnsiReset)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
defer remoteFile.Close()
|
||||||
|
|
||||||
|
// upload the file
|
||||||
|
_, err = localFile.WriteTo(remoteFile)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(backend.AnsiError+"Sync failed - Unable to upload local file:", err.Error()+backend.AnsiReset)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,23 +255,23 @@ func syncLists(localEntryModMap, remoteEntryModMap map[string]int64, manualSync
|
|||||||
// entry exists on both client and server, compare mod times
|
// entry exists on both client and server, compare mod times
|
||||||
if remoteModTime > localModTime {
|
if remoteModTime > localModTime {
|
||||||
fmt.Println(ansiDownload+entry+backend.AnsiReset, "is newer on server, downloading...")
|
fmt.Println(ansiDownload+entry+backend.AnsiReset, "is newer on server, downloading...")
|
||||||
scpTransfer(sshClient, entry, sshUser, true)
|
sftpTransfer(sshClient, entry, sshUser, true)
|
||||||
} else if remoteModTime < localModTime {
|
} else if remoteModTime < localModTime {
|
||||||
fmt.Println(ansiUpload+entry+backend.AnsiReset, "is newer on client, uploading...")
|
fmt.Println(ansiUpload+entry+backend.AnsiReset, "is newer on client, uploading...")
|
||||||
scpTransfer(sshClient, entry, sshUser, false)
|
sftpTransfer(sshClient, entry, sshUser, false)
|
||||||
}
|
}
|
||||||
// remove entry from remoteEntryModMap (process of elimination)
|
// remove entry from remoteEntryModMap (process of elimination)
|
||||||
delete(remoteEntryModMap, entry)
|
delete(remoteEntryModMap, entry)
|
||||||
} else {
|
} else {
|
||||||
fmt.Println(ansiUpload+entry+backend.AnsiReset, "does not exist on server, uploading...")
|
fmt.Println(ansiUpload+entry+backend.AnsiReset, "does not exist on server, uploading...")
|
||||||
scpTransfer(sshClient, entry, sshUser, false)
|
sftpTransfer(sshClient, entry, sshUser, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// iterate over remaining entries in remoteEntryModMap
|
// iterate over remaining entries in remoteEntryModMap
|
||||||
for entry := range remoteEntryModMap {
|
for entry := range remoteEntryModMap {
|
||||||
fmt.Println(ansiDownload+entry+backend.AnsiReset, "does not exist on client, downloading...")
|
fmt.Println(ansiDownload+entry+backend.AnsiReset, "does not exist on client, downloading...")
|
||||||
scpTransfer(sshClient, entry, sshUser, true)
|
sftpTransfer(sshClient, entry, sshUser, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user