cmd/tsconnect: add progress and connection callbacks

Allows UI to display slightly more fine-grained progress when the SSH
connection is being established.

Updates tailscale/corp#7186

Signed-off-by: Mihai Parparita <mihai@tailscale.com>
pull/5977/head
Mihai Parparita 2 years ago committed by Mihai Parparita
parent 246274b8e9
commit 7741e9feb0

@ -46,7 +46,12 @@ function SSHSession({
const ref = useRef<HTMLDivElement>(null)
useEffect(() => {
if (ref.current) {
runSSHSession(ref.current, def, ipn, onDone, (err) => console.error(err))
runSSHSession(ref.current, def, ipn, {
onConnectionProgress: (p) => console.log("Connection progress", p),
onConnected() {},
onError: (err) => console.error(err),
onDone,
})
}
}, [ref])

@ -9,12 +9,18 @@ export type SSHSessionDef = {
timeoutSeconds?: number
}
export type SSHSessionCallbacks = {
onConnectionProgress: (messsage: string) => void
onConnected: () => void
onDone: () => void
onError?: (err: string) => void
}
export function runSSHSession(
termContainerNode: HTMLDivElement,
def: SSHSessionDef,
ipn: IPN,
onDone: () => void,
onError?: (err: string) => void,
callbacks: SSHSessionCallbacks,
terminalOptions?: ITerminalOptions
) {
const parentWindow = termContainerNode.ownerDocument.defaultView ?? window
@ -49,7 +55,7 @@ export function runSSHSession(
term.write(input)
},
writeErrorFn(err) {
onError?.(err)
callbacks.onError?.(err)
term.write(err)
},
setReadFn(hook) {
@ -57,13 +63,15 @@ export function runSSHSession(
},
rows: term.rows,
cols: term.cols,
onConnectionProgress: callbacks.onConnectionProgress,
onConnected: callbacks.onConnected,
onDone() {
resizeObserver?.disconnect()
term.dispose()
if (handleUnload) {
parentWindow.removeEventListener("unload", handleUnload)
}
onDone()
callbacks.onDone()
},
timeoutSeconds: def.timeoutSeconds,
})

@ -25,6 +25,8 @@ declare global {
cols: number
/** Defaults to 5 seconds */
timeoutSeconds?: number
onConnectionProgress: (message: string) => void
onConnected: () => void
onDone: () => void
}
): IPNSSHSession

@ -364,15 +364,21 @@ func (s *jsSSHSession) Run() {
if jsTimeoutSeconds := s.termConfig.Get("timeoutSeconds"); jsTimeoutSeconds.Type() == js.TypeNumber {
timeoutSeconds = jsTimeoutSeconds.Float()
}
onConnectionProgress := s.termConfig.Get("onConnectionProgress")
onConnected := s.termConfig.Get("onConnected")
onDone := s.termConfig.Get("onDone")
defer onDone.Invoke()
writeError := func(label string, err error) {
writeErrorFn.Invoke(fmt.Sprintf("%s Error: %v\r\n", label, err))
}
reportProgress := func(message string) {
onConnectionProgress.Invoke(message)
}
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeoutSeconds*float64(time.Second)))
defer cancel()
reportProgress(fmt.Sprintf("Connecting to %s…", strings.Split(s.host, ".")[0]))
c, err := s.jsIPN.dialer.UserDial(ctx, "tcp", net.JoinHostPort(s.host, "22"))
if err != nil {
writeError("Dial", err)
@ -381,10 +387,16 @@ func (s *jsSSHSession) Run() {
defer c.Close()
config := &ssh.ClientConfig{
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
User: s.username,
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
// Host keys are not used with Tailscale SSH, but we can use this
// callback to know that the connection has been established.
reportProgress("SSH connection established…")
return nil
},
User: s.username,
}
reportProgress("Starting SSH client…")
sshConn, _, _, err := ssh.NewClientConn(c, s.host, config)
if err != nil {
writeError("SSH Connection", err)
@ -442,6 +454,7 @@ func (s *jsSSHSession) Run() {
return
}
onConnected.Invoke()
err = session.Wait()
if err != nil {
writeError("Wait", err)

Loading…
Cancel
Save