mirror of
https://github.com/wavetermdev/backup.git
synced 2026-08-05 13:57:07 -07:00
update termopts for running commands, send specialinput packet
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user