From 6f7186666346af1af904755746d62d4bc5f5ec94 Mon Sep 17 00:00:00 2001 From: sawka Date: Tue, 13 Sep 2022 12:06:12 -0700 Subject: [PATCH] remote archiving, bug fixes --- pkg/cmdrunner/cmdrunner.go | 111 ++++++++++++++++++++++++++++++++----- pkg/remote/remote.go | 4 ++ pkg/remote/updatequeue.go | 4 -- pkg/sstore/dbops.go | 17 ++++++ pkg/sstore/sstore.go | 3 +- 5 files changed, 120 insertions(+), 19 deletions(-) diff --git a/pkg/cmdrunner/cmdrunner.go b/pkg/cmdrunner/cmdrunner.go index cd0e33a8d..ab56f0cee 100644 --- a/pkg/cmdrunner/cmdrunner.go +++ b/pkg/cmdrunner/cmdrunner.go @@ -43,6 +43,16 @@ var genericNameRe = regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9_ .()<>,/\"'\\[\\]{}= var positionRe = regexp.MustCompile("^((\\+|-)?[0-9]+|(\\+|-))$") var wsRe = regexp.MustCompile("\\s+") +type contextType string + +var historyContextKey = contextType("history") + +type historyContextType struct { + LineId string + CmdId string + RemotePtr *sstore.RemotePtrType +} + type MetaCmdFnType = func(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) type MetaCmdEntryType struct { IsAlias bool @@ -66,6 +76,7 @@ func init() { registerCmdFn("session:open", SessionOpenCommand) registerCmdAlias("session:new", SessionOpenCommand) registerCmdFn("session:set", SessionSetCommand) + registerCmdFn("session:delete", SessionDeleteCommand) registerCmdFn("screen", ScreenCommand) registerCmdFn("screen:close", ScreenCloseCommand) @@ -77,11 +88,16 @@ func init() { registerCmdFn("remote:show", RemoteShowCommand) registerCmdFn("remote:showall", RemoteShowAllCommand) registerCmdFn("remote:new", RemoteNewCommand) + registerCmdFn("remote:archive", RemoteArchiveCommand) + registerCmdFn("remote:set", RemoteSetCommand) registerCmdFn("remote:disconnect", RemoteDisconnectCommand) registerCmdFn("remote:connect", RemoteConnectCommand) registerCmdFn("window:resize", WindowResizeCommand) + registerCmdFn("line", LineCommand) + registerCmdFn("line:show", LineShowCommand) + registerCmdFn("history", HistoryCommand) } @@ -195,16 +211,26 @@ func RunCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.U } update := sstore.ModelUpdate{Line: rtnLine, Cmd: cmd, Interactive: pk.Interactive} sstore.MainBus.SendUpdate(ids.SessionId, update) + ctxVal := ctx.Value(historyContextKey) + if ctxVal != nil { + hctx := ctxVal.(*historyContextType) + if rtnLine != nil { + hctx.LineId = rtnLine.LineId + } + if cmd != nil { + hctx.CmdId = cmd.CmdId + hctx.RemotePtr = &cmd.Remote + } + } return nil, nil } -func addToHistory(ctx context.Context, pk *scpacket.FeCommandPacketType, update sstore.UpdatePacket, isMetaCmd bool, hadError bool) error { +func addToHistory(ctx context.Context, pk *scpacket.FeCommandPacketType, historyContext historyContextType, isMetaCmd bool, hadError bool) error { cmdStr := firstArg(pk) ids, err := resolveUiIds(ctx, pk, R_Session|R_Screen|R_Window) if err != nil { return err } - lineId, cmdId, rptr := sstore.ReadHistoryDataFromUpdate(update) hitem := &sstore.HistoryItemType{ HistoryId: uuid.New().String(), Ts: time.Now().UnixMilli(), @@ -212,14 +238,14 @@ func addToHistory(ctx context.Context, pk *scpacket.FeCommandPacketType, update SessionId: ids.SessionId, ScreenId: ids.ScreenId, WindowId: ids.WindowId, - LineId: lineId, + LineId: historyContext.LineId, HadError: hadError, - CmdId: cmdId, + CmdId: historyContext.CmdId, CmdStr: cmdStr, IsMetaCmd: isMetaCmd, } - if !isMetaCmd && rptr != nil { - hitem.Remote = ids.Remote.RemotePtr + if !isMetaCmd && historyContext.RemotePtr != nil { + hitem.Remote = *historyContext.RemotePtr } err = sstore.InsertHistoryItem(ctx, hitem) if err != nil { @@ -232,13 +258,15 @@ func EvalCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore. if len(pk.Args) == 0 { return nil, fmt.Errorf("usage: /eval [command], no command passed to eval") } + var historyContext historyContextType + ctxWithHistory := context.WithValue(ctx, historyContextKey, &historyContext) var update sstore.UpdatePacket - newPk, rtnErr := EvalMetaCommand(ctx, pk) + newPk, rtnErr := EvalMetaCommand(ctxWithHistory, pk) if rtnErr == nil { - update, rtnErr = HandleCommand(ctx, newPk) + update, rtnErr = HandleCommand(ctxWithHistory, newPk) } if !resolveBool(pk.Kwargs["nohist"], false) { - err := addToHistory(ctx, pk, update, (newPk.MetaCmd != "run"), (rtnErr != nil)) + err := addToHistory(ctx, pk, historyContext, (newPk.MetaCmd != "run"), (rtnErr != nil)) if err != nil { fmt.Printf("[error] adding to history: %v\n", err) // continue... @@ -343,7 +371,7 @@ func ScreenCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstor if firstArg == "" { return nil, fmt.Errorf("usage /screen [screen-name|screen-index|screen-id], no param specified") } - ritem, err := resolveSessionScreen(ctx, ids.SessionId, firstArg, pk.Kwargs["screen"]) + ritem, err := resolveSessionScreen(ctx, ids.SessionId, firstArg, ids.ScreenId) if err != nil { return nil, err } @@ -505,6 +533,15 @@ func RemoteNewCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (ss return update, nil } +func RemoteSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) { + ids, err := resolveUiIds(ctx, pk, R_Session|R_Screen|R_Window|R_Remote) + if err != nil { + return nil, err + } + fmt.Printf("ids: %v\n", ids) + return nil, nil +} + func RemoteShowCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) { ids, err := resolveUiIds(ctx, pk, R_Session|R_Window|R_Remote) if err != nil { @@ -524,7 +561,7 @@ func RemoteShowCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (s } return sstore.ModelUpdate{ Info: &sstore.InfoMsgType{ - InfoTitle: fmt.Sprintf("show remote '%s' info", ids.Remote.DisplayName), + InfoTitle: fmt.Sprintf("show remote [%s] info", ids.Remote.DisplayName), InfoLines: splitLinesForInfo(buf.String()), }, }, nil @@ -550,6 +587,15 @@ func RemoteShowAllCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) }, nil } +func RemoteArchiveCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) { + ids, err := resolveUiIds(ctx, pk, R_Session|R_Window|R_Remote) + if err != nil { + return nil, err + } + update := sstore.InfoMsgUpdate("remote [%s] archived", ids.Remote.DisplayName) + return update, nil +} + func RemoteCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) { return nil, fmt.Errorf("/remote requires a subcommand: %s", formatStrs([]string{"show"}, "or", false)) } @@ -568,7 +614,7 @@ func SetEnvCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstor } update := sstore.ModelUpdate{ Info: &sstore.InfoMsgType{ - InfoTitle: fmt.Sprintf("environment for [%s] remote", ids.Remote.DisplayName), + InfoTitle: fmt.Sprintf("environment for remote [%s]", ids.Remote.DisplayName), InfoLines: infoLines, }, } @@ -615,7 +661,7 @@ func CrCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.Up return nil, err } if rptr == nil { - return nil, fmt.Errorf("/cr error: remote '%s' not found", newRemote) + return nil, fmt.Errorf("/cr error: remote [%s] not found", newRemote) } err = sstore.UpdateCurRemote(ctx, ids.SessionId, ids.WindowId, *rptr) if err != nil { @@ -991,6 +1037,26 @@ func SessionOpenCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) ( return update, nil } +func SessionDeleteCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) { + ids, err := resolveUiIds(ctx, pk, R_Session) + if err != nil { + return nil, err + } + err = sstore.DeleteSession(ctx, ids.SessionId) + if err != nil { + return nil, fmt.Errorf("cannot delete session: %v", err) + } + sessionIds, _ := sstore.GetAllSessionIds(ctx) // ignore error, session is already deleted so that's the main return value + delSession := &sstore.SessionType{SessionId: ids.SessionId, Remove: true} + update := sstore.ModelUpdate{ + Sessions: []*sstore.SessionType{delSession}, + } + if len(sessionIds) > 0 { + update.ActiveSessionId = sessionIds[0] + } + return update, nil +} + func SessionSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) { ids, err := resolveUiIds(ctx, pk, R_Session) if err != nil { @@ -1027,6 +1093,10 @@ func SessionSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (s } func SessionCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) { + ids, err := resolveUiIds(ctx, pk, 0) + if err != nil { + return nil, err + } firstArg := firstArg(pk) if firstArg == "" { return nil, fmt.Errorf("usage /session [name|id|pos], no param specified") @@ -1036,7 +1106,7 @@ func SessionCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (ssto return nil, err } ritems := sessionsToResolveItems(bareSessions) - ritem, err := genericResolve(firstArg, pk.Kwargs["session"], ritems, "session") + ritem, err := genericResolve(firstArg, ids.SessionId, ritems, "session") if err != nil { return nil, err } @@ -1179,3 +1249,16 @@ func WindowResizeCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) } return nil, nil } + +func LineCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) { + return nil, fmt.Errorf("/line requires a subcommand: %s", formatStrs([]string{"show"}, "or", false)) +} + +func LineShowCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) { + ids, err := resolveUiIds(ctx, pk, R_Session|R_Screen|R_Window) + if err != nil { + return nil, err + } + fmt.Printf("/line:show ids %v\n", ids) + return nil, nil +} diff --git a/pkg/remote/remote.go b/pkg/remote/remote.go index 85235762f..1a7f293d3 100644 --- a/pkg/remote/remote.go +++ b/pkg/remote/remote.go @@ -413,6 +413,10 @@ func (msh *MShellProc) GetRemoteName() string { func (msh *MShellProc) Launch() { remoteCopy := msh.getRemoteCopy() + if remoteCopy.ConnectMode == sstore.ConnectModeArchive { + logf(&remoteCopy, "cannot launch archived remote") + return + } logf(&remoteCopy, "starting launch") ecmd := convertSSHOpts(remoteCopy.SSHOpts).MakeSSHExecCmd(MShellServerCommand) cmdPty, err := msh.addControllingTty(ecmd) diff --git a/pkg/remote/updatequeue.go b/pkg/remote/updatequeue.go index bab359a1d..4665511ff 100644 --- a/pkg/remote/updatequeue.go +++ b/pkg/remote/updatequeue.go @@ -43,10 +43,6 @@ func removeFirstCmdWaitFn(ck base.CommandKey) func() { delete(GlobalStore.CmdWaitMap, ck) return nil } - if len(fns) == 1 { - delete(GlobalStore.CmdWaitMap, ck) - return fns[0] - } fn := fns[0] GlobalStore.CmdWaitMap[ck] = fns[1:] return fn diff --git a/pkg/sstore/dbops.go b/pkg/sstore/dbops.go index 1c2fd590f..1d7285172 100644 --- a/pkg/sstore/dbops.go +++ b/pkg/sstore/dbops.go @@ -122,6 +122,19 @@ func InsertRemote(ctx context.Context, remote *RemoteType) error { return txErr } +func ArchiveRemote(ctx context.Context, remoteId string) error { + txErr := WithTx(ctx, func(tx *TxWrap) error { + query := `SELECT remoteid FROM remote WHERE remoteid = ?` + if !tx.Exists(query, remoteId) { + return fmt.Errorf("cannot archive, remote does not exist") + } + query = `UPDATE remote SET connectmode = ?, physicalid = '', remotetype = '', remotealias = '', initpk = '', sshopts = '', remoteopts = '', lastconnectts = 0 WHERE remoteid = ?` + tx.ExecWrap(query, ConnectModeArchive, remoteId) + return nil + }) + return txErr +} + func InsertHistoryItem(ctx context.Context, hitem *HistoryItemType) error { if hitem == nil { return fmt.Errorf("cannot insert nil history item") @@ -910,3 +923,7 @@ func UpdateCmdTermOpts(ctx context.Context, sessionId string, cmdId string, term }) return txErr } + +func DeleteSession(ctx context.Context, sessionId string) error { + return nil +} diff --git a/pkg/sstore/sstore.go b/pkg/sstore/sstore.go index f67db53d1..2c6ba812f 100644 --- a/pkg/sstore/sstore.go +++ b/pkg/sstore/sstore.go @@ -55,6 +55,7 @@ const ( ConnectModeStartup = "startup" ConnectModeAuto = "auto" ConnectModeManual = "manual" + ConnectModeArchive = "archive" ) const ( @@ -71,7 +72,7 @@ func GetSessionDBName() string { } func IsValidConnectMode(mode string) bool { - return mode == ConnectModeStartup || mode == ConnectModeAuto || mode == ConnectModeManual + return mode == ConnectModeStartup || mode == ConnectModeAuto || mode == ConnectModeManual || mode == ConnectModeArchive } func GetDB(ctx context.Context) (*sqlx.DB, error) {