2022-08-27 01:24:07 +02:00
|
|
|
package cmdrunner
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
2022-11-29 03:03:02 +01:00
|
|
|
"log"
|
2022-08-27 01:24:07 +02:00
|
|
|
"regexp"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/google/uuid"
|
|
|
|
"github.com/scripthaus-dev/sh2-server/pkg/remote"
|
|
|
|
"github.com/scripthaus-dev/sh2-server/pkg/scpacket"
|
|
|
|
"github.com/scripthaus-dev/sh2-server/pkg/sstore"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2022-08-30 01:31:06 +02:00
|
|
|
R_Session = 1
|
|
|
|
R_Screen = 2
|
|
|
|
R_Window = 4
|
|
|
|
R_Remote = 8
|
2022-09-01 21:47:10 +02:00
|
|
|
R_RemoteConnected = 16
|
2022-08-27 01:24:07 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
type resolvedIds struct {
|
2022-08-30 01:31:06 +02:00
|
|
|
SessionId string
|
|
|
|
ScreenId string
|
|
|
|
WindowId string
|
|
|
|
Remote *ResolvedRemote
|
|
|
|
}
|
|
|
|
|
|
|
|
type ResolvedRemote struct {
|
|
|
|
DisplayName string
|
|
|
|
RemotePtr sstore.RemotePtrType
|
|
|
|
MShell *remote.MShellProc
|
2022-09-14 21:56:05 +02:00
|
|
|
RState remote.RemoteRuntimeState
|
2022-10-04 04:04:48 +02:00
|
|
|
RemoteCopy *sstore.RemoteType
|
2022-11-29 03:03:02 +01:00
|
|
|
StatePtr *sstore.ShellStatePtr
|
|
|
|
FeState *sstore.FeStateType
|
2022-08-27 01:24:07 +02:00
|
|
|
}
|
|
|
|
|
2022-10-07 08:58:38 +02:00
|
|
|
type ResolveItem = sstore.ResolveItem
|
2022-08-27 02:17:33 +02:00
|
|
|
|
|
|
|
func itemNames(items []ResolveItem) []string {
|
|
|
|
if len(items) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
rtn := make([]string, len(items))
|
|
|
|
for idx, item := range items {
|
|
|
|
rtn[idx] = item.Name
|
|
|
|
}
|
|
|
|
return rtn
|
|
|
|
}
|
|
|
|
|
|
|
|
func sessionsToResolveItems(sessions []*sstore.SessionType) []ResolveItem {
|
|
|
|
if len(sessions) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
rtn := make([]ResolveItem, len(sessions))
|
|
|
|
for idx, session := range sessions {
|
2022-12-25 22:03:11 +01:00
|
|
|
rtn[idx] = ResolveItem{Name: session.Name, Id: session.SessionId, Hidden: session.Archived}
|
2022-08-27 02:17:33 +02:00
|
|
|
}
|
|
|
|
return rtn
|
|
|
|
}
|
|
|
|
|
2022-08-27 02:29:32 +02:00
|
|
|
func screensToResolveItems(screens []*sstore.ScreenType) []ResolveItem {
|
|
|
|
if len(screens) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
rtn := make([]ResolveItem, len(screens))
|
|
|
|
for idx, screen := range screens {
|
2022-12-25 22:03:11 +01:00
|
|
|
rtn[idx] = ResolveItem{Name: screen.Name, Id: screen.ScreenId, Hidden: screen.Archived}
|
2022-08-27 02:29:32 +02:00
|
|
|
}
|
|
|
|
return rtn
|
|
|
|
}
|
|
|
|
|
2022-10-07 08:58:38 +02:00
|
|
|
// 1-indexed
|
|
|
|
func boundInt(ival int, maxVal int, wrap bool) int {
|
|
|
|
if maxVal == 0 {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
if ival < 1 {
|
|
|
|
if wrap {
|
|
|
|
return maxVal
|
|
|
|
} else {
|
|
|
|
return 1
|
|
|
|
}
|
2022-08-27 01:24:07 +02:00
|
|
|
}
|
2022-10-07 08:58:38 +02:00
|
|
|
if ival > maxVal {
|
|
|
|
if wrap {
|
|
|
|
return 1
|
|
|
|
} else {
|
|
|
|
return maxVal
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ival
|
|
|
|
}
|
|
|
|
|
|
|
|
type posArgType struct {
|
2022-10-07 10:08:03 +02:00
|
|
|
Pos int
|
|
|
|
IsWrap bool
|
|
|
|
IsRelative bool
|
|
|
|
StartAnchor bool
|
|
|
|
EndAnchor bool
|
2022-10-07 08:58:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func parsePosArg(posStr string) *posArgType {
|
2022-08-27 01:24:07 +02:00
|
|
|
if !positionRe.MatchString(posStr) {
|
2022-08-27 02:17:33 +02:00
|
|
|
return nil
|
2022-08-27 01:24:07 +02:00
|
|
|
}
|
2022-10-07 10:08:03 +02:00
|
|
|
if posStr == "+" {
|
|
|
|
return &posArgType{Pos: 1, IsWrap: true, IsRelative: true}
|
|
|
|
} else if posStr == "-" {
|
|
|
|
return &posArgType{Pos: -1, IsWrap: true, IsRelative: true}
|
|
|
|
} else if posStr == "S" {
|
|
|
|
return &posArgType{Pos: 0, IsRelative: true, StartAnchor: true}
|
|
|
|
} else if posStr == "E" {
|
|
|
|
return &posArgType{Pos: 0, IsRelative: true, EndAnchor: true}
|
|
|
|
}
|
|
|
|
if strings.HasPrefix(posStr, "S+") {
|
|
|
|
pos, _ := strconv.Atoi(posStr[2:])
|
|
|
|
return &posArgType{Pos: pos, IsRelative: true, StartAnchor: true}
|
|
|
|
}
|
|
|
|
if strings.HasPrefix(posStr, "E-") {
|
|
|
|
pos, _ := strconv.Atoi(posStr[1:])
|
|
|
|
return &posArgType{Pos: pos, IsRelative: true, EndAnchor: true}
|
|
|
|
}
|
|
|
|
if strings.HasPrefix(posStr, "+") || strings.HasPrefix(posStr, "-") {
|
|
|
|
pos, _ := strconv.Atoi(posStr)
|
|
|
|
return &posArgType{Pos: pos, IsRelative: true}
|
|
|
|
}
|
|
|
|
pos, _ := strconv.Atoi(posStr)
|
|
|
|
return &posArgType{Pos: pos}
|
2022-10-07 08:58:38 +02:00
|
|
|
}
|
|
|
|
|
2022-12-24 00:56:29 +01:00
|
|
|
func resolveByPosition(isNumeric bool, allItems []ResolveItem, curId string, posStr string) *ResolveItem {
|
|
|
|
items := make([]ResolveItem, 0, len(allItems))
|
|
|
|
for _, item := range allItems {
|
|
|
|
if !item.Hidden {
|
|
|
|
items = append(items, item)
|
|
|
|
}
|
|
|
|
}
|
2022-10-07 08:58:38 +02:00
|
|
|
if len(items) == 0 {
|
|
|
|
return nil
|
2022-08-27 01:24:07 +02:00
|
|
|
}
|
2022-10-07 08:58:38 +02:00
|
|
|
posArg := parsePosArg(posStr)
|
|
|
|
if posArg == nil {
|
|
|
|
return nil
|
2022-08-27 01:24:07 +02:00
|
|
|
}
|
2022-10-07 08:58:38 +02:00
|
|
|
var finalPos int
|
|
|
|
if posArg.IsRelative {
|
2022-10-07 10:08:03 +02:00
|
|
|
var curIdx int
|
|
|
|
if posArg.StartAnchor {
|
|
|
|
curIdx = 1
|
|
|
|
} else if posArg.EndAnchor {
|
|
|
|
curIdx = len(items)
|
|
|
|
} else {
|
|
|
|
curIdx = 1 // if no match, curIdx will be first item
|
|
|
|
for idx, item := range items {
|
|
|
|
if item.Id == curId {
|
|
|
|
curIdx = idx + 1
|
|
|
|
break
|
|
|
|
}
|
2022-10-07 08:58:38 +02:00
|
|
|
}
|
2022-08-27 01:24:07 +02:00
|
|
|
}
|
2022-10-07 08:58:38 +02:00
|
|
|
finalPos = curIdx + posArg.Pos
|
2022-10-07 10:08:03 +02:00
|
|
|
} else if isNumeric {
|
|
|
|
// these resolve items have a "Num" set that should be used to look up non-relative positions
|
2022-12-24 00:56:29 +01:00
|
|
|
// use allItems for numeric resolve
|
|
|
|
for _, item := range allItems {
|
2022-10-07 10:08:03 +02:00
|
|
|
if item.Num == posArg.Pos {
|
|
|
|
return &item
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
2022-10-07 08:58:38 +02:00
|
|
|
} else {
|
2022-10-07 10:08:03 +02:00
|
|
|
// non-numeric means position is just the index
|
2022-10-07 08:58:38 +02:00
|
|
|
finalPos = posArg.Pos
|
2022-08-27 01:24:07 +02:00
|
|
|
}
|
2022-10-07 08:58:38 +02:00
|
|
|
finalPos = boundInt(finalPos, len(items), posArg.IsWrap)
|
|
|
|
return &items[finalPos-1]
|
2022-08-27 01:24:07 +02:00
|
|
|
}
|
|
|
|
|
2022-09-14 21:56:05 +02:00
|
|
|
func resolveRemoteArg(remoteArg string) (*sstore.RemotePtrType, error) {
|
|
|
|
rrUser, rrRemote, rrName, err := parseFullRemoteRef(remoteArg)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if rrUser != "" {
|
|
|
|
return nil, fmt.Errorf("remoteusers not supported")
|
|
|
|
}
|
2022-09-14 22:01:52 +02:00
|
|
|
msh := remote.GetRemoteByArg(rrRemote)
|
2022-09-14 21:56:05 +02:00
|
|
|
if msh == nil {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
rcopy := msh.GetRemoteCopy()
|
|
|
|
return &sstore.RemotePtrType{RemoteId: rcopy.RemoteId, Name: rrName}, nil
|
|
|
|
}
|
|
|
|
|
2022-08-30 01:31:06 +02:00
|
|
|
func resolveUiIds(ctx context.Context, pk *scpacket.FeCommandPacketType, rtype int) (resolvedIds, error) {
|
2022-08-27 01:24:07 +02:00
|
|
|
rtn := resolvedIds{}
|
2022-08-30 01:31:06 +02:00
|
|
|
uictx := pk.UIContext
|
|
|
|
if uictx != nil {
|
|
|
|
rtn.SessionId = uictx.SessionId
|
|
|
|
rtn.ScreenId = uictx.ScreenId
|
|
|
|
rtn.WindowId = uictx.WindowId
|
2022-08-27 01:24:07 +02:00
|
|
|
}
|
2022-10-07 03:33:54 +02:00
|
|
|
if pk.Kwargs["session"] != "" {
|
|
|
|
sessionId, err := resolveSessionArg(pk.Kwargs["session"])
|
|
|
|
if err != nil {
|
|
|
|
return rtn, err
|
|
|
|
}
|
|
|
|
if sessionId != "" {
|
|
|
|
rtn.SessionId = sessionId
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if pk.Kwargs["screen"] != "" {
|
|
|
|
screenId, err := resolveScreenArg(rtn.SessionId, pk.Kwargs["screen"])
|
|
|
|
if err != nil {
|
|
|
|
return rtn, err
|
|
|
|
}
|
|
|
|
if screenId != "" {
|
|
|
|
rtn.ScreenId = screenId
|
|
|
|
}
|
|
|
|
}
|
2022-09-06 05:08:59 +02:00
|
|
|
if pk.Kwargs["window"] != "" {
|
|
|
|
windowId, err := resolveWindowArg(rtn.SessionId, rtn.ScreenId, pk.Kwargs["window"])
|
|
|
|
if err != nil {
|
|
|
|
return rtn, err
|
|
|
|
}
|
|
|
|
if windowId != "" {
|
|
|
|
rtn.WindowId = windowId
|
|
|
|
}
|
|
|
|
}
|
2022-09-14 21:56:05 +02:00
|
|
|
var rptr *sstore.RemotePtrType
|
|
|
|
var err error
|
|
|
|
if pk.Kwargs["remote"] != "" {
|
|
|
|
rptr, err = resolveRemoteArg(pk.Kwargs["remote"])
|
|
|
|
if err != nil {
|
|
|
|
return rtn, err
|
|
|
|
}
|
|
|
|
if rptr == nil {
|
|
|
|
return rtn, fmt.Errorf("invalid remote argument %q passed, remote not found", pk.Kwargs["remote"])
|
|
|
|
}
|
|
|
|
} else if uictx.Remote != nil {
|
|
|
|
rptr = uictx.Remote
|
|
|
|
}
|
|
|
|
if rptr != nil {
|
|
|
|
err = rptr.Validate()
|
|
|
|
if err != nil {
|
|
|
|
return rtn, fmt.Errorf("invalid resolved remote: %v", err)
|
|
|
|
}
|
|
|
|
rr, err := resolveRemoteFromPtr(ctx, rptr, rtn.SessionId, rtn.WindowId)
|
|
|
|
if err != nil {
|
|
|
|
return rtn, err
|
|
|
|
}
|
|
|
|
rtn.Remote = rr
|
|
|
|
}
|
2022-08-30 01:31:06 +02:00
|
|
|
if rtype&R_Session > 0 && rtn.SessionId == "" {
|
|
|
|
return rtn, fmt.Errorf("no session")
|
2022-08-27 01:24:07 +02:00
|
|
|
}
|
2022-08-30 01:31:06 +02:00
|
|
|
if rtype&R_Screen > 0 && rtn.ScreenId == "" {
|
|
|
|
return rtn, fmt.Errorf("no screen")
|
2022-08-27 01:24:07 +02:00
|
|
|
}
|
2022-08-30 01:31:06 +02:00
|
|
|
if rtype&R_Window > 0 && rtn.WindowId == "" {
|
|
|
|
return rtn, fmt.Errorf("no window")
|
|
|
|
}
|
2022-09-01 21:47:10 +02:00
|
|
|
if (rtype&R_Remote > 0 || rtype&R_RemoteConnected > 0) && rtn.Remote == nil {
|
2022-08-30 01:31:06 +02:00
|
|
|
return rtn, fmt.Errorf("no remote")
|
|
|
|
}
|
|
|
|
if rtype&R_RemoteConnected > 0 {
|
|
|
|
if !rtn.Remote.RState.IsConnected() {
|
2022-12-28 22:56:19 +01:00
|
|
|
err = rtn.Remote.MShell.TryAutoConnect()
|
|
|
|
if err != nil {
|
2022-12-29 01:59:54 +01:00
|
|
|
return rtn, fmt.Errorf("error trying to auto-connect remote %q: %w", rtn.Remote.DisplayName, err)
|
2022-12-28 22:56:19 +01:00
|
|
|
}
|
2022-12-29 01:59:54 +01:00
|
|
|
rrNew, err := resolveRemoteFromPtr(ctx, rptr, rtn.SessionId, rtn.WindowId)
|
|
|
|
if err != nil {
|
|
|
|
return rtn, err
|
|
|
|
}
|
|
|
|
rtn.Remote = rrNew
|
2022-12-28 22:56:19 +01:00
|
|
|
}
|
|
|
|
if !rtn.Remote.RState.IsConnected() {
|
|
|
|
return rtn, fmt.Errorf("remote %q is not connected", rtn.Remote.DisplayName)
|
2022-08-27 01:24:07 +02:00
|
|
|
}
|
2022-11-29 03:03:02 +01:00
|
|
|
if rtn.Remote.StatePtr == nil || rtn.Remote.FeState == nil {
|
2022-12-28 22:56:19 +01:00
|
|
|
return rtn, fmt.Errorf("remote %q state is not available", rtn.Remote.DisplayName)
|
2022-08-27 01:24:07 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return rtn, nil
|
|
|
|
}
|
|
|
|
|
2022-08-27 02:29:32 +02:00
|
|
|
func resolveSessionScreen(ctx context.Context, sessionId string, screenArg string, curScreenArg string) (*ResolveItem, error) {
|
2022-12-26 21:38:47 +01:00
|
|
|
screens, err := sstore.GetBareSessionScreens(ctx, sessionId)
|
2022-08-27 01:24:07 +02:00
|
|
|
if err != nil {
|
2022-10-07 10:08:03 +02:00
|
|
|
return nil, fmt.Errorf("could not retreive screens for session=%s: %v", sessionId, err)
|
2022-08-27 01:24:07 +02:00
|
|
|
}
|
2022-08-27 02:29:32 +02:00
|
|
|
ritems := screensToResolveItems(screens)
|
2022-10-07 08:58:38 +02:00
|
|
|
return genericResolve(screenArg, curScreenArg, ritems, false, "screen")
|
2022-08-27 01:24:07 +02:00
|
|
|
}
|
|
|
|
|
2022-12-27 01:09:21 +01:00
|
|
|
func resolveSession(ctx context.Context, sessionArg string, curSessionArg string) (*ResolveItem, error) {
|
|
|
|
bareSessions, err := sstore.GetBareSessions(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
ritems := sessionsToResolveItems(bareSessions)
|
|
|
|
ritem, err := genericResolve(sessionArg, curSessionArg, ritems, false, "session")
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return ritem, nil
|
|
|
|
}
|
|
|
|
|
2022-10-07 10:08:03 +02:00
|
|
|
func resolveLine(ctx context.Context, sessionId string, windowId string, lineArg string, curLineArg string) (*ResolveItem, error) {
|
|
|
|
lines, err := sstore.GetLineResolveItems(ctx, sessionId, windowId)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("could not get lines: %v", err)
|
|
|
|
}
|
|
|
|
return genericResolve(lineArg, curLineArg, lines, true, "line")
|
|
|
|
}
|
|
|
|
|
2022-08-27 01:24:07 +02:00
|
|
|
func getSessionIds(sarr []*sstore.SessionType) []string {
|
|
|
|
rtn := make([]string, len(sarr))
|
|
|
|
for idx, s := range sarr {
|
|
|
|
rtn[idx] = s.SessionId
|
|
|
|
}
|
|
|
|
return rtn
|
|
|
|
}
|
|
|
|
|
|
|
|
var partialUUIDRe = regexp.MustCompile("^[0-9a-f]{8}$")
|
|
|
|
|
|
|
|
func isPartialUUID(s string) bool {
|
|
|
|
return partialUUIDRe.MatchString(s)
|
|
|
|
}
|
|
|
|
|
2022-10-07 10:08:03 +02:00
|
|
|
func isUUID(s string) bool {
|
|
|
|
_, err := uuid.Parse(s)
|
|
|
|
return err == nil
|
|
|
|
}
|
|
|
|
|
2022-10-07 08:58:38 +02:00
|
|
|
func getResolveItemById(id string, items []ResolveItem) *ResolveItem {
|
|
|
|
if id == "" {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
for _, item := range items {
|
|
|
|
if item.Id == id {
|
|
|
|
return &item
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func genericResolve(arg string, curArg string, items []ResolveItem, isNumeric bool, typeStr string) (*ResolveItem, error) {
|
|
|
|
if len(items) == 0 || arg == "" {
|
|
|
|
return nil, nil
|
|
|
|
}
|
2022-08-27 02:17:33 +02:00
|
|
|
var curId string
|
|
|
|
if curArg != "" {
|
2022-10-07 08:58:38 +02:00
|
|
|
curItem, _ := genericResolve(curArg, "", items, isNumeric, typeStr)
|
2022-08-27 02:17:33 +02:00
|
|
|
if curItem != nil {
|
|
|
|
curId = curItem.Id
|
2022-08-27 01:24:07 +02:00
|
|
|
}
|
|
|
|
}
|
2022-10-07 08:58:38 +02:00
|
|
|
rtnItem := resolveByPosition(isNumeric, items, curId, arg)
|
2022-08-27 02:17:33 +02:00
|
|
|
if rtnItem != nil {
|
|
|
|
return rtnItem, nil
|
2022-08-27 01:24:07 +02:00
|
|
|
}
|
2022-10-07 10:08:03 +02:00
|
|
|
isUuid := isUUID(arg)
|
2022-08-27 02:17:33 +02:00
|
|
|
tryPuid := isPartialUUID(arg)
|
|
|
|
var prefixMatches []ResolveItem
|
|
|
|
for _, item := range items {
|
2022-10-07 10:08:03 +02:00
|
|
|
if (isUuid && item.Id == arg) || (tryPuid && strings.HasPrefix(item.Id, arg)) {
|
2022-08-27 02:17:33 +02:00
|
|
|
return &item, nil
|
2022-08-27 01:24:07 +02:00
|
|
|
}
|
2022-12-26 21:38:47 +01:00
|
|
|
if item.Name != "" {
|
2022-10-07 08:58:38 +02:00
|
|
|
if item.Name == arg {
|
|
|
|
return &item, nil
|
|
|
|
}
|
2022-12-26 21:38:47 +01:00
|
|
|
if !item.Hidden && strings.HasPrefix(item.Name, arg) {
|
2022-10-07 08:58:38 +02:00
|
|
|
prefixMatches = append(prefixMatches, item)
|
|
|
|
}
|
2022-08-27 01:24:07 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(prefixMatches) == 1 {
|
2022-08-27 02:17:33 +02:00
|
|
|
return &prefixMatches[0], nil
|
2022-08-27 01:24:07 +02:00
|
|
|
}
|
|
|
|
if len(prefixMatches) > 1 {
|
2022-08-27 02:17:33 +02:00
|
|
|
return nil, fmt.Errorf("could not resolve %s '%s', ambiguious prefix matched multiple %ss: %s", typeStr, arg, typeStr, formatStrs(itemNames(prefixMatches), "and", true))
|
2022-08-27 01:24:07 +02:00
|
|
|
}
|
2022-08-27 02:17:33 +02:00
|
|
|
return nil, fmt.Errorf("could not resolve %s '%s' (name/id/pos not found)", typeStr, arg)
|
2022-08-27 01:24:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func resolveSessionId(pk *scpacket.FeCommandPacketType) (string, error) {
|
|
|
|
sessionId := pk.Kwargs["session"]
|
|
|
|
if sessionId == "" {
|
|
|
|
return "", nil
|
|
|
|
}
|
|
|
|
if _, err := uuid.Parse(sessionId); err != nil {
|
|
|
|
return "", fmt.Errorf("invalid sessionid '%s'", sessionId)
|
|
|
|
}
|
|
|
|
return sessionId, nil
|
|
|
|
}
|
|
|
|
|
2022-09-06 05:08:59 +02:00
|
|
|
func resolveWindowArg(sessionId string, screenId string, windowArg string) (string, error) {
|
|
|
|
if windowArg == "" {
|
2022-08-27 01:24:07 +02:00
|
|
|
return "", nil
|
|
|
|
}
|
2022-09-06 05:08:59 +02:00
|
|
|
if _, err := uuid.Parse(windowArg); err != nil {
|
|
|
|
return "", fmt.Errorf("invalid window arg specified (must be windowid) '%s'", windowArg)
|
2022-08-27 01:24:07 +02:00
|
|
|
}
|
2022-09-06 05:08:59 +02:00
|
|
|
return windowArg, nil
|
2022-08-27 01:24:07 +02:00
|
|
|
}
|
|
|
|
|
2022-10-07 03:33:54 +02:00
|
|
|
func resolveSessionArg(sessionArg string) (string, error) {
|
|
|
|
if sessionArg == "" {
|
|
|
|
return "", nil
|
|
|
|
}
|
|
|
|
if _, err := uuid.Parse(sessionArg); err != nil {
|
|
|
|
return "", fmt.Errorf("invalid session arg specified (must be sessionid) '%s'", sessionArg)
|
|
|
|
}
|
|
|
|
return sessionArg, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func resolveScreenArg(sessionId string, screenArg string) (string, error) {
|
|
|
|
if screenArg == "" {
|
|
|
|
return "", nil
|
|
|
|
}
|
|
|
|
if _, err := uuid.Parse(screenArg); err != nil {
|
2022-12-24 00:56:29 +01:00
|
|
|
return "", fmt.Errorf("invalid screen arg specified (must be screenid) '%s'", screenArg)
|
2022-10-07 03:33:54 +02:00
|
|
|
}
|
|
|
|
return screenArg, nil
|
|
|
|
}
|
|
|
|
|
2022-08-27 01:24:07 +02:00
|
|
|
func resolveScreenId(ctx context.Context, pk *scpacket.FeCommandPacketType, sessionId string) (string, error) {
|
|
|
|
screenArg := pk.Kwargs["screen"]
|
|
|
|
if screenArg == "" {
|
|
|
|
return "", nil
|
|
|
|
}
|
|
|
|
if _, err := uuid.Parse(screenArg); err == nil {
|
|
|
|
return screenArg, nil
|
|
|
|
}
|
|
|
|
if sessionId == "" {
|
|
|
|
return "", fmt.Errorf("cannot resolve screen without session")
|
|
|
|
}
|
2022-08-27 02:29:32 +02:00
|
|
|
ritem, err := resolveSessionScreen(ctx, sessionId, screenArg, "")
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
return ritem.Id, nil
|
2022-08-27 01:24:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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]
|
|
|
|
}
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2022-08-30 01:31:06 +02:00
|
|
|
func resolveRemoteFromPtr(ctx context.Context, rptr *sstore.RemotePtrType, sessionId string, windowId string) (*ResolvedRemote, error) {
|
|
|
|
if rptr == nil || rptr.RemoteId == "" {
|
2022-09-14 21:56:05 +02:00
|
|
|
return nil, nil
|
2022-08-30 01:31:06 +02:00
|
|
|
}
|
|
|
|
msh := remote.GetRemoteById(rptr.RemoteId)
|
|
|
|
if msh == nil {
|
|
|
|
return nil, fmt.Errorf("invalid remote '%s', not found", rptr.RemoteId)
|
|
|
|
}
|
|
|
|
rstate := msh.GetRemoteRuntimeState()
|
2022-10-04 04:04:48 +02:00
|
|
|
rcopy := msh.GetRemoteCopy()
|
2022-08-30 01:31:06 +02:00
|
|
|
displayName := rstate.GetDisplayName(rptr)
|
2022-09-14 21:56:05 +02:00
|
|
|
rtn := &ResolvedRemote{
|
2022-08-30 01:31:06 +02:00
|
|
|
DisplayName: displayName,
|
|
|
|
RemotePtr: *rptr,
|
|
|
|
RState: rstate,
|
|
|
|
MShell: msh,
|
2022-10-04 04:04:48 +02:00
|
|
|
RemoteCopy: &rcopy,
|
2022-11-29 03:03:02 +01:00
|
|
|
StatePtr: nil,
|
|
|
|
FeState: nil,
|
2022-09-14 21:56:05 +02:00
|
|
|
}
|
|
|
|
if sessionId != "" && windowId != "" {
|
2022-11-29 03:03:02 +01:00
|
|
|
ri, err := sstore.GetRemoteInstance(ctx, sessionId, windowId, *rptr)
|
2022-09-14 21:56:05 +02:00
|
|
|
if err != nil {
|
2022-11-29 03:03:02 +01:00
|
|
|
log.Printf("ERROR resolving remote state '%s': %v\n", displayName, err)
|
|
|
|
// continue with state set to nil
|
|
|
|
} else {
|
|
|
|
if ri == nil {
|
|
|
|
rtn.StatePtr = msh.GetDefaultStatePtr()
|
|
|
|
rtn.FeState = msh.GetDefaultFeState()
|
|
|
|
} else {
|
|
|
|
rtn.StatePtr = &sstore.ShellStatePtr{BaseHash: ri.StateBaseHash, DiffHashArr: ri.StateDiffHashArr}
|
|
|
|
rtn.FeState = &ri.FeState
|
|
|
|
}
|
2022-09-14 21:56:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return rtn, nil
|
2022-08-30 01:31:06 +02:00
|
|
|
}
|
|
|
|
|
2022-08-27 01:24:07 +02:00
|
|
|
// returns (remoteDisplayName, remoteptr, state, rstate, err)
|
2022-11-28 09:13:00 +01:00
|
|
|
func resolveRemote(ctx context.Context, fullRemoteRef string, sessionId string, windowId string) (string, *sstore.RemotePtrType, *remote.RemoteRuntimeState, error) {
|
2022-08-27 01:24:07 +02:00
|
|
|
if fullRemoteRef == "" {
|
2022-11-28 09:13:00 +01:00
|
|
|
return "", nil, nil, nil
|
2022-08-27 01:24:07 +02:00
|
|
|
}
|
|
|
|
userRef, remoteRef, remoteName, err := parseFullRemoteRef(fullRemoteRef)
|
|
|
|
if err != nil {
|
2022-11-28 09:13:00 +01:00
|
|
|
return "", nil, nil, err
|
2022-08-27 01:24:07 +02:00
|
|
|
}
|
|
|
|
if userRef != "" {
|
2022-11-28 09:13:00 +01:00
|
|
|
return "", nil, nil, fmt.Errorf("invalid remote '%s', cannot resolve remote userid '%s'", fullRemoteRef, userRef)
|
2022-08-27 01:24:07 +02:00
|
|
|
}
|
|
|
|
rstate := remote.ResolveRemoteRef(remoteRef)
|
|
|
|
if rstate == nil {
|
2022-11-28 09:13:00 +01:00
|
|
|
return "", nil, nil, fmt.Errorf("cannot resolve remote '%s': not found", fullRemoteRef)
|
2022-08-27 01:24:07 +02:00
|
|
|
}
|
|
|
|
rptr := sstore.RemotePtrType{RemoteId: rstate.RemoteId, Name: remoteName}
|
|
|
|
rname := rstate.RemoteCanonicalName
|
|
|
|
if rstate.RemoteAlias != "" {
|
|
|
|
rname = rstate.RemoteAlias
|
|
|
|
}
|
|
|
|
if rptr.Name != "" {
|
|
|
|
rname = fmt.Sprintf("%s:%s", rname, rptr.Name)
|
|
|
|
}
|
2022-11-28 09:13:00 +01:00
|
|
|
return rname, &rptr, rstate, nil
|
2022-08-27 01:24:07 +02:00
|
|
|
}
|