fix: reject + handle remote-to-remote sync pairs

Option A (validation):
- handlers_syncpairs.go: reject create/update when both SourceMachineID
  and DestMachineID are set; clear error message explains the constraint
- engine.go: detect 'both remote' rsync error at runtime and surface it
  as error_code=remote_to_remote_unsupported with a human-readable message

Option B (remote-to-remote support):
- rsync_runner.go: add RunRemote() method that SSHs to the source machine
  and runs rsync locally there (src=local path, dst=user@host:/path),
  streaming output back through the onLine callback
- engine.go: when both srcMachine and dstMachine are non-nil, use
  RunRemote() instead of Run(), SSHing to srcMachine and running rsync
  from there. Also wake dstMachine via WoL when both sides are remote.
This commit is contained in:
2026-07-09 10:40:12 -04:00
parent ba4c6aa732
commit d7e6d64967
3 changed files with 200 additions and 6 deletions
+8
View File
@@ -75,6 +75,10 @@ func (h *SyncPairHandler) Create(w http.ResponseWriter, r *http.Request) {
writeError(w, http.StatusBadRequest, "direction must be push, pull, or mirror")
return
}
if req.SourceMachineID != nil && req.DestMachineID != nil {
writeError(w, http.StatusBadRequest, "both source and destination cannot be remote machines; one side must be the server (set one MachineID to null)")
return
}
if req.RsyncFlags == "" {
req.RsyncFlags = "-aP"
}
@@ -127,6 +131,10 @@ func (h *SyncPairHandler) Update(w http.ResponseWriter, r *http.Request) {
writeError(w, http.StatusBadRequest, "direction must be push, pull, or mirror")
return
}
if req.SourceMachineID != nil && req.DestMachineID != nil {
writeError(w, http.StatusBadRequest, "both source and destination cannot be remote machines; one side must be the server (set one MachineID to null)")
return
}
repo := models.NewSyncPairRepository(h.db)
existing, err := repo.GetByID(id)