mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-02 18:39:05 +01:00
allow switching between new and old ssh for dev
It is inconvenient to create milestones without being able to merge into the main branch. But due to the experimental nature of the ssh changes, it is not desired to use these changes in the main branch yet. This change disables the new ssh launcher by default. It can be used by changing the UseSshLibrary constant to true in remote.go. With this, it becomes possible to merge these changes into the main branch without them being used in production.
This commit is contained in:
parent
8e79eeccca
commit
37821738d8
@ -40,6 +40,8 @@ import (
|
||||
"golang.org/x/mod/semver"
|
||||
)
|
||||
|
||||
const UseSshLibrary = false
|
||||
|
||||
const RemoteTypeMShell = "mshell"
|
||||
const DefaultTerm = "xterm-256color"
|
||||
const DefaultMaxPtySize = 1024 * 1024
|
||||
@ -135,6 +137,12 @@ type pendingStateKey struct {
|
||||
RemotePtr sstore.RemotePtrType
|
||||
}
|
||||
|
||||
// for conditional launch method based on ssh library in use
|
||||
// remove once ssh library is stabilized
|
||||
type Launcher interface {
|
||||
Launch(*MShellProc, bool)
|
||||
}
|
||||
|
||||
type MShellProc struct {
|
||||
Lock *sync.Mutex
|
||||
Remote *sstore.RemoteType
|
||||
@ -163,6 +171,7 @@ type MShellProc struct {
|
||||
RunningCmds map[base.CommandKey]RunCmdType
|
||||
WaitingCmds []RunCmdType
|
||||
PendingStateCmds map[pendingStateKey]base.CommandKey // key=[remoteinstance name]
|
||||
launcher Launcher // for conditional launch method based on ssh library in use. remove once ssh library is stabilized
|
||||
}
|
||||
|
||||
type RunCmdType struct {
|
||||
@ -183,6 +192,12 @@ func CanComplete(remoteType string) bool {
|
||||
}
|
||||
}
|
||||
|
||||
// for conditional launch method based on ssh library in use
|
||||
// remove once ssh library is stabilized
|
||||
func (msh *MShellProc) Launch(interactive bool) {
|
||||
msh.launcher.Launch(msh, interactive)
|
||||
}
|
||||
|
||||
func (msh *MShellProc) GetStatus() string {
|
||||
msh.Lock.Lock()
|
||||
defer msh.Lock.Unlock()
|
||||
@ -676,7 +691,14 @@ func MakeMShell(r *sstore.RemoteType) *MShellProc {
|
||||
RunningCmds: make(map[base.CommandKey]RunCmdType),
|
||||
PendingStateCmds: make(map[pendingStateKey]base.CommandKey),
|
||||
StateMap: server.MakeShellStateMap(),
|
||||
launcher: LegacyLauncher{}, // for conditional launch method based on ssh library in use. remove once ssh library is stabilized
|
||||
}
|
||||
// for conditional launch method based on ssh library in use
|
||||
// remove once ssh library is stabilized
|
||||
if UseSshLibrary {
|
||||
rtn.launcher = NewLauncher{}
|
||||
}
|
||||
|
||||
rtn.WriteToPtyBuffer("console for connection [%s]\n", r.GetName())
|
||||
return rtn
|
||||
}
|
||||
@ -1232,7 +1254,12 @@ func (msh *MShellProc) getActiveShellTypes(ctx context.Context) ([]string, error
|
||||
return utilfn.CombineStrArrays(rtn, activeShells), nil
|
||||
}
|
||||
|
||||
func (msh *MShellProc) Launch(interactive bool) {
|
||||
// for conditional launch method based on ssh library in use
|
||||
// remove once ssh library is stabilized
|
||||
type NewLauncher struct{}
|
||||
|
||||
// func (msh *MShellProc) LaunchNew(interactive bool) {
|
||||
func (NewLauncher) Launch(msh *MShellProc, interactive bool) {
|
||||
remoteCopy := msh.GetRemoteCopy()
|
||||
if remoteCopy.Archived {
|
||||
msh.WriteToPtyBuffer("cannot launch archived remote\n")
|
||||
@ -1390,6 +1417,155 @@ func (msh *MShellProc) Launch(interactive bool) {
|
||||
return
|
||||
}
|
||||
|
||||
// for conditional launch method based on ssh library in use
|
||||
// remove once ssh library is stabilized
|
||||
type LegacyLauncher struct{}
|
||||
|
||||
// func (msh *MShellProc) LaunchLegacy(interactive bool) {
|
||||
func (LegacyLauncher) Launch(msh *MShellProc, interactive bool) {
|
||||
remoteCopy := msh.GetRemoteCopy()
|
||||
if remoteCopy.Archived {
|
||||
msh.WriteToPtyBuffer("cannot launch archived remote\n")
|
||||
return
|
||||
}
|
||||
curStatus := msh.GetStatus()
|
||||
if curStatus == StatusConnected {
|
||||
msh.WriteToPtyBuffer("remote is already connected (no action taken)\n")
|
||||
return
|
||||
}
|
||||
if curStatus == StatusConnecting {
|
||||
msh.WriteToPtyBuffer("remote is already connecting, disconnect before trying to connect again\n")
|
||||
return
|
||||
}
|
||||
sapi, err := shellapi.MakeShellApi(msh.GetShellType())
|
||||
if err != nil {
|
||||
msh.WriteToPtyBuffer("*error, %v\n", err)
|
||||
return
|
||||
}
|
||||
istatus := msh.GetInstallStatus()
|
||||
if istatus == StatusConnecting {
|
||||
msh.WriteToPtyBuffer("remote is trying to install, cancel install before trying to connect again\n")
|
||||
return
|
||||
}
|
||||
if remoteCopy.SSHOpts.SSHPort != 0 && remoteCopy.SSHOpts.SSHPort != 22 {
|
||||
msh.WriteToPtyBuffer("connecting to %s (port %d)...\n", remoteCopy.RemoteCanonicalName, remoteCopy.SSHOpts.SSHPort)
|
||||
} else {
|
||||
msh.WriteToPtyBuffer("connecting to %s...\n", remoteCopy.RemoteCanonicalName)
|
||||
}
|
||||
sshOpts := convertSSHOpts(remoteCopy.SSHOpts)
|
||||
sshOpts.SSHErrorsToTty = true
|
||||
if remoteCopy.ConnectMode != sstore.ConnectModeManual && remoteCopy.SSHOpts.SSHPassword == "" && !interactive {
|
||||
sshOpts.BatchMode = true
|
||||
}
|
||||
var cmdStr string
|
||||
if sshOpts.SSHHost == "" && remoteCopy.Local {
|
||||
var err error
|
||||
cmdStr, err = MakeLocalMShellCommandStr(remoteCopy.IsSudo())
|
||||
if err != nil {
|
||||
msh.WriteToPtyBuffer("*error, cannot find local mshell binary: %v\n", err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
cmdStr = MakeServerCommandStr()
|
||||
}
|
||||
ecmd := sshOpts.MakeSSHExecCmd(cmdStr, sapi)
|
||||
cmdPty, err := msh.addControllingTty(ecmd)
|
||||
if err != nil {
|
||||
statusErr := fmt.Errorf("cannot attach controlling tty to mshell command: %w", err)
|
||||
msh.WriteToPtyBuffer("*error, %s\n", statusErr.Error())
|
||||
msh.setErrorStatus(statusErr)
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if len(ecmd.ExtraFiles) > 0 {
|
||||
ecmd.ExtraFiles[len(ecmd.ExtraFiles)-1].Close()
|
||||
}
|
||||
}()
|
||||
go msh.RunPtyReadLoop(cmdPty)
|
||||
if remoteCopy.SSHOpts.SSHPassword != "" {
|
||||
go msh.WaitAndSendPassword(remoteCopy.SSHOpts.SSHPassword)
|
||||
}
|
||||
makeClientCtx, makeClientCancelFn := context.WithCancel(context.Background())
|
||||
defer makeClientCancelFn()
|
||||
msh.WithLock(func() {
|
||||
msh.Err = nil
|
||||
msh.ErrNoInitPk = false
|
||||
msh.Status = StatusConnecting
|
||||
msh.MakeClientCancelFn = makeClientCancelFn
|
||||
deadlineTime := time.Now().Add(RemoteConnectTimeout)
|
||||
msh.MakeClientDeadline = &deadlineTime
|
||||
go msh.NotifyRemoteUpdate()
|
||||
})
|
||||
go msh.watchClientDeadlineTime()
|
||||
cproc, initPk, err := shexec.MakeClientProc(makeClientCtx, shexec.CmdWrap{Cmd: ecmd})
|
||||
// TODO check if initPk.State is not nil
|
||||
var mshellVersion string
|
||||
var hitDeadline bool
|
||||
msh.WithLock(func() {
|
||||
msh.MakeClientCancelFn = nil
|
||||
if time.Now().After(*msh.MakeClientDeadline) {
|
||||
hitDeadline = true
|
||||
}
|
||||
msh.MakeClientDeadline = nil
|
||||
if initPk == nil {
|
||||
msh.ErrNoInitPk = true
|
||||
}
|
||||
if initPk != nil {
|
||||
msh.UName = initPk.UName
|
||||
mshellVersion = initPk.Version
|
||||
if semver.Compare(mshellVersion, scbase.MShellVersion) < 0 {
|
||||
// only set NeedsMShellUpgrade if we got an InitPk
|
||||
msh.NeedsMShellUpgrade = true
|
||||
}
|
||||
msh.InitPkShellType = initPk.Shell
|
||||
}
|
||||
msh.StateMap.Clear()
|
||||
// no notify here, because we'll call notify in either case below
|
||||
})
|
||||
if err == context.Canceled {
|
||||
if hitDeadline {
|
||||
msh.WriteToPtyBuffer("*connect timeout\n")
|
||||
msh.setErrorStatus(errors.New("connect timeout"))
|
||||
} else {
|
||||
msh.WriteToPtyBuffer("*forced disconnection\n")
|
||||
msh.WithLock(func() {
|
||||
msh.Status = StatusDisconnected
|
||||
go msh.NotifyRemoteUpdate()
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
if err == nil && semver.MajorMinor(mshellVersion) != semver.MajorMinor(scbase.MShellVersion) {
|
||||
err = fmt.Errorf("mshell version is not compatible current=%s remote=%s", scbase.MShellVersion, mshellVersion)
|
||||
}
|
||||
if err != nil {
|
||||
msh.setErrorStatus(err)
|
||||
msh.WriteToPtyBuffer("*error connecting to remote: %v\n", err)
|
||||
go msh.tryAutoInstall()
|
||||
return
|
||||
}
|
||||
msh.updateRemoteStateVars(context.Background(), msh.RemoteId, initPk)
|
||||
msh.WithLock(func() {
|
||||
msh.ServerProc = cproc
|
||||
msh.Status = StatusConnected
|
||||
})
|
||||
go func() {
|
||||
exitErr := cproc.Cmd.Wait()
|
||||
exitCode := shexec.GetExitCode(exitErr)
|
||||
msh.WithLock(func() {
|
||||
if msh.Status == StatusConnected || msh.Status == StatusConnecting {
|
||||
msh.Status = StatusDisconnected
|
||||
go msh.NotifyRemoteUpdate()
|
||||
}
|
||||
})
|
||||
msh.WriteToPtyBuffer("*disconnected exitcode=%d\n", exitCode)
|
||||
}()
|
||||
go msh.ProcessPackets()
|
||||
msh.initActiveShells()
|
||||
go msh.NotifyRemoteUpdate()
|
||||
return
|
||||
}
|
||||
|
||||
func (msh *MShellProc) initActiveShells() {
|
||||
ctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancelFn()
|
||||
|
Loading…
Reference in New Issue
Block a user