feat: send or move files and folders to another machine or an SSH host from the move dialog, streamed as tar with progress, speed and cancel; same conflict rules as a local move
This commit is contained in:
1 parent
1a38c2ac18
commit
18d6684c55
7 files changed
+1274
-28
No files matched your search
+31
-19
@@ -148,32 +148,22 @@ func (s *sshShell) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// runSSH connects to the target and bridges its shell to the session.
|
||||
func (a *Agent) runSSH(parent context.Context, sid string, t proto.SSHTarget) {
|
||||
status := func(st, note string) {
|
||||
a.postOut(context.Background(), sid, proto.OutMessage{Status: st, Note: note})
|
||||
}
|
||||
fail := func(err error) {
|
||||
log.Printf("ssh %s: %v", sid, err)
|
||||
status(proto.SSHErr, err.Error())
|
||||
a.postOut(context.Background(), sid, proto.OutMessage{Data: b64.EncodeToString([]byte("\x1b[31m" + err.Error() + "\x1b[0m\r\n"))})
|
||||
a.postOut(context.Background(), sid, proto.OutMessage{Exit: true})
|
||||
}
|
||||
// sshConnect connects and signs in to t, saying how it goes by status (the
|
||||
// SSHStatus steps). It returns the client and the host key's fingerprint.
|
||||
func (a *Agent) sshConnect(ctx context.Context, t proto.SSHTarget, status func(st, note string)) (*ssh.Client, string, error) {
|
||||
if t.Port == 0 {
|
||||
t.Port = 22
|
||||
}
|
||||
addr := net.JoinHostPort(t.Host, strconv.Itoa(t.Port))
|
||||
auth, err := sshAuth(t)
|
||||
if err != nil {
|
||||
fail(err)
|
||||
return
|
||||
return nil, "", err
|
||||
}
|
||||
status(proto.SSHDial, "подключение к "+addr)
|
||||
d := net.Dialer{Timeout: 15 * time.Second, KeepAlive: 30 * time.Second}
|
||||
conn, err := d.DialContext(parent, "tcp", addr)
|
||||
conn, err := d.DialContext(ctx, "tcp", addr)
|
||||
if err != nil {
|
||||
fail(fmt.Errorf("не подключиться к %s: %v", addr, err))
|
||||
return
|
||||
return nil, "", fmt.Errorf("не подключиться к %s: %v", addr, err)
|
||||
}
|
||||
status(proto.SSHAuth, "вход как "+t.User)
|
||||
var fp string
|
||||
@@ -190,11 +180,33 @@ func (a *Agent) runSSH(parent context.Context, sid string, t proto.SSHTarget) {
|
||||
if strings.Contains(msg, "unable to authenticate") {
|
||||
msg = "сервер не принял вход как " + t.User + " - проверьте пароль или ключ"
|
||||
}
|
||||
fail(errors.New(msg))
|
||||
return
|
||||
return nil, "", errors.New(msg)
|
||||
}
|
||||
_ = conn.SetDeadline(time.Time{})
|
||||
client := ssh.NewClient(c, chans, reqs)
|
||||
return ssh.NewClient(c, chans, reqs), fp, nil
|
||||
}
|
||||
|
||||
// runSSH connects to the target and bridges its shell to the session.
|
||||
func (a *Agent) runSSH(parent context.Context, sid string, t proto.SSHTarget) {
|
||||
status := func(st, note string) {
|
||||
a.postOut(context.Background(), sid, proto.OutMessage{Status: st, Note: note})
|
||||
}
|
||||
fail := func(err error) {
|
||||
log.Printf("ssh %s: %v", sid, err)
|
||||
status(proto.SSHErr, err.Error())
|
||||
a.postOut(context.Background(), sid, proto.OutMessage{Data: b64.EncodeToString([]byte("\x1b[31m" + err.Error() + "\x1b[0m\r\n"))})
|
||||
a.postOut(context.Background(), sid, proto.OutMessage{Exit: true})
|
||||
}
|
||||
client, fp, err := a.sshConnect(parent, t, status)
|
||||
if err != nil {
|
||||
fail(err)
|
||||
return
|
||||
}
|
||||
port := t.Port
|
||||
if port == 0 {
|
||||
port = 22
|
||||
}
|
||||
addr := net.JoinHostPort(t.Host, strconv.Itoa(port))
|
||||
sess, err := client.NewSession()
|
||||
if err != nil {
|
||||
client.Close()
|
||||
|
||||
Reference in new issue
Block a user