pass 'uicontext' with fecmd, use that to resolve ids instead of kwargs. other bug fixes

This commit is contained in:
sawka 2022-08-29 16:31:06 -07:00
parent f2a5985349
commit 03dd6b1a7e
8 changed files with 215 additions and 174 deletions

View File

@ -158,7 +158,7 @@ func HandleGetRemotes(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Credentials", "true")
w.Header().Set("Vary", "Origin")
w.Header().Set("Cache-Control", "no-cache")
remotes := remote.GetAllRemoteState()
remotes := remote.GetAllRemoteRuntimeState()
WriteJsonSuccess(w, remotes)
return
}

View File

@ -141,28 +141,22 @@ func resolveInt(arg string, def int) (int, error) {
}
func RunCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
ids, err := resolveIds(ctx, pk, R_Session|R_Window|R_Remote)
ids, err := resolveUiIds(ctx, pk, R_Session|R_Window|R_RemoteConnected)
if err != nil {
return nil, fmt.Errorf("/run error: %w", err)
}
if !ids.RState.IsConnected() {
return nil, fmt.Errorf("cannot run command, remote '%s' not connected", ids.RemoteDisplayName)
}
if ids.RemoteState == nil {
return nil, fmt.Errorf("cannot run command, remote '%s' has no state", ids.RemoteDisplayName)
}
cmdId := uuid.New().String()
cmdStr := firstArg(pk)
runPacket := packet.MakeRunPacket()
runPacket.ReqId = uuid.New().String()
runPacket.CK = base.MakeCommandKey(ids.SessionId, cmdId)
runPacket.Cwd = ids.RemoteState.Cwd
runPacket.Env0 = ids.RemoteState.Env0
runPacket.Cwd = ids.Remote.RemoteState.Cwd
runPacket.Env0 = ids.Remote.RemoteState.Env0
runPacket.EnvComplete = true
runPacket.UsePty = true
runPacket.TermOpts = &packet.TermOpts{Rows: remote.DefaultTermRows, Cols: remote.DefaultTermCols, Term: remote.DefaultTerm}
runPacket.Command = strings.TrimSpace(cmdStr)
cmd, err := remote.RunCommand(ctx, cmdId, ids.RemotePtr, ids.RemoteState, runPacket)
cmd, err := remote.RunCommand(ctx, cmdId, ids.Remote.RemotePtr, ids.Remote.RemoteState, runPacket)
if err != nil {
return nil, err
}
@ -175,7 +169,7 @@ func RunCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.U
func addToHistory(ctx context.Context, pk *scpacket.FeCommandPacketType, update sstore.UpdatePacket, isMetaCmd bool, hadError bool) error {
cmdStr := firstArg(pk)
ids, err := resolveIds(ctx, pk, R_Session|R_Screen|R_Window)
ids, err := resolveUiIds(ctx, pk, R_Session|R_Screen|R_Window)
if err != nil {
return err
}
@ -194,7 +188,7 @@ func addToHistory(ctx context.Context, pk *scpacket.FeCommandPacketType, update
IsMetaCmd: isMetaCmd,
}
if !isMetaCmd && rptr != nil {
hitem.Remote = *rptr
hitem.Remote = ids.Remote.RemotePtr
}
err = sstore.InsertHistoryItem(ctx, hitem)
if err != nil {
@ -223,7 +217,7 @@ func EvalCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.
}
func ScreenCloseCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
ids, err := resolveIds(ctx, pk, R_Session|R_Screen)
ids, err := resolveUiIds(ctx, pk, R_Session|R_Screen)
if err != nil {
return nil, fmt.Errorf("/screen:close cannot close screen: %w", err)
}
@ -235,7 +229,7 @@ func ScreenCloseCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (
}
func ScreenOpenCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
ids, err := resolveIds(ctx, pk, R_Session)
ids, err := resolveUiIds(ctx, pk, R_Session)
if err != nil {
return nil, fmt.Errorf("/screen:open cannot open screen: %w", err)
}
@ -255,7 +249,7 @@ func ScreenOpenCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (s
}
func ScreenSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
ids, err := resolveIds(ctx, pk, R_Session|R_Screen)
ids, err := resolveUiIds(ctx, pk, R_Session|R_Screen)
if err != nil {
return nil, err
}
@ -310,7 +304,7 @@ func ScreenSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (ss
}
func ScreenCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
ids, err := resolveIds(ctx, pk, R_Session)
ids, err := resolveUiIds(ctx, pk, R_Session)
if err != nil {
return nil, fmt.Errorf("/screen cannot switch to screen: %w", err)
}
@ -330,17 +324,11 @@ func ScreenCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstor
}
func UnSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
ids, err := resolveIds(ctx, pk, R_Session|R_Window|R_Remote)
ids, err := resolveUiIds(ctx, pk, R_Session|R_Window|R_RemoteConnected)
if err != nil {
return nil, err
return nil, fmt.Errorf("cannot unset: %v", err)
}
if !ids.RState.IsConnected() {
return nil, fmt.Errorf("remote '%s' is not connected, cannot unset", ids.RemoteDisplayName)
}
if ids.RemoteState == nil {
return nil, fmt.Errorf("remote '%s' state is not available, cannot unset", ids.RemoteDisplayName)
}
envMap := shexec.ParseEnv0(ids.RemoteState.Env0)
envMap := shexec.ParseEnv0(ids.Remote.RemoteState.Env0)
unsetVars := make(map[string]bool)
for _, argStr := range pk.Args {
eqIdx := strings.Index(argStr, "=")
@ -350,16 +338,16 @@ func UnSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore
delete(envMap, argStr)
unsetVars[argStr] = true
}
state := *ids.RemoteState
state := *ids.Remote.RemoteState
state.Env0 = shexec.MakeEnv0(envMap)
remote, err := sstore.UpdateRemoteState(ctx, ids.SessionId, ids.WindowId, ids.RemotePtr, state)
remote, err := sstore.UpdateRemoteState(ctx, ids.SessionId, ids.WindowId, ids.Remote.RemotePtr, state)
if err != nil {
return nil, err
}
update := sstore.ModelUpdate{
Sessions: sstore.MakeSessionsUpdateForRemote(ids.SessionId, remote),
Info: &sstore.InfoMsgType{
InfoMsg: fmt.Sprintf("[%s] unset vars: %s", ids.RemoteDisplayName, formatStrs(mapToStrs(unsetVars), "and", false)),
InfoMsg: fmt.Sprintf("[%s] unset vars: %s", ids.Remote.DisplayName, formatStrs(mapToStrs(unsetVars), "and", false)),
TimeoutMs: 2000,
},
}
@ -367,15 +355,11 @@ func UnSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore
}
func RemoteShowCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
ids, err := resolveIds(ctx, pk, R_Session|R_Window|R_Remote)
ids, err := resolveUiIds(ctx, pk, R_Session|R_Window|R_Remote)
if err != nil {
return nil, err
}
curRemote := remote.GetRemoteById(ids.RemotePtr.RemoteId)
if curRemote == nil {
return nil, fmt.Errorf("invalid remote '%s' (not found)", ids.RemoteDisplayName)
}
state := curRemote.GetRemoteState()
state := ids.Remote.RState
var buf bytes.Buffer
buf.WriteString(fmt.Sprintf(" %-15s %s\n", "type", state.RemoteType))
buf.WriteString(fmt.Sprintf(" %-15s %s\n", "remoteid", state.RemoteId))
@ -384,19 +368,19 @@ func RemoteShowCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (s
buf.WriteString(fmt.Sprintf(" %-15s %s\n", "canonicalname", state.RemoteCanonicalName))
buf.WriteString(fmt.Sprintf(" %-15s %s\n", "status", state.Status))
buf.WriteString(fmt.Sprintf(" %-15s %s\n", "connectmode", state.ConnectMode))
if ids.RemoteState != nil {
buf.WriteString(fmt.Sprintf(" %-15s %s\n", "cwd", ids.RemoteState.Cwd))
if ids.Remote.RemoteState != nil {
buf.WriteString(fmt.Sprintf(" %-15s %s\n", "cwd", ids.Remote.RemoteState.Cwd))
}
return sstore.ModelUpdate{
Info: &sstore.InfoMsgType{
InfoTitle: fmt.Sprintf("show remote '%s' info", ids.RemoteDisplayName),
InfoTitle: fmt.Sprintf("show remote '%s' info", ids.Remote.DisplayName),
InfoLines: splitLinesForInfo(buf.String()),
},
}, nil
}
func RemoteShowAllCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
stateArr := remote.GetAllRemoteState()
stateArr := remote.GetAllRemoteRuntimeState()
var buf bytes.Buffer
for _, rstate := range stateArr {
var name string
@ -420,17 +404,11 @@ func RemoteCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstor
}
func SetEnvCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
ids, err := resolveIds(ctx, pk, R_Session|R_Window|R_Remote)
ids, err := resolveUiIds(ctx, pk, R_Session|R_Window|R_RemoteConnected)
if err != nil {
return nil, err
return nil, fmt.Errorf("cannot setenv: %v", err)
}
if !ids.RState.IsConnected() {
return nil, fmt.Errorf("remote '%s' is not connected, cannot setenv", ids.RemoteDisplayName)
}
if ids.RemoteState == nil {
return nil, fmt.Errorf("remote '%s' state is not available, cannot setenv", ids.RemoteDisplayName)
}
envMap := shexec.ParseEnv0(ids.RemoteState.Env0)
envMap := shexec.ParseEnv0(ids.Remote.RemoteState.Env0)
if len(pk.Args) == 0 {
var infoLines []string
for varName, varVal := range envMap {
@ -439,7 +417,7 @@ func SetEnvCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstor
}
update := sstore.ModelUpdate{
Info: &sstore.InfoMsgType{
InfoTitle: fmt.Sprintf("environment for [%s] remote", ids.RemoteDisplayName),
InfoTitle: fmt.Sprintf("environment for [%s] remote", ids.Remote.DisplayName),
InfoLines: infoLines,
},
}
@ -456,16 +434,16 @@ func SetEnvCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstor
envMap[envName] = envVal
setVars[envName] = true
}
state := *ids.RemoteState
state := *ids.Remote.RemoteState
state.Env0 = shexec.MakeEnv0(envMap)
remote, err := sstore.UpdateRemoteState(ctx, ids.SessionId, ids.WindowId, ids.RemotePtr, state)
remote, err := sstore.UpdateRemoteState(ctx, ids.SessionId, ids.WindowId, ids.Remote.RemotePtr, state)
if err != nil {
return nil, err
}
update := sstore.ModelUpdate{
Sessions: sstore.MakeSessionsUpdateForRemote(ids.SessionId, remote),
Info: &sstore.InfoMsgType{
InfoMsg: fmt.Sprintf("[%s] set vars: %s", ids.RemoteDisplayName, formatStrs(mapToStrs(setVars), "and", false)),
InfoMsg: fmt.Sprintf("[%s] set vars: %s", ids.Remote.DisplayName, formatStrs(mapToStrs(setVars), "and", false)),
TimeoutMs: 2000,
},
}
@ -473,7 +451,7 @@ func SetEnvCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstor
}
func CrCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
ids, err := resolveIds(ctx, pk, R_Session|R_Window)
ids, err := resolveUiIds(ctx, pk, R_Session|R_Window)
if err != nil {
return nil, fmt.Errorf("/cr error: %w", err)
}
@ -507,37 +485,27 @@ func CrCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.Up
}
func CdCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
ids, err := resolveIds(ctx, pk, R_Session|R_Window|R_Remote)
ids, err := resolveUiIds(ctx, pk, R_Session|R_Window|R_RemoteConnected)
if err != nil {
return nil, fmt.Errorf("/cd error: %w", err)
}
newDir := firstArg(pk)
curRemote := remote.GetRemoteById(ids.RemotePtr.RemoteId)
if curRemote == nil {
return nil, fmt.Errorf("remote '%s' not found, cannot change directory", ids.RemoteDisplayName)
}
if !ids.RState.IsConnected() {
return nil, fmt.Errorf("remote '%s' is not connected, cannot change directory", ids.RemoteDisplayName)
}
if ids.RemoteState == nil {
return nil, fmt.Errorf("remote '%s' state is not available, cannot change directory", ids.RemoteDisplayName)
}
if newDir == "" {
return sstore.ModelUpdate{
Info: &sstore.InfoMsgType{
InfoMsg: fmt.Sprintf("[%s] current directory = %s", ids.RemoteDisplayName, ids.RemoteState.Cwd),
InfoMsg: fmt.Sprintf("[%s] current directory = %s", ids.Remote.DisplayName, ids.Remote.RemoteState.Cwd),
},
}, nil
}
newDir, err = ids.RState.ExpandHomeDir(newDir)
newDir, err = ids.Remote.RState.ExpandHomeDir(newDir)
if err != nil {
return nil, err
}
if !strings.HasPrefix(newDir, "/") {
if ids.RemoteState == nil {
if ids.Remote.RemoteState == nil {
return nil, fmt.Errorf("/cd error: cannot get current remote directory (can only cd with absolute path)")
}
newDir = path.Join(ids.RemoteState.Cwd, newDir)
newDir = path.Join(ids.Remote.RemoteState.Cwd, newDir)
newDir, err = filepath.Abs(newDir)
if err != nil {
return nil, fmt.Errorf("/cd error: error canonicalizing new directory: %w", err)
@ -546,23 +514,23 @@ func CdCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.Up
cdPacket := packet.MakeCdPacket()
cdPacket.ReqId = uuid.New().String()
cdPacket.Dir = newDir
resp, err := curRemote.PacketRpc(ctx, cdPacket)
resp, err := ids.Remote.MShell.PacketRpc(ctx, cdPacket)
if err != nil {
return nil, err
}
if err = resp.Err(); err != nil {
return nil, err
}
state := *ids.RemoteState
state := *ids.Remote.RemoteState
state.Cwd = newDir
remote, err := sstore.UpdateRemoteState(ctx, ids.SessionId, ids.WindowId, ids.RemotePtr, state)
remoteInst, err := sstore.UpdateRemoteState(ctx, ids.SessionId, ids.WindowId, ids.Remote.RemotePtr, state)
if err != nil {
return nil, err
}
update := sstore.ModelUpdate{
Sessions: sstore.MakeSessionsUpdateForRemote(ids.SessionId, remote),
Sessions: sstore.MakeSessionsUpdateForRemote(ids.SessionId, remoteInst),
Info: &sstore.InfoMsgType{
InfoMsg: fmt.Sprintf("[%s] current directory = %s", ids.RemoteDisplayName, newDir),
InfoMsg: fmt.Sprintf("[%s] current directory = %s", ids.Remote.DisplayName, newDir),
TimeoutMs: 2000,
},
}
@ -682,10 +650,15 @@ func longestPrefix(root string, comps []string) string {
return lcp
}
func doMetaCompGen(ctx context.Context, ids resolvedIds, prefix string, forDisplay bool) ([]string, bool, error) {
comps, hasMore, err := doCompGen(ctx, ids, prefix, "file", forDisplay)
if err != nil {
return nil, false, err
func doMetaCompGen(ctx context.Context, pk *scpacket.FeCommandPacketType, prefix string, forDisplay bool) ([]string, bool, error) {
ids, err := resolveUiIds(ctx, pk, 0) // best effort
var comps []string
var hasMore bool
if ids.Remote != nil && ids.Remote.RState.IsConnected() {
comps, hasMore, err = doCompGen(ctx, pk, prefix, "file", forDisplay)
if err != nil {
return nil, false, err
}
}
validCommands := getValidCommands()
for _, cmd := range validCommands {
@ -700,26 +673,23 @@ func doMetaCompGen(ctx context.Context, ids resolvedIds, prefix string, forDispl
return comps, hasMore, nil
}
func doCompGen(ctx context.Context, ids resolvedIds, prefix string, compType string, forDisplay bool) ([]string, bool, error) {
func doCompGen(ctx context.Context, pk *scpacket.FeCommandPacketType, prefix string, compType string, forDisplay bool) ([]string, bool, error) {
if compType == "metacommand" {
return doMetaCompGen(ctx, ids, prefix, forDisplay)
return doMetaCompGen(ctx, pk, prefix, forDisplay)
}
if !packet.IsValidCompGenType(compType) {
return nil, false, fmt.Errorf("/compgen invalid type '%s'", compType)
}
ids, err := resolveUiIds(ctx, pk, R_Session|R_Window|R_RemoteConnected)
if err != nil {
return nil, false, fmt.Errorf("compgen error: %w", err)
}
cgPacket := packet.MakeCompGenPacket()
cgPacket.ReqId = uuid.New().String()
cgPacket.CompType = compType
cgPacket.Prefix = prefix
if ids.RemoteState == nil {
return nil, false, fmt.Errorf("/compgen invalid remote state")
}
cgPacket.Cwd = ids.RemoteState.Cwd
curRemote := remote.GetRemoteById(ids.RemotePtr.RemoteId)
if curRemote == nil {
return nil, false, fmt.Errorf("invalid remote, cannot execute command")
}
resp, err := curRemote.PacketRpc(ctx, cgPacket)
cgPacket.Cwd = ids.Remote.RemoteState.Cwd
resp, err := ids.Remote.MShell.PacketRpc(ctx, cgPacket)
if err != nil {
return nil, false, err
}
@ -732,10 +702,6 @@ func doCompGen(ctx context.Context, ids resolvedIds, prefix string, compType str
}
func CompGenCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
ids, err := resolveIds(ctx, pk, R_Session|R_Window|R_Remote)
if err != nil {
return nil, fmt.Errorf("/compgen error: %w", err)
}
cmdLine := firstArg(pk)
pos := len(cmdLine)
if pk.Kwargs["comppos"] != "" {
@ -766,7 +732,7 @@ func CompGenCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (ssto
if len(parts) > 0 {
lastPart = parts[len(parts)-1]
}
comps, hasMore, err := doCompGen(ctx, ids, lastPart, compType, showComps)
comps, hasMore, err := doCompGen(ctx, pk, lastPart, compType, showComps)
if err != nil {
return nil, err
}
@ -777,7 +743,7 @@ func CompGenCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (ssto
}
func CommentCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
ids, err := resolveIds(ctx, pk, R_Session|R_Window)
ids, err := resolveUiIds(ctx, pk, R_Session|R_Window)
if err != nil {
return nil, fmt.Errorf("/comment error: %w", err)
}
@ -866,7 +832,7 @@ func SessionOpenCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (
}
func SessionSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
ids, err := resolveIds(ctx, pk, R_Session)
ids, err := resolveUiIds(ctx, pk, R_Session)
if err != nil {
return nil, err
}
@ -914,6 +880,10 @@ func SessionCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (ssto
if err != nil {
return nil, err
}
err = sstore.SetActiveSessionId(ctx, ritem.Id)
if err != nil {
return nil, err
}
update := sstore.ModelUpdate{
ActiveSessionId: ritem.Id,
Info: &sstore.InfoMsgType{
@ -925,7 +895,7 @@ func SessionCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (ssto
}
func ClearCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
ids, err := resolveIds(ctx, pk, R_Session|R_Screen|R_Window)
ids, err := resolveUiIds(ctx, pk, R_Session|R_Screen|R_Window)
if err != nil {
return nil, err
}
@ -943,7 +913,7 @@ func ClearCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore
const DefaultMaxHistoryItems = 10000
func HistoryCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
ids, err := resolveIds(ctx, pk, R_Session|R_Screen|R_Window|R_Remote)
ids, err := resolveUiIds(ctx, pk, R_Session|R_Screen|R_Window|R_Remote)
if err != nil {
return nil, err
}
@ -963,7 +933,7 @@ func HistoryCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (ssto
}
var filteredItems []*sstore.HistoryItemType
for _, hitem := range hitems {
if hitem.ScreenId == ids.ScreenId && hitem.WindowId == ids.WindowId && (hitem.Remote == ids.RemotePtr || hitem.IsMetaCmd) {
if hitem.ScreenId == ids.ScreenId && hitem.WindowId == ids.WindowId && (hitem.Remote == ids.Remote.RemotePtr || hitem.IsMetaCmd) {
filteredItems = append(filteredItems, hitem)
}
}
@ -986,6 +956,9 @@ func HistoryCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (ssto
InfoMsg: fmt.Sprintf("history, limited to current session, screen, window, and remote (maxitems=%d)", maxItems),
InfoLines: splitLinesForInfo(buf.String()),
}
update.History = &sstore.HistoryInfoType{
Items: filteredItems,
}
return update, nil
}

View File

@ -14,24 +14,26 @@ import (
)
const (
R_Session = 1
R_Screen = 2
R_Window = 4
R_Remote = 8
R_SessionOpt = 16
R_ScreenOpt = 32
R_WindowOpt = 64
R_RemoteOpt = 128
R_Session = 1
R_Screen = 2
R_Window = 4
R_Remote = 8
R_RemoteConnected = 8 + 16
)
type resolvedIds struct {
SessionId string
ScreenId string
WindowId string
RemotePtr sstore.RemotePtrType
RemoteState *sstore.RemoteState
RemoteDisplayName string
RState remote.RemoteState
SessionId string
ScreenId string
WindowId string
Remote *ResolvedRemote
}
type ResolvedRemote struct {
DisplayName string
RemotePtr sstore.RemotePtrType
RemoteState *sstore.RemoteState
RState remote.RemoteRuntimeState
MShell *remote.MShellProc
}
type ResolveItem struct {
@ -116,52 +118,45 @@ func resolveByPosition(items []ResolveItem, curId string, posStr string) *Resolv
return &items[pos-1]
}
func resolveIds(ctx context.Context, pk *scpacket.FeCommandPacketType, rtype int) (resolvedIds, error) {
func resolveUiIds(ctx context.Context, pk *scpacket.FeCommandPacketType, rtype int) (resolvedIds, error) {
fmt.Printf("resolve-ui-ids: %#v\n", pk)
rtn := resolvedIds{}
if rtype == 0 {
return rtn, nil
}
var err error
if (rtype&R_Session)+(rtype&R_SessionOpt) > 0 {
rtn.SessionId, err = resolveSessionId(pk)
if err != nil {
return rtn, err
}
if rtn.SessionId == "" && (rtype&R_Session) > 0 {
return rtn, fmt.Errorf("no session")
uictx := pk.UIContext
if uictx != nil {
rtn.SessionId = uictx.SessionId
rtn.ScreenId = uictx.ScreenId
rtn.WindowId = uictx.WindowId
if uictx.Remote != nil && rtn.SessionId != "" && rtn.WindowId != "" {
rr, err := resolveRemoteFromPtr(ctx, uictx.Remote, rtn.SessionId, rtn.WindowId)
if err != nil {
if rtype&R_Remote > 0 {
return rtn, err
}
// otherwise just don't set uictx.Remote
} else {
rtn.Remote = rr
}
}
}
if (rtype&R_Window)+(rtype&R_WindowOpt) > 0 {
rtn.WindowId, err = resolveWindowId(pk, rtn.SessionId)
if err != nil {
return rtn, err
}
if rtn.WindowId == "" && (rtype&R_Window) > 0 {
return rtn, fmt.Errorf("no window")
}
if rtype&R_Session > 0 && rtn.SessionId == "" {
return rtn, fmt.Errorf("no session")
}
if (rtype&R_Screen)+(rtype&R_ScreenOpt) > 0 {
rtn.ScreenId, err = resolveScreenId(ctx, pk, rtn.SessionId)
if err != nil {
return rtn, err
}
if rtn.ScreenId == "" && (rtype&R_Screen) > 0 {
return rtn, fmt.Errorf("no screen")
}
if rtype&R_Screen > 0 && rtn.ScreenId == "" {
return rtn, fmt.Errorf("no screen")
}
if (rtype&R_Remote)+(rtype&R_RemoteOpt) > 0 {
rname, rptr, state, rstate, err := resolveRemote(ctx, pk.Kwargs["remote"], rtn.SessionId, rtn.WindowId)
if err != nil {
return rtn, err
if rtype&R_Window > 0 && rtn.WindowId == "" {
return rtn, fmt.Errorf("no window")
}
if rtype&R_Remote > 0 && rtn.Remote == nil {
return rtn, fmt.Errorf("no remote")
}
if rtype&R_RemoteConnected > 0 {
if !rtn.Remote.RState.IsConnected() {
return rtn, fmt.Errorf("remote '%s' is not connected", rtn.Remote.DisplayName)
}
if rptr == nil && (rtype&R_Remote) > 0 {
return rtn, fmt.Errorf("no remote")
if rtn.Remote.RemoteState == nil {
return rtn, fmt.Errorf("remote '%s' state is not available", rtn.Remote.DisplayName)
}
rtn.RemoteDisplayName = rname
rtn.RemotePtr = *rptr
rtn.RemoteState = state
rtn.RState = *rstate
}
return rtn, nil
}
@ -281,8 +276,34 @@ func parseFullRemoteRef(fullRemoteRef string) (string, string, string, error) {
return fields[0], fields[1], fields[2], nil
}
func resolveRemoteFromPtr(ctx context.Context, rptr *sstore.RemotePtrType, sessionId string, windowId string) (*ResolvedRemote, error) {
if rptr == nil || rptr.RemoteId == "" {
return nil, fmt.Errorf("no remote to resolve")
}
msh := remote.GetRemoteById(rptr.RemoteId)
if msh == nil {
return nil, fmt.Errorf("invalid remote '%s', not found", rptr.RemoteId)
}
rstate := msh.GetRemoteRuntimeState()
displayName := rstate.GetDisplayName(rptr)
state, err := sstore.GetRemoteState(ctx, sessionId, windowId, *rptr)
if err != nil {
return nil, fmt.Errorf("cannot resolve remote state '%s': %w", displayName, err)
}
if state == nil {
state = rstate.DefaultState
}
return &ResolvedRemote{
DisplayName: displayName,
RemotePtr: *rptr,
RemoteState: state,
RState: rstate,
MShell: msh,
}, nil
}
// returns (remoteDisplayName, remoteptr, state, rstate, err)
func resolveRemote(ctx context.Context, fullRemoteRef string, sessionId string, windowId string) (string, *sstore.RemotePtrType, *sstore.RemoteState, *remote.RemoteState, error) {
func resolveRemote(ctx context.Context, fullRemoteRef string, sessionId string, windowId string) (string, *sstore.RemotePtrType, *sstore.RemoteState, *remote.RemoteRuntimeState, error) {
if fullRemoteRef == "" {
return "", nil, nil, nil, nil
}

View File

@ -163,6 +163,7 @@ func EvalMetaCommand(ctx context.Context, origPk *scpacket.FeCommandPacketType)
rtnPk.MetaCmd = metaCmd
rtnPk.MetaSubCmd = metaSubCmd
rtnPk.Kwargs = make(map[string]string)
rtnPk.UIContext = origPk.UIContext
for key, val := range origPk.Kwargs {
rtnPk.Kwargs[key] = val
}

View File

@ -55,7 +55,7 @@ type Store struct {
Map map[string]*MShellProc // key=remoteid
}
type RemoteState struct {
type RemoteRuntimeState struct {
RemoteType string `json:"remotetype"`
RemoteId string `json:"remoteid"`
PhysicalId string `json:"physicalremoteid"`
@ -68,10 +68,31 @@ type RemoteState struct {
ConnectMode string `json:"connectmode"`
}
func (state RemoteState) IsConnected() bool {
func (state RemoteRuntimeState) IsConnected() bool {
return state.Status == StatusConnected
}
func (state RemoteRuntimeState) GetBaseDisplayName() string {
if state.RemoteAlias != "" {
return state.RemoteAlias
}
return state.RemoteCanonicalName
}
func (state RemoteRuntimeState) GetDisplayName(rptr *sstore.RemotePtrType) string {
name := state.GetBaseDisplayName()
if rptr == nil {
return name
}
if rptr.Name != "" {
name = name + ":" + rptr.Name
}
if rptr.OwnerId != "" {
name = "@" + rptr.OwnerId + ":" + name
}
return name
}
type MShellProc struct {
Lock *sync.Mutex
Remote *sstore.RemoteType
@ -122,7 +143,7 @@ func GetRemoteById(remoteId string) *MShellProc {
return GlobalStore.Map[remoteId]
}
func ResolveRemoteRef(remoteRef string) *RemoteState {
func ResolveRemoteRef(remoteRef string) *RemoteRuntimeState {
GlobalStore.Lock.Lock()
defer GlobalStore.Lock.Unlock()
@ -130,14 +151,14 @@ func ResolveRemoteRef(remoteRef string) *RemoteState {
if err == nil {
msh := GlobalStore.Map[remoteRef]
if msh != nil {
state := msh.GetRemoteState()
state := msh.GetRemoteRuntimeState()
return &state
}
return nil
}
for _, msh := range GlobalStore.Map {
if msh.Remote.RemoteAlias == remoteRef || msh.Remote.RemoteCanonicalName == remoteRef {
state := msh.GetRemoteState()
state := msh.GetRemoteRuntimeState()
return &state
}
}
@ -188,10 +209,10 @@ func makeShortHost(host string) string {
return host[0:dotIdx]
}
func (proc *MShellProc) GetRemoteState() RemoteState {
func (proc *MShellProc) GetRemoteRuntimeState() RemoteRuntimeState {
proc.Lock.Lock()
defer proc.Lock.Unlock()
state := RemoteState{
state := RemoteRuntimeState{
RemoteType: proc.Remote.RemoteType,
RemoteId: proc.Remote.RemoteId,
RemoteAlias: proc.Remote.RemoteAlias,
@ -251,18 +272,18 @@ func (proc *MShellProc) GetRemoteState() RemoteState {
}
func (msh *MShellProc) NotifyUpdate() {
rstate := msh.GetRemoteState()
rstate := msh.GetRemoteRuntimeState()
update := &sstore.ModelUpdate{Remote: rstate}
sstore.MainBus.SendUpdate("", update)
}
func GetAllRemoteState() []RemoteState {
func GetAllRemoteRuntimeState() []RemoteRuntimeState {
GlobalStore.Lock.Lock()
defer GlobalStore.Lock.Unlock()
var rtn []RemoteState
var rtn []RemoteRuntimeState
for _, proc := range GlobalStore.Map {
state := proc.GetRemoteState()
state := proc.GetRemoteRuntimeState()
rtn = append(rtn, state)
}
return rtn
@ -427,7 +448,7 @@ func replaceHomePath(pathStr string, homeDir string) string {
return pathStr
}
func (state RemoteState) ExpandHomeDir(pathStr string) (string, error) {
func (state RemoteRuntimeState) ExpandHomeDir(pathStr string) (string, error) {
if pathStr != "~" && !strings.HasPrefix(pathStr, "~/") {
return pathStr, nil
}
@ -484,7 +505,6 @@ func RunCommand(ctx context.Context, cmdId string, remotePtr sstore.RemotePtrTyp
if remoteState == nil {
return nil, fmt.Errorf("no remote state passed to RunCommand")
}
fmt.Printf("RUN-CMD> %s reqid=%s (msh=%v)\n", runPacket.CK, runPacket.ReqId, msh.Remote)
msh.ServerProc.Output.RegisterRpc(runPacket.ReqId)
err := shexec.SendRunPacketAndRunData(ctx, msh.ServerProc.Input, runPacket)
if err != nil {

View File

@ -18,6 +18,14 @@ type FeCommandPacketType struct {
MetaSubCmd string `json:"metasubcmd,omitempty"`
Args []string `json:"args,omitempty"`
Kwargs map[string]string `json:"kwargs,omitempty"`
UIContext *UIContextType `json:"uicontext,omitempty"`
}
type UIContextType struct {
SessionId string `json:"sessionid"`
ScreenId string `json:"screenid"`
WindowId string `json:"windowid"`
Remote *sstore.RemotePtrType `json:"remote,omitempty"`
}
type FeInputPacketType struct {

View File

@ -334,6 +334,19 @@ func InsertSessionWithName(ctx context.Context, sessionName string, activate boo
return update, nil
}
func SetActiveSessionId(ctx context.Context, sessionId string) error {
txErr := WithTx(ctx, func(tx *TxWrap) error {
query := `SELECT sessionid FROM session WHERE sessionid = ?`
if !tx.Exists(query, sessionId) {
return fmt.Errorf("cannot switch to session, not found")
}
query = `UPDATE client SET activesessionid = ?`
tx.ExecWrap(query, sessionId)
return nil
})
return txErr
}
func containsStr(strs []string, testStr string) bool {
for _, s := range strs {
if s == testStr {

View File

@ -24,14 +24,15 @@ func (PtyDataUpdate) UpdateType() string {
}
type ModelUpdate struct {
Sessions []*SessionType `json:"sessions,omitempty"`
ActiveSessionId string `json:"activesessionid,omitempty"`
Window *WindowType `json:"window,omitempty"`
Line *LineType `json:"line,omitempty"`
Cmd *CmdType `json:"cmd,omitempty"`
CmdLine *CmdLineType `json:"cmdline,omitempty"`
Info *InfoMsgType `json:"info,omitempty"`
Remote interface{} `json:"remote,omitempty"` // *remote.RemoteState
Sessions []*SessionType `json:"sessions,omitempty"`
ActiveSessionId string `json:"activesessionid,omitempty"`
Window *WindowType `json:"window,omitempty"`
Line *LineType `json:"line,omitempty"`
Cmd *CmdType `json:"cmd,omitempty"`
CmdLine *CmdLineType `json:"cmdline,omitempty"`
Info *InfoMsgType `json:"info,omitempty"`
Remote interface{} `json:"remote,omitempty"` // *remote.RemoteState
History *HistoryInfoType `json:"history,omitempty"`
}
func (ModelUpdate) UpdateType() string {
@ -74,6 +75,10 @@ type InfoMsgType struct {
TimeoutMs int64 `json:"timeoutms,omitempty"`
}
type HistoryInfoType struct {
Items []*HistoryItemType `json:"items"`
}
type CmdLineType struct {
InsertChars string `json:"insertchars"`
InsertPos int64 `json:"insertpos"`