update termopts for running commands, send specialinput packet

This commit is contained in:
sawka
2022-09-05 20:08:59 -07:00
parent 54d2f5d761
commit 2b7045443d
6 changed files with 122 additions and 13 deletions
+56
View File
@@ -80,6 +80,8 @@ func init() {
registerCmdFn("remote:disconnect", RemoteDisconnectCommand)
registerCmdFn("remote:connect", RemoteConnectCommand)
registerCmdFn("window:resize", WindowResizeCommand)
registerCmdFn("history", HistoryCommand)
}
@@ -1123,3 +1125,57 @@ func splitLinesForInfo(str string) []string {
}
return rtn
}
func resizeRunningCommand(ctx context.Context, cmd *sstore.CmdType, newCols int) error {
fmt.Printf("resize running cmd %s/%s %d => %d\n", cmd.SessionId, cmd.CmdId, cmd.TermOpts.Cols, newCols)
siPk := packet.MakeSpecialInputPacket()
siPk.CK = base.MakeCommandKey(cmd.SessionId, cmd.CmdId)
siPk.WinSize = &packet.WinSize{Rows: int(cmd.TermOpts.Rows), Cols: newCols}
msh := remote.GetRemoteById(cmd.Remote.RemoteId)
if msh == nil {
return fmt.Errorf("cannot resize, cmd remote not found")
}
err := msh.SendSpecialInput(siPk)
if err != nil {
return err
}
newTermOpts := cmd.TermOpts
newTermOpts.Cols = int64(newCols)
err = sstore.UpdateCmdTermOpts(ctx, cmd.SessionId, cmd.CmdId, newTermOpts)
if err != nil {
return err
}
return nil
}
func WindowResizeCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
ids, err := resolveUiIds(ctx, pk, R_Session|R_Screen|R_Window)
if err != nil {
return nil, err
}
colsStr := pk.Kwargs["cols"]
if colsStr == "" {
return nil, fmt.Errorf("/window:resize requires a numeric 'cols' argument")
}
cols, err := strconv.Atoi(colsStr)
if err != nil {
return nil, fmt.Errorf("/window:resize requires a numeric 'cols' argument: %v", err)
}
if cols <= 0 {
return nil, fmt.Errorf("/window:resize invalid zero/negative 'cols' argument")
}
cols = base.BoundInt(cols, shexec.MinTermCols, shexec.MaxTermCols)
runningCmds, err := sstore.GetRunningWindowCmds(ctx, ids.SessionId, ids.WindowId)
if err != nil {
return nil, fmt.Errorf("/window:resize cannot get running commands: %v", err)
}
if len(runningCmds) == 0 {
return nil, nil
}
for _, cmd := range runningCmds {
if int(cmd.TermOpts.Cols) != cols {
resizeRunningCommand(ctx, cmd, cols)
}
}
return nil, nil
}
+14 -6
View File
@@ -137,6 +137,15 @@ func resolveUiIds(ctx context.Context, pk *scpacket.FeCommandPacketType, rtype i
}
}
}
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
}
}
if rtype&R_Session > 0 && rtn.SessionId == "" {
return rtn, fmt.Errorf("no session")
}
@@ -225,15 +234,14 @@ func resolveSessionId(pk *scpacket.FeCommandPacketType) (string, error) {
return sessionId, nil
}
func resolveWindowId(pk *scpacket.FeCommandPacketType, sessionId string) (string, error) {
windowId := pk.Kwargs["window"]
if windowId == "" {
func resolveWindowArg(sessionId string, screenId string, windowArg string) (string, error) {
if windowArg == "" {
return "", nil
}
if _, err := uuid.Parse(windowId); err != nil {
return "", fmt.Errorf("invalid windowid '%s'", windowId)
if _, err := uuid.Parse(windowArg); err != nil {
return "", fmt.Errorf("invalid window arg specified (must be windowid) '%s'", windowArg)
}
return windowId, nil
return windowArg, nil
}
func resolveScreenId(ctx context.Context, pk *scpacket.FeCommandPacketType, sessionId string) (string, error) {
+10
View File
@@ -540,6 +540,16 @@ func (msh *MShellProc) SendInput(dataPk *packet.DataPacketType) error {
return msh.ServerProc.Input.SendPacket(dataPk)
}
func (msh *MShellProc) SendSpecialInput(siPk *packet.SpecialInputPacketType) error {
if !msh.IsConnected() {
return fmt.Errorf("remote is not connected, cannot send input")
}
if !msh.IsCmdRunning(siPk.CK) {
return fmt.Errorf("cannot send input, cmd is not running")
}
return msh.ServerProc.Input.SendPacket(siPk)
}
func makeTermOpts(runPk *packet.RunPacketType) sstore.TermOpts {
return sstore.TermOpts{Rows: int64(runPk.TermOpts.Rows), Cols: int64(runPk.TermOpts.Cols), FlexRows: true, MaxPtySize: DefaultMaxPtySize}
}
+1 -1
View File
@@ -34,7 +34,7 @@ type FeInputPacketType struct {
Type string `json:"type"`
CK base.CommandKey `json:"ck"`
Remote sstore.RemotePtrType `json:"remote"`
InputData64 string `json:"inputdata"`
InputData64 string `json:"inputdata64"`
SigNum int `json:"signum,omitempty"`
WinSize *packet.WinSize `json:"winsize,omitempty"`
}
+16 -6
View File
@@ -217,23 +217,33 @@ func sendCmdInput(pk *scpacket.FeInputPacketType) error {
if pk.Remote.RemoteId == "" {
return fmt.Errorf("input must set remoteid")
}
msh := remote.GetRemoteById(pk.Remote.RemoteId)
if msh == nil {
return fmt.Errorf("remote %d not found", pk.Remote.RemoteId)
}
if len(pk.InputData64) > 0 {
inputLen := packet.B64DecodedLen(pk.InputData64)
if inputLen > MaxInputDataSize {
return fmt.Errorf("input data size too large, len=%d (max=%d)", inputLen, MaxInputDataSize)
}
msh := remote.GetRemoteById(pk.Remote.RemoteId)
if msh == nil {
return fmt.Errorf("remote %d not found", pk.Remote.RemoteId)
}
dataPk := packet.MakeDataPacket()
dataPk.CK = pk.CK
dataPk.FdNum = 0 // stdin
dataPk.Data64 = pk.InputData64
return msh.SendInput(dataPk)
err = msh.SendInput(dataPk)
if err != nil {
return err
}
}
if pk.SigNum != 0 || pk.WinSize != nil {
return fmt.Errorf("signum / winsize not supported")
siPk := packet.MakeSpecialInputPacket()
siPk.CK = pk.CK
siPk.SigNum = pk.SigNum
siPk.WinSize = pk.WinSize
err = msh.SendSpecialInput(siPk)
if err != nil {
return err
}
}
return nil
}
+25
View File
@@ -885,3 +885,28 @@ func ClearWindow(ctx context.Context, sessionId string, windowId string) (*Model
}
return &ModelUpdate{Window: win}, nil
}
func GetRunningWindowCmds(ctx context.Context, sessionId string, windowId string) ([]*CmdType, error) {
var rtn []*CmdType
txErr := WithTx(ctx, func(tx *TxWrap) error {
query := `SELECT * from cmd WHERE cmdid IN (SELECT cmdid FROM line WHERE sessionid = ? AND windowid = ?) AND status = ?`
cmdMaps := tx.SelectMaps(query, sessionId, windowId, CmdStatusRunning)
for _, m := range cmdMaps {
rtn = append(rtn, CmdFromMap(m))
}
return nil
})
if txErr != nil {
return nil, txErr
}
return rtn, nil
}
func UpdateCmdTermOpts(ctx context.Context, sessionId string, cmdId string, termOpts TermOpts) error {
txErr := WithTx(ctx, func(tx *TxWrap) error {
query := `UPDATE cmd SET termopts = ? WHERE sessionid = ? AND cmdid = ?`
tx.ExecWrap(query, termOpts, sessionId, cmdId)
return nil
})
return txErr
}