mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-03 18:47:56 +01:00
big updates to remoteinstance, push changes through stack
This commit is contained in:
parent
51f7b0798b
commit
4f686e891b
@ -18,7 +18,9 @@ CREATE TABLE session (
|
||||
CREATE TABLE window (
|
||||
sessionid varchar(36) NOT NULL,
|
||||
windowid varchar(36) NOT NULL,
|
||||
curremote varchar(50) NOT NULL,
|
||||
curremoteowneruserid varchar(36) NOT NULL,
|
||||
curremoteid varchar(36) NOT NULL,
|
||||
curremotename varchar(50) NOT NULL,
|
||||
winopts json NOT NULL,
|
||||
owneruserid varchar(36) NOT NULL,
|
||||
sharemode varchar(12) NOT NULL,
|
||||
@ -52,8 +54,8 @@ CREATE TABLE remote_instance (
|
||||
name varchar(50) NOT NULL,
|
||||
sessionid varchar(36) NOT NULL,
|
||||
windowid varchar(36) NOT NULL,
|
||||
remoteowneruserid varchar(36) NOT NULL,
|
||||
remoteid varchar(36) NOT NULL,
|
||||
sessionscope boolean NOT NULL,
|
||||
state json NOT NULL
|
||||
);
|
||||
|
||||
@ -98,7 +100,6 @@ CREATE TABLE cmd (
|
||||
donepk json NOT NULL,
|
||||
runout json NOT NULL,
|
||||
usedrows int NOT NULL,
|
||||
prompt text NOT NULL,
|
||||
PRIMARY KEY (sessionid, cmdid)
|
||||
);
|
||||
|
||||
|
@ -18,7 +18,9 @@ CREATE TABLE session (
|
||||
CREATE TABLE window (
|
||||
sessionid varchar(36) NOT NULL,
|
||||
windowid varchar(36) NOT NULL,
|
||||
curremote varchar(50) NOT NULL,
|
||||
curremoteowneruserid varchar(36) NOT NULL,
|
||||
curremoteid varchar(36) NOT NULL,
|
||||
curremotename varchar(50) NOT NULL,
|
||||
winopts json NOT NULL,
|
||||
owneruserid varchar(36) NOT NULL,
|
||||
sharemode varchar(12) NOT NULL,
|
||||
@ -49,8 +51,8 @@ CREATE TABLE remote_instance (
|
||||
name varchar(50) NOT NULL,
|
||||
sessionid varchar(36) NOT NULL,
|
||||
windowid varchar(36) NOT NULL,
|
||||
remoteowneruserid varchar(36) NOT NULL,
|
||||
remoteid varchar(36) NOT NULL,
|
||||
sessionscope boolean NOT NULL,
|
||||
state json NOT NULL
|
||||
);
|
||||
CREATE TABLE line (
|
||||
@ -92,7 +94,6 @@ CREATE TABLE cmd (
|
||||
donepk json NOT NULL,
|
||||
runout json NOT NULL,
|
||||
usedrows int NOT NULL,
|
||||
prompt text NOT NULL,
|
||||
PRIMARY KEY (sessionid, cmdid)
|
||||
);
|
||||
CREATE TABLE history (
|
||||
|
@ -39,9 +39,9 @@ type resolvedIds struct {
|
||||
SessionId string
|
||||
ScreenId string
|
||||
WindowId string
|
||||
RemoteId string
|
||||
RemoteName string
|
||||
RemotePtr sstore.RemotePtrType
|
||||
RemoteState *sstore.RemoteState
|
||||
RemoteDisplayName string
|
||||
}
|
||||
|
||||
func SubMetaCmd(cmd string) string {
|
||||
@ -208,22 +208,59 @@ func resolveScreenId(ctx context.Context, pk *scpacket.FeCommandPacketType, sess
|
||||
return resolveSessionScreen(ctx, sessionId, screenArg)
|
||||
}
|
||||
|
||||
// returns (remoteName, remoteId, state, err)
|
||||
func resolveRemote(ctx context.Context, remoteName string, sessionId string, windowId string) (string, string, *sstore.RemoteState, error) {
|
||||
if remoteName == "" {
|
||||
return "", "", nil, nil
|
||||
// returns (remoteuserref, remoteref, name, error)
|
||||
func parseFullRemoteRef(fullRemoteRef string) (string, string, string, error) {
|
||||
if strings.HasPrefix(fullRemoteRef, "[") && strings.HasSuffix(fullRemoteRef, "]") {
|
||||
fullRemoteRef = fullRemoteRef[1 : len(fullRemoteRef)-1]
|
||||
}
|
||||
remoteId, state, err := sstore.GetRemoteState(ctx, remoteName, sessionId, windowId)
|
||||
fields := strings.Split(fullRemoteRef, ":")
|
||||
if len(fields) > 3 {
|
||||
return "", "", "", fmt.Errorf("invalid remote format '%s'", fullRemoteRef)
|
||||
}
|
||||
if len(fields) == 1 {
|
||||
return "", fields[0], "", nil
|
||||
}
|
||||
if len(fields) == 2 {
|
||||
if strings.HasPrefix(fields[0], "@") {
|
||||
return fields[0], fields[1], "", nil
|
||||
}
|
||||
return "", fields[0], fields[1], nil
|
||||
}
|
||||
return fields[0], fields[1], fields[2], nil
|
||||
}
|
||||
|
||||
// returns (remoteDisplayName, remoteptr, state, err)
|
||||
func resolveRemote(ctx context.Context, fullRemoteRef string, sessionId string, windowId string) (string, *sstore.RemotePtrType, *sstore.RemoteState, error) {
|
||||
if fullRemoteRef == "" {
|
||||
return "", nil, nil, nil
|
||||
}
|
||||
userRef, remoteRef, remoteName, err := parseFullRemoteRef(fullRemoteRef)
|
||||
if err != nil {
|
||||
return "", "", nil, fmt.Errorf("cannot resolve remote '%s': %w", remoteName, err)
|
||||
return "", nil, nil, err
|
||||
}
|
||||
if userRef != "" {
|
||||
return "", nil, nil, fmt.Errorf("invalid remote '%s', cannot resolve remote userid '%s'", fullRemoteRef, userRef)
|
||||
}
|
||||
rstate := remote.ResolveRemoteRef(remoteRef)
|
||||
if rstate == nil {
|
||||
return "", nil, nil, fmt.Errorf("cannot resolve remote '%s': not found", fullRemoteRef)
|
||||
}
|
||||
rptr := sstore.RemotePtrType{RemoteId: rstate.RemoteId, Name: remoteName}
|
||||
state, err := sstore.GetRemoteState(ctx, sessionId, windowId, rptr)
|
||||
if err != nil {
|
||||
return "", nil, nil, fmt.Errorf("cannot resolve remote state '%s': %w", fullRemoteRef, err)
|
||||
}
|
||||
rname := rstate.RemoteCanonicalName
|
||||
if rstate.RemoteAlias != "" {
|
||||
rname = rstate.RemoteAlias
|
||||
}
|
||||
if rptr.Name != "" {
|
||||
rname = fmt.Sprintf("%s:%s", rname, rptr.Name)
|
||||
}
|
||||
if state == nil {
|
||||
state, err = remote.GetDefaultRemoteStateById(remoteId)
|
||||
if err != nil {
|
||||
return "", "", nil, fmt.Errorf("cannot resolve remote '%s': %w", remoteName, err)
|
||||
return rname, &rptr, rstate.DefaultState, nil
|
||||
}
|
||||
}
|
||||
return remoteName, remoteId, state, nil
|
||||
return rname, &rptr, state, nil
|
||||
}
|
||||
|
||||
func resolveIds(ctx context.Context, pk *scpacket.FeCommandPacketType, rtype int) (resolvedIds, error) {
|
||||
@ -261,13 +298,16 @@ func resolveIds(ctx context.Context, pk *scpacket.FeCommandPacketType, rtype int
|
||||
}
|
||||
}
|
||||
if (rtype&R_Remote)+(rtype&R_RemoteOpt) > 0 {
|
||||
rtn.RemoteName, rtn.RemoteId, rtn.RemoteState, err = resolveRemote(ctx, pk.Kwargs["remote"], rtn.SessionId, rtn.WindowId)
|
||||
rname, rptr, rstate, err := resolveRemote(ctx, pk.Kwargs["remote"], rtn.SessionId, rtn.WindowId)
|
||||
if err != nil {
|
||||
return rtn, err
|
||||
}
|
||||
if rtn.RemoteId == "" && (rtype&R_Remote) > 0 {
|
||||
if rptr == nil && (rtype&R_Remote) > 0 {
|
||||
return rtn, fmt.Errorf("no remote")
|
||||
}
|
||||
rtn.RemoteDisplayName = rname
|
||||
rtn.RemotePtr = *rptr
|
||||
rtn.RemoteState = rstate
|
||||
}
|
||||
return rtn, nil
|
||||
}
|
||||
@ -289,7 +329,7 @@ func RunCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.U
|
||||
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.RemoteId, ids.RemoteState, runPacket)
|
||||
cmd, err := remote.RunCommand(ctx, cmdId, ids.RemotePtr.RemoteId, ids.RemoteState, runPacket)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -297,7 +337,7 @@ func RunCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.U
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sstore.LineUpdate{Line: rtnLine, Cmd: cmd}, nil
|
||||
return sstore.ModelUpdate{Line: rtnLine, Cmd: cmd}, nil
|
||||
}
|
||||
|
||||
func addToHistory(ctx context.Context, pk *scpacket.FeCommandPacketType, update sstore.UpdatePacket, hadError bool) error {
|
||||
@ -467,7 +507,7 @@ func UnSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
curRemote := remote.GetRemoteById(ids.RemoteId)
|
||||
curRemote := remote.GetRemoteById(ids.RemotePtr.RemoteId)
|
||||
if curRemote == nil {
|
||||
return nil, fmt.Errorf("invalid remote, cannot unset")
|
||||
}
|
||||
@ -489,18 +529,14 @@ func UnSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore
|
||||
}
|
||||
state := *ids.RemoteState
|
||||
state.Env0 = shexec.MakeEnv0(envMap)
|
||||
remote, err := sstore.UpdateRemoteState(ctx, ids.RemoteName, ids.SessionId, ids.WindowId, ids.RemoteId, state)
|
||||
remote, err := sstore.UpdateRemoteState(ctx, ids.SessionId, ids.WindowId, ids.RemotePtr, state)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
update := sstore.WindowUpdate{
|
||||
Window: sstore.WindowType{
|
||||
SessionId: ids.SessionId,
|
||||
WindowId: ids.WindowId,
|
||||
Remotes: []*sstore.RemoteInstance{remote},
|
||||
},
|
||||
update := sstore.ModelUpdate{
|
||||
Sessions: sstore.MakeSessionsUpdateForRemote(ids.SessionId, remote),
|
||||
Info: &sstore.InfoMsgType{
|
||||
InfoMsg: fmt.Sprintf("[%s] unset vars: %s", ids.RemoteName, makeSetVarsStr(unsetVars)),
|
||||
InfoMsg: fmt.Sprintf("[%s] unset vars: %s", ids.RemoteDisplayName, makeSetVarsStr(unsetVars)),
|
||||
TimeoutMs: 2000,
|
||||
},
|
||||
}
|
||||
@ -513,9 +549,9 @@ func RemoteCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstor
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
curRemote := remote.GetRemoteById(ids.RemoteId)
|
||||
curRemote := remote.GetRemoteById(ids.RemotePtr.RemoteId)
|
||||
if curRemote == nil {
|
||||
return nil, fmt.Errorf("invalid remote [%s] (not found)", ids.RemoteName)
|
||||
return nil, fmt.Errorf("invalid remote '%s' (not found)", ids.RemoteDisplayName)
|
||||
}
|
||||
state := curRemote.GetRemoteState()
|
||||
var buf bytes.Buffer
|
||||
@ -530,9 +566,9 @@ func RemoteCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstor
|
||||
buf.WriteString(fmt.Sprintf(" %-15s %s\n", "cwd", ids.RemoteState.Cwd))
|
||||
}
|
||||
output := buf.String()
|
||||
return sstore.InfoUpdate{
|
||||
return sstore.ModelUpdate{
|
||||
Info: &sstore.InfoMsgType{
|
||||
InfoTitle: fmt.Sprintf("show remote '%s' info", ids.RemoteName),
|
||||
InfoTitle: fmt.Sprintf("show remote '%s' info", ids.RemoteDisplayName),
|
||||
InfoLines: splitLinesForInfo(output),
|
||||
},
|
||||
}, nil
|
||||
@ -559,7 +595,7 @@ func SetEnvCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstor
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
curRemote := remote.GetRemoteById(ids.RemoteId)
|
||||
curRemote := remote.GetRemoteById(ids.RemotePtr.RemoteId)
|
||||
if curRemote == nil {
|
||||
return nil, fmt.Errorf("invalid remote, cannot setenv")
|
||||
}
|
||||
@ -576,9 +612,9 @@ func SetEnvCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstor
|
||||
line := fmt.Sprintf("%s=%s", varName, shellescape.Quote(varVal))
|
||||
infoLines = append(infoLines, line)
|
||||
}
|
||||
update := sstore.InfoUpdate{
|
||||
update := sstore.ModelUpdate{
|
||||
Info: &sstore.InfoMsgType{
|
||||
InfoTitle: fmt.Sprintf("environment for [%s] remote", ids.RemoteName),
|
||||
InfoTitle: fmt.Sprintf("environment for [%s] remote", ids.RemoteDisplayName),
|
||||
InfoLines: infoLines,
|
||||
},
|
||||
}
|
||||
@ -597,18 +633,14 @@ func SetEnvCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstor
|
||||
}
|
||||
state := *ids.RemoteState
|
||||
state.Env0 = shexec.MakeEnv0(envMap)
|
||||
remote, err := sstore.UpdateRemoteState(ctx, ids.RemoteName, ids.SessionId, ids.WindowId, ids.RemoteId, state)
|
||||
remote, err := sstore.UpdateRemoteState(ctx, ids.SessionId, ids.WindowId, ids.RemotePtr, state)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
update := sstore.WindowUpdate{
|
||||
Window: sstore.WindowType{
|
||||
SessionId: ids.SessionId,
|
||||
WindowId: ids.WindowId,
|
||||
Remotes: []*sstore.RemoteInstance{remote},
|
||||
},
|
||||
update := sstore.ModelUpdate{
|
||||
Sessions: sstore.MakeSessionsUpdateForRemote(ids.SessionId, remote),
|
||||
Info: &sstore.InfoMsgType{
|
||||
InfoMsg: fmt.Sprintf("[%s] set vars: %s", ids.RemoteName, makeSetVarsStr(setVars)),
|
||||
InfoMsg: fmt.Sprintf("[%s] set vars: %s", ids.RemoteDisplayName, makeSetVarsStr(setVars)),
|
||||
TimeoutMs: 2000,
|
||||
},
|
||||
}
|
||||
@ -624,23 +656,22 @@ func CrCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.Up
|
||||
if newRemote == "" {
|
||||
return nil, nil
|
||||
}
|
||||
remoteName, remoteId, _, err := resolveRemote(ctx, newRemote, ids.SessionId, ids.WindowId)
|
||||
fmt.Printf("found: name[%s] id[%s] err[%v]\n", remoteName, remoteId, err)
|
||||
remoteName, rptr, _, err := resolveRemote(ctx, newRemote, ids.SessionId, ids.WindowId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if remoteId == "" {
|
||||
return nil, fmt.Errorf("/cr error: remote not found")
|
||||
if rptr == nil {
|
||||
return nil, fmt.Errorf("/cr error: remote '%s' not found", newRemote)
|
||||
}
|
||||
err = sstore.UpdateCurRemote(ctx, ids.SessionId, ids.WindowId, remoteName)
|
||||
err = sstore.UpdateCurRemote(ctx, ids.SessionId, ids.WindowId, *rptr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("/cr error: cannot update curremote: %w", err)
|
||||
}
|
||||
update := sstore.WindowUpdate{
|
||||
update := sstore.ModelUpdate{
|
||||
Window: sstore.WindowType{
|
||||
SessionId: ids.SessionId,
|
||||
WindowId: ids.WindowId,
|
||||
CurRemote: remoteName,
|
||||
CurRemote: *rptr,
|
||||
},
|
||||
Info: &sstore.InfoMsgType{
|
||||
InfoMsg: fmt.Sprintf("current remote = %s", remoteName),
|
||||
@ -656,7 +687,7 @@ func CdCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.Up
|
||||
return nil, fmt.Errorf("/cd error: %w", err)
|
||||
}
|
||||
newDir := firstArg(pk)
|
||||
curRemote := remote.GetRemoteById(ids.RemoteId)
|
||||
curRemote := remote.GetRemoteById(ids.RemotePtr.RemoteId)
|
||||
if curRemote == nil {
|
||||
return nil, fmt.Errorf("invalid remote, cannot change directory")
|
||||
}
|
||||
@ -667,9 +698,9 @@ func CdCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.Up
|
||||
return nil, fmt.Errorf("remote state is not available")
|
||||
}
|
||||
if newDir == "" {
|
||||
return sstore.InfoUpdate{
|
||||
return sstore.ModelUpdate{
|
||||
Info: &sstore.InfoMsgType{
|
||||
InfoMsg: fmt.Sprintf("[%s] current directory = %s", ids.RemoteName, ids.RemoteState.Cwd),
|
||||
InfoMsg: fmt.Sprintf("[%s] current directory = %s", ids.RemoteDisplayName, ids.RemoteState.Cwd),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
@ -699,18 +730,14 @@ func CdCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.Up
|
||||
}
|
||||
state := *ids.RemoteState
|
||||
state.Cwd = newDir
|
||||
remote, err := sstore.UpdateRemoteState(ctx, ids.RemoteName, ids.SessionId, ids.WindowId, ids.RemoteId, state)
|
||||
remote, err := sstore.UpdateRemoteState(ctx, ids.SessionId, ids.WindowId, ids.RemotePtr, state)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
update := sstore.WindowUpdate{
|
||||
Window: sstore.WindowType{
|
||||
SessionId: ids.SessionId,
|
||||
WindowId: ids.WindowId,
|
||||
Remotes: []*sstore.RemoteInstance{remote},
|
||||
},
|
||||
update := sstore.ModelUpdate{
|
||||
Sessions: sstore.MakeSessionsUpdateForRemote(ids.SessionId, remote),
|
||||
Info: &sstore.InfoMsgType{
|
||||
InfoMsg: fmt.Sprintf("[%s] current directory = %s", ids.RemoteName, newDir),
|
||||
InfoMsg: fmt.Sprintf("[%s] current directory = %s", ids.RemoteDisplayName, newDir),
|
||||
TimeoutMs: 2000,
|
||||
},
|
||||
}
|
||||
@ -778,7 +805,7 @@ func makeInfoFromComps(compType string, comps []string, hasMore bool) sstore.Upd
|
||||
if len(comps) == 0 {
|
||||
comps = []string{"(no completions)"}
|
||||
}
|
||||
update := sstore.InfoUpdate{
|
||||
update := sstore.ModelUpdate{
|
||||
Info: &sstore.InfoMsgType{
|
||||
InfoTitle: fmt.Sprintf("%s completions", compType),
|
||||
InfoComps: comps,
|
||||
@ -798,7 +825,7 @@ func makeInsertUpdateFromComps(pos int64, prefix string, comps []string, hasMore
|
||||
}
|
||||
insertChars := lcp[len(prefix):]
|
||||
clu := &sstore.CmdLineType{InsertChars: insertChars, InsertPos: pos}
|
||||
return sstore.InfoUpdate{CmdLine: clu}
|
||||
return sstore.ModelUpdate{CmdLine: clu}
|
||||
}
|
||||
|
||||
func longestPrefix(root string, comps []string) string {
|
||||
@ -864,7 +891,7 @@ func doCompGen(ctx context.Context, ids resolvedIds, prefix string, compType str
|
||||
return nil, false, fmt.Errorf("/compgen invalid remote state")
|
||||
}
|
||||
cgPacket.Cwd = ids.RemoteState.Cwd
|
||||
curRemote := remote.GetRemoteById(ids.RemoteId)
|
||||
curRemote := remote.GetRemoteById(ids.RemotePtr.RemoteId)
|
||||
if curRemote == nil {
|
||||
return nil, false, fmt.Errorf("invalid remote, cannot execute command")
|
||||
}
|
||||
@ -938,7 +965,7 @@ func CommentCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (ssto
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sstore.LineUpdate{Line: rtnLine}, nil
|
||||
return sstore.ModelUpdate{Line: rtnLine}, nil
|
||||
}
|
||||
|
||||
func SessionCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
|
||||
@ -961,7 +988,7 @@ func SessionCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (ssto
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sstore.SessionUpdate{ActiveSessionId: sessionId}, nil
|
||||
return sstore.ModelUpdate{ActiveSessionId: sessionId}, nil
|
||||
}
|
||||
|
||||
func splitLinesForInfo(str string) []string {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package remote
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
@ -16,6 +17,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/creack/pty"
|
||||
"github.com/google/uuid"
|
||||
"github.com/scripthaus-dev/mshell/pkg/base"
|
||||
"github.com/scripthaus-dev/mshell/pkg/packet"
|
||||
"github.com/scripthaus-dev/mshell/pkg/shexec"
|
||||
@ -116,6 +118,28 @@ func GetRemoteById(remoteId string) *MShellProc {
|
||||
return GlobalStore.Map[remoteId]
|
||||
}
|
||||
|
||||
func ResolveRemoteRef(remoteRef string) *RemoteState {
|
||||
GlobalStore.Lock.Lock()
|
||||
defer GlobalStore.Lock.Unlock()
|
||||
|
||||
_, err := uuid.Parse(remoteRef)
|
||||
if err == nil {
|
||||
msh := GlobalStore.Map[remoteRef]
|
||||
if msh != nil {
|
||||
state := msh.GetRemoteState()
|
||||
return &state
|
||||
}
|
||||
return nil
|
||||
}
|
||||
for _, msh := range GlobalStore.Map {
|
||||
if msh.Remote.RemoteAlias == remoteRef || msh.Remote.RemoteCanonicalName == remoteRef {
|
||||
state := msh.GetRemoteState()
|
||||
return &state
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func unquoteDQBashString(str string) (string, bool) {
|
||||
if len(str) < 2 {
|
||||
return str, false
|
||||
@ -175,19 +199,24 @@ func (proc *MShellProc) GetRemoteState() RemoteState {
|
||||
if proc.Err != nil {
|
||||
state.ErrorStr = proc.Err.Error()
|
||||
}
|
||||
local := (proc.Remote.SSHOpts == nil || proc.Remote.SSHOpts.Local)
|
||||
vars := make(map[string]string)
|
||||
vars["user"] = proc.Remote.RemoteUser
|
||||
vars["bestuser"] = vars["user"]
|
||||
vars["host"] = proc.Remote.RemoteHost
|
||||
vars["shorthost"] = makeShortHost(proc.Remote.RemoteHost)
|
||||
if proc.Remote.RemoteSudo {
|
||||
vars["sudo"] = "1"
|
||||
}
|
||||
vars["alias"] = proc.Remote.RemoteAlias
|
||||
vars["cname"] = proc.Remote.RemoteCanonicalName
|
||||
vars["physicalid"] = proc.Remote.PhysicalId
|
||||
vars["remoteid"] = proc.Remote.RemoteId
|
||||
vars["status"] = proc.Status
|
||||
vars["type"] = proc.Remote.RemoteType
|
||||
if proc.Remote.RemoteSudo {
|
||||
vars["sudo"] = "1"
|
||||
}
|
||||
if local {
|
||||
vars["local"] = "1"
|
||||
}
|
||||
if proc.ServerProc != nil && proc.ServerProc.InitPk != nil {
|
||||
state.DefaultState = &sstore.RemoteState{
|
||||
Cwd: proc.ServerProc.InitPk.Cwd,
|
||||
@ -195,11 +224,23 @@ func (proc *MShellProc) GetRemoteState() RemoteState {
|
||||
}
|
||||
vars["home"] = proc.ServerProc.InitPk.HomeDir
|
||||
vars["remoteuser"] = proc.ServerProc.InitPk.User
|
||||
vars["bestuser"] = vars["remoteuser"]
|
||||
vars["remotehost"] = proc.ServerProc.InitPk.HostName
|
||||
vars["remoteshorthost"] = makeShortHost(proc.ServerProc.InitPk.HostName)
|
||||
if proc.Remote.SSHOpts == nil || proc.Remote.SSHOpts.SSHHost == "" {
|
||||
vars["local"] = "1"
|
||||
vars["besthost"] = vars["remotehost"]
|
||||
vars["bestshorthost"] = vars["remoteshorthost"]
|
||||
}
|
||||
if local && proc.Remote.RemoteSudo {
|
||||
vars["bestuser"] = "sudo"
|
||||
} else if proc.Remote.RemoteSudo {
|
||||
vars["bestuser"] = "sudo@" + vars["bestuser"]
|
||||
}
|
||||
if local {
|
||||
vars["bestname"] = vars["bestuser"] + "@local"
|
||||
vars["bestshortname"] = vars["bestuser"] + "@local"
|
||||
} else {
|
||||
vars["bestname"] = vars["bestuser"] + "@" + vars["besthost"]
|
||||
vars["bestshortname"] = vars["bestuser"] + "@" + vars["bestshorthost"]
|
||||
}
|
||||
state.RemoteVars = vars
|
||||
return state
|
||||
@ -238,8 +279,8 @@ func MakeMShell(r *sstore.RemoteType) *MShellProc {
|
||||
}
|
||||
|
||||
func convertSSHOpts(opts *sstore.SSHOpts) shexec.SSHOpts {
|
||||
if opts == nil {
|
||||
return shexec.SSHOpts{}
|
||||
if opts == nil || opts.Local {
|
||||
opts = &sstore.SSHOpts{}
|
||||
}
|
||||
return shexec.SSHOpts{
|
||||
SSHHost: opts.SSHHost,
|
||||
@ -347,6 +388,19 @@ func (msh *MShellProc) GetDefaultState() *sstore.RemoteState {
|
||||
return &sstore.RemoteState{Cwd: msh.ServerProc.InitPk.HomeDir, Env0: msh.ServerProc.InitPk.Env0}
|
||||
}
|
||||
|
||||
func replaceHomePath(pathStr string, homeDir string) string {
|
||||
if homeDir == "" {
|
||||
return pathStr
|
||||
}
|
||||
if pathStr == homeDir {
|
||||
return "~"
|
||||
}
|
||||
if strings.HasPrefix(pathStr, homeDir+"/") {
|
||||
return "~" + pathStr[len(homeDir):]
|
||||
}
|
||||
return pathStr
|
||||
}
|
||||
|
||||
func (msh *MShellProc) ExpandHomeDir(pathStr string) (string, error) {
|
||||
if pathStr != "~" && !strings.HasPrefix(pathStr, "~/") {
|
||||
return pathStr, nil
|
||||
@ -526,7 +580,7 @@ func (msh *MShellProc) notifyHangups_nolock() {
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
update := sstore.LineUpdate{Cmd: cmd}
|
||||
update := sstore.ModelUpdate{Cmd: cmd}
|
||||
sstore.MainBus.SendUpdate(ck.GetSessionId(), update)
|
||||
}
|
||||
msh.RunningCmds = nil
|
||||
@ -602,16 +656,79 @@ func (runner *MShellProc) ProcessPackets() {
|
||||
}
|
||||
}
|
||||
|
||||
func EvalPromptEsc(escCode string, vars map[string]string, state sstore.RemoteState) string {
|
||||
if escCode == "d" {
|
||||
now := time.Now()
|
||||
return now.Format("Mon Jan 02")
|
||||
// returns number of chars (including braces) for brace-expr
|
||||
func getBracedStr(runeStr []rune) int {
|
||||
if len(runeStr) < 3 {
|
||||
return 0
|
||||
}
|
||||
if runeStr[0] != '{' {
|
||||
return 0
|
||||
}
|
||||
for i := 1; i < len(runeStr); i++ {
|
||||
if runeStr[i] == '}' {
|
||||
if i == 1 { // cannot have {}
|
||||
return 0
|
||||
}
|
||||
return i + 1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func isDigit(r rune) bool {
|
||||
return r >= '0' && r <= '9' // just check ascii digits (not unicode)
|
||||
}
|
||||
|
||||
func EvalPrompt(promptFmt string, vars map[string]string, state *sstore.RemoteState) string {
|
||||
var buf bytes.Buffer
|
||||
promptRunes := []rune(promptFmt)
|
||||
for i := 0; i < len(promptRunes); i++ {
|
||||
ch := promptRunes[i]
|
||||
if ch == '\\' && i != len(promptRunes)-1 {
|
||||
nextCh := promptRunes[i+1]
|
||||
if nextCh == 'x' || nextCh == 'y' {
|
||||
nr := getBracedStr(promptRunes[i+2:])
|
||||
if nr > 0 {
|
||||
escCode := string(promptRunes[i+1 : i+1+nr+1]) // start at "x" or "y", extend nr+1 runes
|
||||
escStr := evalPromptEsc(escCode, vars, state)
|
||||
buf.WriteString(escStr)
|
||||
i += nr + 1
|
||||
continue
|
||||
} else {
|
||||
buf.WriteRune(ch) // invalid escape, so just write ch and move on
|
||||
continue
|
||||
}
|
||||
} else if isDigit(nextCh) {
|
||||
if len(promptRunes) >= i+4 && isDigit(promptRunes[i+2]) && isDigit(promptRunes[i+3]) {
|
||||
i += 3
|
||||
escStr := evalPromptEsc(string(promptRunes[i+1:i+4]), vars, state)
|
||||
buf.WriteString(escStr)
|
||||
continue
|
||||
} else {
|
||||
buf.WriteRune(ch) // invalid escape, so just write ch and move on
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
i += 1
|
||||
escStr := evalPromptEsc(string(nextCh), vars, state)
|
||||
buf.WriteString(escStr)
|
||||
continue
|
||||
}
|
||||
}
|
||||
buf.WriteRune(ch)
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func evalPromptEsc(escCode string, vars map[string]string, state *sstore.RemoteState) string {
|
||||
if strings.HasPrefix(escCode, "x{") && strings.HasSuffix(escCode, "}") {
|
||||
varName := escCode[2 : len(escCode)-1]
|
||||
return vars[varName]
|
||||
}
|
||||
if strings.HasPrefix(escCode, "y{") && strings.HasSuffix(escCode, "}") {
|
||||
if state == nil {
|
||||
return ""
|
||||
}
|
||||
varName := escCode[2 : len(escCode)-1]
|
||||
varMap := shexec.ParseEnv0(state.Env0)
|
||||
return varMap[varName]
|
||||
@ -622,50 +739,26 @@ func EvalPromptEsc(escCode string, vars map[string]string, state sstore.RemoteSt
|
||||
if escCode == "H" {
|
||||
return vars["remotehost"]
|
||||
}
|
||||
if escCode == "j" {
|
||||
return "0"
|
||||
}
|
||||
if escCode == "l" {
|
||||
return "(l)"
|
||||
}
|
||||
if escCode == "s" {
|
||||
return "mshell"
|
||||
}
|
||||
if escCode == "t" {
|
||||
now := time.Now()
|
||||
return now.Format("15:04:05")
|
||||
}
|
||||
if escCode == "T" {
|
||||
now := time.Now()
|
||||
return now.Format("03:04:05")
|
||||
}
|
||||
if escCode == "@" {
|
||||
now := time.Now()
|
||||
return now.Format("03:04:05PM")
|
||||
}
|
||||
if escCode == "u" {
|
||||
return vars["remoteuser"]
|
||||
}
|
||||
if escCode == "v" {
|
||||
return "0.1"
|
||||
}
|
||||
if escCode == "V" {
|
||||
return "0"
|
||||
}
|
||||
if escCode == "w" {
|
||||
return state.Cwd
|
||||
if state == nil {
|
||||
return "?"
|
||||
}
|
||||
return replaceHomePath(state.Cwd, vars["home"])
|
||||
}
|
||||
if escCode == "W" {
|
||||
return path.Base(state.Cwd)
|
||||
if state == nil {
|
||||
return "?"
|
||||
}
|
||||
if escCode == "!" {
|
||||
return "(!)"
|
||||
}
|
||||
if escCode == "#" {
|
||||
return "(#)"
|
||||
return path.Base(replaceHomePath(state.Cwd, vars["home"]))
|
||||
}
|
||||
if escCode == "$" {
|
||||
if vars["remoteuser"] == "root" {
|
||||
if vars["remoteuser"] == "root" || vars["sudo"] == "1" {
|
||||
return "#"
|
||||
} else {
|
||||
return "$"
|
||||
@ -700,5 +793,7 @@ func EvalPromptEsc(escCode string, vars map[string]string, state sstore.RemoteSt
|
||||
if escCode == "]" {
|
||||
return ""
|
||||
}
|
||||
|
||||
// we don't support date/time escapes (d, t, T, @), version escapes (v, V), cmd number (#, !), terminal device (l), jobs (j)
|
||||
return "(" + escCode + ")"
|
||||
}
|
||||
|
@ -178,7 +178,7 @@ func GetAllSessions(ctx context.Context) ([]*SessionType, error) {
|
||||
}
|
||||
screen.Windows = append(screen.Windows, sw)
|
||||
}
|
||||
query = `SELECT * FROM remote_instance WHERE sessionscope`
|
||||
query = `SELECT * FROM remote_instance`
|
||||
var ris []*RemoteInstance
|
||||
tx.SelectWrap(&ris, query)
|
||||
for _, ri := range ris {
|
||||
@ -195,22 +195,19 @@ func GetAllSessions(ctx context.Context) ([]*SessionType, error) {
|
||||
func GetWindowById(ctx context.Context, sessionId string, windowId string) (*WindowType, error) {
|
||||
var rtnWindow *WindowType
|
||||
err := WithTx(ctx, func(tx *TxWrap) error {
|
||||
var window WindowType
|
||||
query := `SELECT * FROM window WHERE sessionid = ? AND windowid = ?`
|
||||
found := tx.GetWrap(&window, query, sessionId, windowId)
|
||||
if !found {
|
||||
m := tx.GetMap(query, sessionId, windowId)
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
rtnWindow = &window
|
||||
rtnWindow = WindowFromMap(m)
|
||||
query = `SELECT * FROM line WHERE sessionid = ? AND windowid = ?`
|
||||
tx.SelectWrap(&window.Lines, query, sessionId, windowId)
|
||||
tx.SelectWrap(&rtnWindow.Lines, query, sessionId, windowId)
|
||||
query = `SELECT * FROM cmd WHERE cmdid IN (SELECT cmdid FROM line WHERE sessionid = ? AND windowid = ?)`
|
||||
cmdMaps := tx.SelectMaps(query, sessionId, windowId)
|
||||
for _, m := range cmdMaps {
|
||||
window.Cmds = append(window.Cmds, CmdFromMap(m))
|
||||
rtnWindow.Cmds = append(rtnWindow.Cmds, CmdFromMap(m))
|
||||
}
|
||||
query = `SELECT * FROM remote_instance WHERE sessionid = ? AND windowid = ? AND NOT sessionscope`
|
||||
tx.SelectWrap(&window.Remotes, query, sessionId, windowId)
|
||||
return nil
|
||||
})
|
||||
return rtnWindow, err
|
||||
@ -258,7 +255,7 @@ func GetSessionByName(ctx context.Context, name string) (*SessionType, error) {
|
||||
|
||||
// also creates default window, returns sessionId
|
||||
// if sessionName == "", it will be generated
|
||||
func InsertSessionWithName(ctx context.Context, sessionName string, activate bool) (*SessionUpdate, error) {
|
||||
func InsertSessionWithName(ctx context.Context, sessionName string, activate bool) (UpdatePacket, error) {
|
||||
newSessionId := uuid.New().String()
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
names := tx.SelectStrings(`SELECT name FROM session`)
|
||||
@ -279,7 +276,7 @@ func InsertSessionWithName(ctx context.Context, sessionName string, activate boo
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
update := &SessionUpdate{
|
||||
update := ModelUpdate{
|
||||
Sessions: []*SessionType{session},
|
||||
}
|
||||
if activate {
|
||||
@ -328,7 +325,11 @@ func InsertScreen(ctx context.Context, sessionId string, screenName string, acti
|
||||
if !tx.Exists(query, sessionId) {
|
||||
return fmt.Errorf("cannot create screen, no session found")
|
||||
}
|
||||
newWindowId := txCreateWindow(tx, sessionId)
|
||||
remoteId := tx.GetString(`SELECT remoteid FROM remote WHERE remotealias = ?`, LocalRemoteAlias)
|
||||
if remoteId == "" {
|
||||
return fmt.Errorf("cannot create screen, no local remote found")
|
||||
}
|
||||
newWindowId := txCreateWindow(tx, sessionId, RemotePtrType{RemoteId: remoteId})
|
||||
maxScreenIdx := tx.GetInt(`SELECT COALESCE(max(screenidx), 0) FROM screen WHERE sessionid = ?`, sessionId)
|
||||
screenNames := tx.SelectStrings(`SELECT name FROM screen WHERE sessionid = ?`, sessionId)
|
||||
screenName = fmtUniqueName(screenName, "s%d", maxScreenIdx+1, screenNames)
|
||||
@ -377,11 +378,20 @@ func GetScreenById(ctx context.Context, sessionId string, screenId string) (*Scr
|
||||
return rtnScreen, nil
|
||||
}
|
||||
|
||||
func txCreateWindow(tx *TxWrap, sessionId string) string {
|
||||
windowId := uuid.New().String()
|
||||
query := `INSERT INTO window (sessionid, windowid, curremote, winopts, shareopts, owneruserid, sharemode) VALUES (?, ?, ?, ?, ?, '', 'local')`
|
||||
tx.ExecWrap(query, sessionId, windowId, LocalRemoteName, WindowOptsType{}, WindowShareOptsType{})
|
||||
return windowId
|
||||
func txCreateWindow(tx *TxWrap, sessionId string, curRemote RemotePtrType) string {
|
||||
w := &WindowType{
|
||||
SessionId: sessionId,
|
||||
WindowId: uuid.New().String(),
|
||||
CurRemote: curRemote,
|
||||
WinOpts: WindowOptsType{},
|
||||
ShareMode: ShareModeLocal,
|
||||
ShareOpts: WindowShareOptsType{},
|
||||
}
|
||||
wmap := w.ToMap()
|
||||
query := `INSERT INTO window ( sessionid, windowid, curremoteowneruserid, curremoteid, curremotename, winopts, owneruserid, sharemode, shareopts)
|
||||
VALUES (:sessionid,:windowid,:curremoteowneruserid,:curremoteid,:curremotename,:winopts,:owneruserid,:sharemode,:shareopts)`
|
||||
tx.NamedExecWrap(query, wmap)
|
||||
return w.WindowId
|
||||
}
|
||||
|
||||
func InsertLine(ctx context.Context, line *LineType, cmd *CmdType) error {
|
||||
@ -404,8 +414,8 @@ func InsertLine(ctx context.Context, line *LineType, cmd *CmdType) error {
|
||||
if cmd != nil {
|
||||
cmdMap := cmd.ToMap()
|
||||
query = `
|
||||
INSERT INTO cmd ( sessionid, cmdid, remoteid, cmdstr, remotestate, termopts, status, startpk, donepk, runout, usedrows, prompt)
|
||||
VALUES (:sessionid,:cmdid,:remoteid,:cmdstr,:remotestate,:termopts,:status,:startpk,:donepk,:runout,:usedrows,:prompt)
|
||||
INSERT INTO cmd ( sessionid, cmdid, remoteid, cmdstr, remotestate, termopts, status, startpk, donepk, runout, usedrows)
|
||||
VALUES (:sessionid,:cmdid,:remoteid,:cmdstr,:remotestate,:termopts,:status,:startpk,:donepk,:runout,:usedrows)
|
||||
`
|
||||
tx.NamedExecWrap(query, cmdMap)
|
||||
}
|
||||
@ -448,7 +458,7 @@ func UpdateCmdDonePk(ctx context.Context, donePk *packet.CmdDonePacketType) (Upd
|
||||
if rtnCmd == nil {
|
||||
return nil, fmt.Errorf("cmd data not found for ck[%s]", donePk.CK)
|
||||
}
|
||||
return LineUpdate{Cmd: rtnCmd}, nil
|
||||
return ModelUpdate{Cmd: rtnCmd}, nil
|
||||
}
|
||||
|
||||
func AppendCmdErrorPk(ctx context.Context, errPk *packet.CmdErrorPacketType) error {
|
||||
@ -548,67 +558,80 @@ func DeleteScreen(ctx context.Context, sessionId string, screenId string) (Updat
|
||||
return update, nil
|
||||
}
|
||||
|
||||
func GetRemoteState(ctx context.Context, rname string, sessionId string, windowId string) (string, *RemoteState, error) {
|
||||
var remoteId string
|
||||
func GetRemoteState(ctx context.Context, sessionId string, windowId string, remotePtr RemotePtrType) (*RemoteState, error) {
|
||||
var remoteState *RemoteState
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
var ri RemoteInstance
|
||||
query := `SELECT * FROM remote_instance WHERE sessionid = ? AND windowid = ? AND name = ?`
|
||||
found := tx.GetWrap(&ri, query, sessionId, windowId, rname)
|
||||
query := `SELECT * FROM remote_instance WHERE sessionid = ? AND windowid = ? AND remoteowneruserid = ? AND remoteid = ? AND name = ?`
|
||||
found := tx.GetWrap(&ri, query, sessionId, windowId, remotePtr.OwnerUserId, remotePtr.RemoteId, remotePtr.Name)
|
||||
if found {
|
||||
remoteId = ri.RemoteId
|
||||
remoteState = &ri.State
|
||||
return nil
|
||||
}
|
||||
query = `SELECT remoteid FROM remote WHERE remotealias = ? OR remotecanonicalname = ?`
|
||||
remoteId = tx.GetString(query, rname, rname)
|
||||
if remoteId == "" {
|
||||
return fmt.Errorf("remote not found", rname)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return remoteId, remoteState, txErr
|
||||
return remoteState, txErr
|
||||
}
|
||||
|
||||
func UpdateRemoteState(ctx context.Context, rname string, sessionId string, windowId string, remoteId string, state RemoteState) (*RemoteInstance, error) {
|
||||
var ri RemoteInstance
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
func validateSessionWindow(tx *TxWrap, sessionId string, windowId string) error {
|
||||
if windowId == "" {
|
||||
query := `SELECT sessionid FROM session WHERE sessionid = ?`
|
||||
if !tx.Exists(query, sessionId) {
|
||||
return fmt.Errorf("no session found")
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
query := `SELECT windowid FROM window WHERE sessionid = ? AND windowid = ?`
|
||||
if !tx.Exists(query, sessionId, windowId) {
|
||||
return fmt.Errorf("cannot update remote instance cwd, no window found")
|
||||
return fmt.Errorf("no window found")
|
||||
}
|
||||
query = `SELECT * FROM remote_instance WHERE sessionid = ? AND windowid = ? AND name = ?`
|
||||
found := tx.GetWrap(&ri, query, sessionId, windowId, rname)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateRemoteState(ctx context.Context, sessionId string, windowId string, remotePtr RemotePtrType, state RemoteState) (*RemoteInstance, error) {
|
||||
if remotePtr.IsSessionScope() {
|
||||
windowId = ""
|
||||
}
|
||||
var ri RemoteInstance
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
err := validateSessionWindow(tx, sessionId, windowId)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot update remote instance cwd: %w", err)
|
||||
}
|
||||
query := `SELECT * FROM remote_instance WHERE sessionid = ? AND windowid = ? AND remoteowneruserid = ? AND remoteid = ? AND name = ?`
|
||||
found := tx.GetWrap(&ri, query, sessionId, windowId, remotePtr.OwnerUserId, remotePtr.RemoteId, remotePtr.Name)
|
||||
if !found {
|
||||
ri = RemoteInstance{
|
||||
RIId: uuid.New().String(),
|
||||
Name: rname,
|
||||
Name: remotePtr.Name,
|
||||
SessionId: sessionId,
|
||||
WindowId: windowId,
|
||||
RemoteId: remoteId,
|
||||
SessionScope: (windowId == ""),
|
||||
RemoteOwnerUserId: remotePtr.OwnerUserId,
|
||||
RemoteId: remotePtr.RemoteId,
|
||||
State: state,
|
||||
}
|
||||
query = `INSERT INTO remote_instance (riid, name, sessionid, windowid, remoteid, sessionscope, state) VALUES (:riid, :name, :sessionid, :windowid, :remoteid, :sessionscope, :state)`
|
||||
query = `INSERT INTO remote_instance ( riid, name, sessionid, windowid, remoteowneruserid, remoteid, state)
|
||||
VALUES (:riid,:name,:sessionid,:windowid,:remoteowneruserid,:remoteid,:state)`
|
||||
tx.NamedExecWrap(query, ri)
|
||||
return nil
|
||||
}
|
||||
query = `UPDATE remote_instance SET state = ? WHERE sessionid = ? AND windowid = ? AND name = ?`
|
||||
query = `UPDATE remote_instance SET state = ? WHERE sessionid = ? AND windowid = ? AND remoteowneruserid = ? AND remoteid = ? AND name = ?`
|
||||
ri.State = state
|
||||
tx.ExecWrap(query, ri.State, ri.SessionId, ri.WindowId, ri.Name)
|
||||
tx.ExecWrap(query, ri.State, ri.SessionId, ri.WindowId, remotePtr.OwnerUserId, remotePtr.RemoteId, remotePtr.Name)
|
||||
return nil
|
||||
})
|
||||
return &ri, txErr
|
||||
}
|
||||
|
||||
func UpdateCurRemote(ctx context.Context, sessionId string, windowId string, remoteName string) error {
|
||||
func UpdateCurRemote(ctx context.Context, sessionId string, windowId string, remotePtr RemotePtrType) error {
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `SELECT windowid FROM window WHERE sessionid = ? AND windowid = ?`
|
||||
if !tx.Exists(query, sessionId, windowId) {
|
||||
return fmt.Errorf("cannot update curremote, no window found")
|
||||
return fmt.Errorf("cannot update curremote: no window found")
|
||||
}
|
||||
query = `UPDATE window SET curremote = ? WHERE sessionid = ? AND windowid = ?`
|
||||
tx.ExecWrap(query, remoteName, sessionId, windowId)
|
||||
query = `UPDATE window SET curremoteowneruserid = ?, curremoteid = ?, curremotename = ? WHERE sessionid = ? AND windowid = ?`
|
||||
tx.ExecWrap(query, remotePtr.OwnerUserId, remotePtr.RemoteId, remotePtr.Name, sessionId, windowId)
|
||||
return nil
|
||||
})
|
||||
return txErr
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"os"
|
||||
"os/user"
|
||||
"path"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@ -30,7 +31,7 @@ const DBFileName = "sh2.db"
|
||||
|
||||
const DefaultSessionName = "default"
|
||||
const DefaultWindowName = "default"
|
||||
const LocalRemoteName = "local"
|
||||
const LocalRemoteAlias = "local"
|
||||
const DefaultScreenWindowName = "w1"
|
||||
|
||||
const DefaultCwd = "~"
|
||||
@ -132,22 +133,78 @@ func (opts WindowShareOptsType) Value() (driver.Value, error) {
|
||||
return quickValueJson(opts)
|
||||
}
|
||||
|
||||
type RemotePtrType struct {
|
||||
OwnerUserId string `json:"owneruserid"`
|
||||
RemoteId string `json:"remoteid"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func (r RemotePtrType) IsSessionScope() bool {
|
||||
return strings.HasPrefix(r.Name, "*")
|
||||
}
|
||||
|
||||
func (r RemotePtrType) MakeFullRemoteRef() string {
|
||||
if r.RemoteId == "" {
|
||||
return ""
|
||||
}
|
||||
if r.OwnerUserId == "" && r.Name == "" {
|
||||
return r.RemoteId
|
||||
}
|
||||
if r.OwnerUserId != "" && r.Name == "" {
|
||||
return fmt.Sprintf("@%s:%s", r.OwnerUserId, r.RemoteId)
|
||||
}
|
||||
if r.OwnerUserId == "" && r.Name != "" {
|
||||
return fmt.Sprintf("%s:%s", r.RemoteId, r.Name)
|
||||
}
|
||||
return fmt.Sprintf("@%s:%s:%s", r.OwnerUserId, r.RemoteId, r.Name)
|
||||
}
|
||||
|
||||
type WindowType struct {
|
||||
SessionId string `json:"sessionid"`
|
||||
WindowId string `json:"windowid"`
|
||||
CurRemote string `json:"curremote"`
|
||||
CurRemote RemotePtrType `json:"curremote"`
|
||||
WinOpts WindowOptsType `json:"winopts"`
|
||||
OwnerUserId string `json:"owneruserid"`
|
||||
ShareMode string `json:"sharemode"`
|
||||
ShareOpts WindowShareOptsType `json:"shareopts"`
|
||||
Lines []*LineType `json:"lines"`
|
||||
Cmds []*CmdType `json:"cmds"`
|
||||
Remotes []*RemoteInstance `json:"remotes"`
|
||||
|
||||
// only for updates
|
||||
Remove bool `json:"remove,omitempty"`
|
||||
}
|
||||
|
||||
func (w *WindowType) ToMap() map[string]interface{} {
|
||||
rtn := make(map[string]interface{})
|
||||
rtn["sessionid"] = w.SessionId
|
||||
rtn["windowid"] = w.WindowId
|
||||
rtn["curremoteowneruserid"] = w.CurRemote.OwnerUserId
|
||||
rtn["curremoteid"] = w.CurRemote.RemoteId
|
||||
rtn["curremotename"] = w.CurRemote.Name
|
||||
rtn["winopts"] = quickJson(w.WinOpts)
|
||||
rtn["owneruserid"] = w.OwnerUserId
|
||||
rtn["sharemode"] = w.ShareMode
|
||||
rtn["shareopts"] = quickJson(w.ShareOpts)
|
||||
return rtn
|
||||
}
|
||||
|
||||
func WindowFromMap(m map[string]interface{}) *WindowType {
|
||||
if len(m) == 0 {
|
||||
return nil
|
||||
}
|
||||
var w WindowType
|
||||
quickSetStr(&w.SessionId, m, "sessionid")
|
||||
quickSetStr(&w.WindowId, m, "windowid")
|
||||
quickSetStr(&w.CurRemote.OwnerUserId, m, "curremoteowneruserid")
|
||||
quickSetStr(&w.CurRemote.RemoteId, m, "curremoteid")
|
||||
quickSetStr(&w.CurRemote.Name, m, "curremotename")
|
||||
quickSetJson(&w.WinOpts, m, "winopts")
|
||||
quickSetStr(&w.OwnerUserId, m, "owneruserid")
|
||||
quickSetStr(&w.ShareMode, m, "sharemode")
|
||||
quickSetJson(&w.ShareOpts, m, "shareopts")
|
||||
return &w
|
||||
}
|
||||
|
||||
type ScreenOptsType struct {
|
||||
TabColor string `json:"tabcolor"`
|
||||
}
|
||||
@ -261,8 +318,8 @@ type RemoteInstance struct {
|
||||
Name string `json:"name"`
|
||||
SessionId string `json:"sessionid"`
|
||||
WindowId string `json:"windowid"`
|
||||
RemoteOwnerUserId string `json:"remoteowneruserid"`
|
||||
RemoteId string `json:"remoteid"`
|
||||
SessionScope bool `json:"sessionscope"`
|
||||
State RemoteState `json:"state"`
|
||||
|
||||
// only for updates
|
||||
@ -292,7 +349,6 @@ type SSHOpts struct {
|
||||
|
||||
type RemoteOptsType struct {
|
||||
Color string `json:"color"`
|
||||
Prompt string `json:"prompt"`
|
||||
}
|
||||
|
||||
func (opts *RemoteOptsType) Scan(val interface{}) error {
|
||||
@ -341,7 +397,6 @@ type CmdType struct {
|
||||
DonePk *packet.CmdDonePacketType `json:"donepk"`
|
||||
UsedRows int64 `json:"usedrows"`
|
||||
RunOut []packet.PacketType `json:"runout"`
|
||||
Prompt string `json:"prompt"`
|
||||
Remove bool `json:"remove"`
|
||||
}
|
||||
|
||||
@ -397,7 +452,6 @@ func (cmd *CmdType) ToMap() map[string]interface{} {
|
||||
rtn["donepk"] = quickJson(cmd.DonePk)
|
||||
rtn["runout"] = quickJson(cmd.RunOut)
|
||||
rtn["usedrows"] = cmd.UsedRows
|
||||
rtn["prompt"] = cmd.Prompt
|
||||
return rtn
|
||||
}
|
||||
|
||||
@ -417,7 +471,6 @@ func CmdFromMap(m map[string]interface{}) *CmdType {
|
||||
quickSetJson(&cmd.DonePk, m, "donepk")
|
||||
quickSetJson(&cmd.RunOut, m, "runout")
|
||||
quickSetInt64(&cmd.UsedRows, m, "usedrows")
|
||||
quickSetStr(&cmd.Prompt, m, "prompt")
|
||||
return &cmd
|
||||
}
|
||||
|
||||
@ -488,7 +541,7 @@ func EnsureLocalRemote(ctx context.Context) error {
|
||||
RemoteId: uuid.New().String(),
|
||||
PhysicalId: physicalId,
|
||||
RemoteType: RemoteTypeSsh,
|
||||
RemoteAlias: LocalRemoteName,
|
||||
RemoteAlias: LocalRemoteAlias,
|
||||
RemoteCanonicalName: fmt.Sprintf("%s@%s", user.Username, hostName),
|
||||
RemoteSudo: false,
|
||||
RemoteUser: user.Username,
|
||||
@ -521,6 +574,7 @@ func AddTest01Remote(ctx context.Context) error {
|
||||
RemoteUser: "ubuntu",
|
||||
RemoteHost: "test01.ec2",
|
||||
SSHOpts: &SSHOpts{
|
||||
Local: false,
|
||||
SSHHost: "test01.ec2",
|
||||
SSHUser: "ubuntu",
|
||||
SSHIdentity: "/Users/mike/aws/mfmt.pem",
|
||||
@ -552,6 +606,7 @@ func AddTest02Remote(ctx context.Context) error {
|
||||
RemoteUser: "test2",
|
||||
RemoteHost: "test01.ec2",
|
||||
SSHOpts: &SSHOpts{
|
||||
Local: false,
|
||||
SSHHost: "test01.ec2",
|
||||
SSHUser: "test2",
|
||||
},
|
||||
|
@ -5,12 +5,7 @@ import "sync"
|
||||
var MainBus *UpdateBus = MakeUpdateBus()
|
||||
|
||||
const PtyDataUpdateStr = "pty"
|
||||
const SessionUpdateStr = "session"
|
||||
const WindowUpdateStr = "window"
|
||||
const CmdUpdateStr = "cmd"
|
||||
const LineCmdUpdateStr = "line+cmd"
|
||||
const InfoUpdateStr = "info"
|
||||
const CompGenUpdateStr = "compgen"
|
||||
const ModelUpdateStr = "model"
|
||||
|
||||
type UpdatePacket interface {
|
||||
UpdateType() string
|
||||
@ -28,56 +23,40 @@ func (PtyDataUpdate) UpdateType() string {
|
||||
return PtyDataUpdateStr
|
||||
}
|
||||
|
||||
type WindowUpdate struct {
|
||||
Window WindowType `json:"window"`
|
||||
Info *InfoMsgType `json:"info,omitempty"`
|
||||
}
|
||||
|
||||
func (WindowUpdate) UpdateType() string {
|
||||
return WindowUpdateStr
|
||||
}
|
||||
|
||||
type SessionUpdate struct {
|
||||
type ModelUpdate struct {
|
||||
Sessions []*SessionType `json:"sessions"`
|
||||
ActiveSessionId string `json:"activesessionid,omitempty"`
|
||||
Window WindowType `json:"window"`
|
||||
Line *LineType `json:"line"`
|
||||
Cmd *CmdType `json:"cmd,omitempty"`
|
||||
CmdLine *CmdLineType `json:"cmdline,omitempty"`
|
||||
Info *InfoMsgType `json:"info,omitempty"`
|
||||
}
|
||||
|
||||
func (SessionUpdate) UpdateType() string {
|
||||
return SessionUpdateStr
|
||||
func (ModelUpdate) UpdateType() string {
|
||||
return ModelUpdateStr
|
||||
}
|
||||
|
||||
func MakeSingleSessionUpdate(sessionId string) (*SessionUpdate, *SessionType) {
|
||||
func MakeSingleSessionUpdate(sessionId string) (ModelUpdate, *SessionType) {
|
||||
session := &SessionType{
|
||||
SessionId: sessionId,
|
||||
NotifyNum: -1,
|
||||
}
|
||||
update := &SessionUpdate{
|
||||
update := ModelUpdate{
|
||||
Sessions: []*SessionType{session},
|
||||
}
|
||||
return update, session
|
||||
}
|
||||
|
||||
type LineUpdate struct {
|
||||
Line *LineType `json:"line"`
|
||||
Cmd *CmdType `json:"cmd,omitempty"`
|
||||
Remove bool `json:"remove,omitempty"`
|
||||
Info *InfoMsgType `json:"info,omitempty"`
|
||||
}
|
||||
|
||||
func (LineUpdate) UpdateType() string {
|
||||
return LineCmdUpdateStr
|
||||
}
|
||||
|
||||
func ReadLineCmdIdFromUpdate(update UpdatePacket) (string, string) {
|
||||
lineUpdate, ok := update.(LineUpdate)
|
||||
modelUpdate, ok := update.(ModelUpdate)
|
||||
if !ok {
|
||||
return "", ""
|
||||
}
|
||||
if lineUpdate.Line == nil {
|
||||
if modelUpdate.Line == nil {
|
||||
return "", ""
|
||||
}
|
||||
return lineUpdate.Line.LineId, lineUpdate.Line.CmdId
|
||||
return modelUpdate.Line.LineId, modelUpdate.Line.CmdId
|
||||
}
|
||||
|
||||
type InfoMsgType struct {
|
||||
@ -95,15 +74,6 @@ type CmdLineType struct {
|
||||
InsertPos int64 `json:"insertpos"`
|
||||
}
|
||||
|
||||
type InfoUpdate struct {
|
||||
Info *InfoMsgType `json:"info,omitempty"`
|
||||
CmdLine *CmdLineType `json:"cmdline,omitempty"`
|
||||
}
|
||||
|
||||
func (InfoUpdate) UpdateType() string {
|
||||
return InfoUpdateStr
|
||||
}
|
||||
|
||||
type UpdateChannel struct {
|
||||
SessionId string
|
||||
ClientId string
|
||||
@ -167,3 +137,12 @@ func (bus *UpdateBus) SendUpdate(sessionId string, update interface{}) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func MakeSessionsUpdateForRemote(sessionId string, ri *RemoteInstance) []*SessionType {
|
||||
return []*SessionType{
|
||||
&SessionType{
|
||||
SessionId: sessionId,
|
||||
Remotes: []*RemoteInstance{ri},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user