050f2b74c3
- add settings for ssh config - implement save remote function by ssh
60 lines
2.1 KiB
Go
60 lines
2.1 KiB
Go
// uploader.go — small adapter that satisfies application.SSHUploader by
|
|
// dialing a one-shot connection per upload. This keeps the application
|
|
// layer free of any direct dependency on golang.org/x/crypto/ssh while
|
|
// still exposing a clean, unit-testable contract.
|
|
package ssh
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/mmmy/snapgo/internal/domain"
|
|
)
|
|
|
|
// Uploader is the production implementation of application.SSHUploader.
|
|
//
|
|
// We dial fresh per-upload because:
|
|
// - Captures happen sparsely (a few per minute at peak), so the cost of
|
|
// a TCP+SSH handshake is dwarfed by user think-time.
|
|
// - Holding a long-lived connection would force us to add keepalives,
|
|
// reconnection logic, and config-change invalidation — not worth it
|
|
// for the current usage profile.
|
|
type Uploader struct {
|
|
cfg domain.SSHConfig
|
|
}
|
|
|
|
// NewUploader returns a ready-to-use uploader. The configuration is
|
|
// captured by value so a simultaneous in-flight upload cannot be re-
|
|
// targeted by a settings save.
|
|
func NewUploader(cfg domain.SSHConfig) *Uploader {
|
|
return &Uploader{cfg: cfg}
|
|
}
|
|
|
|
// Upload satisfies application.SSHUploader. We log entry/exit at INFO so
|
|
// the operator sees a single line per upload in the normal happy path,
|
|
// and ERROR with elapsed time when something fails.
|
|
func (u *Uploader) Upload(ctx context.Context, remoteRelPath string, data []byte, mode os.FileMode) error {
|
|
start := time.Now()
|
|
sshLog().Info("uploader.Upload start",
|
|
"host", u.cfg.Host, "user", u.cfg.User, "port", u.cfg.Port,
|
|
"remote_path", remoteRelPath, "size", len(data))
|
|
|
|
client, err := Dial(ctx, u.cfg)
|
|
if err != nil {
|
|
sshLog().Error("uploader.Upload dial failed",
|
|
"host", u.cfg.Host, "elapsed", time.Since(start), "err", err)
|
|
return err
|
|
}
|
|
defer client.Close()
|
|
if err := client.CopyFile(ctx, remoteRelPath, data, mode); err != nil {
|
|
sshLog().Error("uploader.Upload copy failed",
|
|
"remote_path", remoteRelPath, "elapsed", time.Since(start), "err", err)
|
|
return err
|
|
}
|
|
sshLog().Info("uploader.Upload done",
|
|
"remote_path", remoteRelPath, "size", len(data),
|
|
"total_elapsed", time.Since(start))
|
|
return nil
|
|
}
|