From 5fa65107c9573b4a3b437bde3206a32af7baa5c5 Mon Sep 17 00:00:00 2001 From: sawka Date: Wed, 18 Dec 2024 15:17:03 -0800 Subject: [PATCH 1/7] getNextActionId() util fn --- frontend/util/util.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/frontend/util/util.ts b/frontend/util/util.ts index 9af85bc26..450940667 100644 --- a/frontend/util/util.ts +++ b/frontend/util/util.ts @@ -287,6 +287,24 @@ function makeConnRoute(conn: string): string { return "conn:" + conn; } +let lastTimestamp = 0; +let counter = 0; + +// guaranteed to be monotonically increasing for each call within the same tab +function getNextActionId(): string { + const now = Date.now(); + + if (now === lastTimestamp) { + counter += 1; + } else { + lastTimestamp = now; + counter = 0; + } + + const paddedCounter = String(counter).padStart(5, "0"); + return `${now}:${paddedCounter}`; +} + export { atomWithDebounce, atomWithThrottle, @@ -295,6 +313,7 @@ export { boundNumber, countGraphemes, fireAndForget, + getNextActionId, getPrefixedSettings, getPromiseState, getPromiseValue, From d6af5be14d3ce1791fa6935e4f0e2ec1cc5bab76 Mon Sep 17 00:00:00 2001 From: sawka Date: Wed, 18 Dec 2024 15:34:02 -0800 Subject: [PATCH 2/7] disable bracketed paste mode. increase max for termscrollback to 50k --- docs/docs/config.mdx | 2 +- frontend/app/view/term/term.tsx | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/docs/docs/config.mdx b/docs/docs/config.mdx index 49cada776..e96d89902 100644 --- a/docs/docs/config.mdx +++ b/docs/docs/config.mdx @@ -43,7 +43,7 @@ wsh editconfig | term:localshellpath | string | set to override the default shell path for local terminals | | term:localshellopts | string[] | set to pass additional parameters to the term:localshellpath (example: `["-NoLogo"]` for PowerShell will remove the copyright notice) | | term:copyonselect | bool | set to false to disable terminal copy-on-select | -| term:scrollback | int | size of terminal scrollback buffer, max is 10000 | +| term:scrollback | int | size of terminal scrollback buffer, default is 2000, max is 50000 (setting this too high may cause performance issues) | | editor:minimapenabled | bool | set to false to disable editor minimap | | editor:stickyscrollenabled | bool | enables monaco editor's stickyScroll feature (pinning headers of current context, e.g. class names, method names, etc.), defaults to false | | editor:wordwrap | bool | set to true to enable word wrapping in the editor (defaults to false) | diff --git a/frontend/app/view/term/term.tsx b/frontend/app/view/term/term.tsx index a834adfd5..b3b6198f1 100644 --- a/frontend/app/view/term/term.tsx +++ b/frontend/app/view/term/term.tsx @@ -24,6 +24,7 @@ import { } from "@/store/global"; import * as services from "@/store/services"; import * as keyutil from "@/util/keyutil"; +import { boundNumber } from "@/util/util"; import clsx from "clsx"; import debug from "debug"; import * as jotai from "jotai"; @@ -735,19 +736,14 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => { const fullConfig = globalStore.get(atoms.fullConfigAtom); const termThemeName = globalStore.get(model.termThemeNameAtom); const [termTheme, _] = computeTheme(fullConfig, termThemeName); - let termScrollback = 1000; + let termScrollback = 2000; if (termSettings?.["term:scrollback"]) { termScrollback = Math.floor(termSettings["term:scrollback"]); } if (blockData?.meta?.["term:scrollback"]) { termScrollback = Math.floor(blockData.meta["term:scrollback"]); } - if (termScrollback < 0) { - termScrollback = 0; - } - if (termScrollback > 10000) { - termScrollback = 10000; - } + termScrollback = boundNumber(termScrollback, 0, 50000); const wasFocused = model.termRef.current != null && globalStore.get(model.nodeModel.isFocused); const termWrap = new TermWrap( blockId, @@ -761,6 +757,7 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => { fontWeightBold: "bold", allowTransparency: true, scrollback: termScrollback, + ignoreBracketedPasteMode: true, }, { keydownHandler: model.handleTerminalKeydown.bind(model), From aee35f0e01fba095765af8bb5d2bff68793184ec Mon Sep 17 00:00:00 2001 From: sawka Date: Wed, 18 Dec 2024 15:34:40 -0800 Subject: [PATCH 3/7] fix indentation --- pkg/wconfig/defaultconfig/settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/wconfig/defaultconfig/settings.json b/pkg/wconfig/defaultconfig/settings.json index fa8d98f88..983490a11 100644 --- a/pkg/wconfig/defaultconfig/settings.json +++ b/pkg/wconfig/defaultconfig/settings.json @@ -7,7 +7,7 @@ "autoupdate:installonquit": true, "autoupdate:intervalms": 3600000, "conn:askbeforewshinstall": true, - "conn:wshenabled": true, + "conn:wshenabled": true, "editor:minimapenabled": true, "web:defaulturl": "https://github.com/wavetermdev/waveterm", "web:defaultsearch": "https://www.google.com/search?q={query}", From e6315658e185485cad4422c69ff19bb0d45fd636 Mon Sep 17 00:00:00 2001 From: sawka Date: Thu, 19 Dec 2024 09:44:29 -0800 Subject: [PATCH 4/7] serialize (w/ actionid) the resize events --- frontend/app/view/term/termwrap.ts | 58 +++++++++++++++++-------- frontend/types/gotypes.d.ts | 2 + pkg/blockcontroller/blockcontroller.go | 60 ++++++++++++++++---------- pkg/wshrpc/wshrpctypes.go | 10 +++-- pkg/wshrpc/wshserver/wshserver.go | 5 ++- 5 files changed, 88 insertions(+), 47 deletions(-) diff --git a/frontend/app/view/term/termwrap.ts b/frontend/app/view/term/termwrap.ts index 0ab2ea634..ab845c496 100644 --- a/frontend/app/view/term/termwrap.ts +++ b/frontend/app/view/term/termwrap.ts @@ -46,6 +46,7 @@ type TermWrapOptions = { export class TermWrap { blockId: string; ptyOffset: number; + pendingPtyOffset: number; dataBytesProcessed: number; terminal: Terminal; connectElem: HTMLDivElement; @@ -56,6 +57,7 @@ export class TermWrap { heldData: Uint8Array[]; handleResize_debounced: () => void; hasResized: boolean; + isLoadingCache: boolean; constructor( blockId: string, @@ -64,6 +66,7 @@ export class TermWrap { waveOptions: TermWrapOptions ) { this.loaded = false; + this.isLoadingCache = false; this.blockId = blockId; this.ptyOffset = 0; this.dataBytesProcessed = 0; @@ -165,11 +168,20 @@ export class TermWrap { } handleTermData(data: string) { + if (this.isLoadingCache) { + return; + } if (!this.loaded) { return; } const b64data = util.stringToBase64(data); - RpcApi.ControllerInputCommand(TabRpcClient, { blockid: this.blockId, inputdata64: b64data }); + const actionId = util.getNextActionId(); + RpcApi.ControllerInputCommand(TabRpcClient, { + blockid: this.blockId, + inputdata64: b64data, + feactionid: actionId, + pendingptyoffset: this.pendingPtyOffset, + }); } addFocusListener(focusFn: () => void) { @@ -198,11 +210,14 @@ export class TermWrap { let prtn = new Promise((presolve, _) => { resolve = presolve; }); + if (setPtyOffset != null) { + this.pendingPtyOffset = setPtyOffset; + } else { + this.pendingPtyOffset = this.ptyOffset + data.length; + } this.terminal.write(data, () => { - if (setPtyOffset != null) { - this.ptyOffset = setPtyOffset; - } else { - this.ptyOffset += data.length; + this.ptyOffset = this.pendingPtyOffset; + if (setPtyOffset == null) { this.dataBytesProcessed += data.length; } resolve(); @@ -217,20 +232,25 @@ export class TermWrap { if (cacheFile != null) { ptyOffset = cacheFile.meta["ptyoffset"] ?? 0; if (cacheData.byteLength > 0) { - const curTermSize: TermSize = { rows: this.terminal.rows, cols: this.terminal.cols }; - const fileTermSize: TermSize = cacheFile.meta["termsize"]; - let didResize = false; - if ( - fileTermSize != null && - (fileTermSize.rows != curTermSize.rows || fileTermSize.cols != curTermSize.cols) - ) { - console.log("terminal restore size mismatch, temp resize", fileTermSize, curTermSize); - this.terminal.resize(fileTermSize.cols, fileTermSize.rows); - didResize = true; - } - this.doTerminalWrite(cacheData, ptyOffset); - if (didResize) { - this.terminal.resize(curTermSize.cols, curTermSize.rows); + try { + this.isLoadingCache = true; + const curTermSize: TermSize = { rows: this.terminal.rows, cols: this.terminal.cols }; + const fileTermSize: TermSize = cacheFile.meta["termsize"]; + let didResize = false; + if ( + fileTermSize != null && + (fileTermSize.rows != curTermSize.rows || fileTermSize.cols != curTermSize.cols) + ) { + console.log("terminal restore size mismatch, temp resize", fileTermSize, curTermSize); + this.terminal.resize(fileTermSize.cols, fileTermSize.rows); + didResize = true; + } + await this.doTerminalWrite(cacheData, ptyOffset); + if (didResize) { + this.terminal.resize(curTermSize.cols, curTermSize.rows); + } + } finally { + this.isLoadingCache = false; } } } diff --git a/frontend/types/gotypes.d.ts b/frontend/types/gotypes.d.ts index c0149d01e..4a893746b 100644 --- a/frontend/types/gotypes.d.ts +++ b/frontend/types/gotypes.d.ts @@ -116,6 +116,8 @@ declare global { blockid: string; inputdata64?: string; signame?: string; + pendingptyoffset?: number; + feactionid?: string; termsize?: TermSize; }; diff --git a/pkg/blockcontroller/blockcontroller.go b/pkg/blockcontroller/blockcontroller.go index 35d32eb68..083175d23 100644 --- a/pkg/blockcontroller/blockcontroller.go +++ b/pkg/blockcontroller/blockcontroller.go @@ -62,24 +62,27 @@ var globalLock = &sync.Mutex{} var blockControllerMap = make(map[string]*BlockController) type BlockInputUnion struct { - InputData []byte `json:"inputdata,omitempty"` - SigName string `json:"signame,omitempty"` - TermSize *waveobj.TermSize `json:"termsize,omitempty"` + InputData []byte `json:"inputdata,omitempty"` + SigName string `json:"signame,omitempty"` + TermSize *waveobj.TermSize `json:"termsize,omitempty"` + FeActionId string `json:"feactionid,omitempty"` } type BlockController struct { - Lock *sync.Mutex - ControllerType string - TabId string - BlockId string - BlockDef *waveobj.BlockDef - CreatedHtmlFile bool - ShellProc *shellexec.ShellProc - ShellInputCh chan *BlockInputUnion - ShellProcStatus string - ShellProcExitCode int - RunLock *atomic.Bool - StatusVersion int + Lock *sync.Mutex + ControllerType string + TabId string + BlockId string + BlockDef *waveobj.BlockDef + CreatedHtmlFile bool + ShellProc *shellexec.ShellProc + ShellInputCh chan *BlockInputUnion + ShellProcStatus string + ShellProcExitCode int + RunLock *atomic.Bool + StatusVersion int + ProcessedToOffset int64 + LastResizeActionId string } type BlockControllerRuntimeStatus struct { @@ -117,6 +120,16 @@ func (bc *BlockController) getShellProc() *shellexec.ShellProc { return bc.ShellProc } +func (bc *BlockController) TestAndSetResizeActionId(actionId string) bool { + bc.Lock.Lock() + defer bc.Lock.Unlock() + if actionId <= bc.LastResizeActionId { + return false + } + bc.LastResizeActionId = actionId + return true +} + type RunShellOpts struct { TermSize waveobj.TermSize `json:"termsize,omitempty"` } @@ -469,13 +482,16 @@ func (bc *BlockController) DoRunShellCommand(rc *RunShellOpts, blockMeta waveobj shellProc.Cmd.Write(ic.InputData) } if ic.TermSize != nil { - err = setTermSize(ctx, bc.BlockId, *ic.TermSize) - if err != nil { - log.Printf("error setting pty size: %v\n", err) - } - err = shellProc.Cmd.SetSize(ic.TermSize.Rows, ic.TermSize.Cols) - if err != nil { - log.Printf("error setting pty size: %v\n", err) + ok := bc.TestAndSetResizeActionId(ic.FeActionId) + if ok { + err = setTermSize(ctx, bc.BlockId, *ic.TermSize) + if err != nil { + log.Printf("error setting pty size: %v\n", err) + } + err = shellProc.Cmd.SetSize(ic.TermSize.Rows, ic.TermSize.Cols) + if err != nil { + log.Printf("error setting pty size: %v\n", err) + } } } } diff --git a/pkg/wshrpc/wshrpctypes.go b/pkg/wshrpc/wshrpctypes.go index 71806f6b0..077af53b0 100644 --- a/pkg/wshrpc/wshrpctypes.go +++ b/pkg/wshrpc/wshrpctypes.go @@ -312,10 +312,12 @@ type CommandControllerResyncData struct { } type CommandBlockInputData struct { - BlockId string `json:"blockid" wshcontext:"BlockId"` - InputData64 string `json:"inputdata64,omitempty"` - SigName string `json:"signame,omitempty"` - TermSize *waveobj.TermSize `json:"termsize,omitempty"` + BlockId string `json:"blockid" wshcontext:"BlockId"` + InputData64 string `json:"inputdata64,omitempty"` + SigName string `json:"signame,omitempty"` + PendingPtyOffset int64 `json:"pendingptyoffset,omitempty"` + FeActionId string `json:"feactionid,omitempty"` + TermSize *waveobj.TermSize `json:"termsize,omitempty"` } type CommandFileDataAt struct { diff --git a/pkg/wshrpc/wshserver/wshserver.go b/pkg/wshrpc/wshserver/wshserver.go index b4e2acfec..56dbc58cf 100644 --- a/pkg/wshrpc/wshserver/wshserver.go +++ b/pkg/wshrpc/wshserver/wshserver.go @@ -242,8 +242,9 @@ func (ws *WshServer) ControllerInputCommand(ctx context.Context, data wshrpc.Com return fmt.Errorf("block controller not found for block %q", data.BlockId) } inputUnion := &blockcontroller.BlockInputUnion{ - SigName: data.SigName, - TermSize: data.TermSize, + SigName: data.SigName, + TermSize: data.TermSize, + FeActionId: data.FeActionId, } if len(data.InputData64) > 0 { inputBuf := make([]byte, base64.StdEncoding.DecodedLen(len(data.InputData64))) From 1233eecd1644cd1b1e743eab2f31e6474e821464 Mon Sep 17 00:00:00 2001 From: sawka Date: Fri, 14 Feb 2025 13:54:16 -0800 Subject: [PATCH 5/7] fix double input --- frontend/app/view/term/term.tsx | 10 ++++++++-- frontend/app/view/term/termwrap.ts | 9 --------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/frontend/app/view/term/term.tsx b/frontend/app/view/term/term.tsx index ceb558e12..4b8ebc04d 100644 --- a/frontend/app/view/term/term.tsx +++ b/frontend/app/view/term/term.tsx @@ -26,7 +26,7 @@ import { } from "@/store/global"; import * as services from "@/store/services"; import * as keyutil from "@/util/keyutil"; -import { boundNumber, fireAndForget, stringToBase64, useAtomValueSafe } from "@/util/util"; +import { boundNumber, fireAndForget, getNextActionId, stringToBase64, useAtomValueSafe } from "@/util/util"; import { computeBgStyleFromMeta } from "@/util/waveutil"; import { ISearchOptions } from "@xterm/addon-search"; import clsx from "clsx"; @@ -350,7 +350,13 @@ class TermViewModel implements ViewModel { sendDataToController(data: string) { const b64data = stringToBase64(data); - RpcApi.ControllerInputCommand(TabRpcClient, { blockid: this.blockId, inputdata64: b64data }); + const actionId = getNextActionId(); + RpcApi.ControllerInputCommand(TabRpcClient, { + blockid: this.blockId, + inputdata64: b64data, + feactionid: actionId, + pendingptyoffset: this.termRef.current.pendingPtyOffset, + }); } setTermMode(mode: "term" | "vdom") { diff --git a/frontend/app/view/term/termwrap.ts b/frontend/app/view/term/termwrap.ts index 55734f638..42c3b46d9 100644 --- a/frontend/app/view/term/termwrap.ts +++ b/frontend/app/view/term/termwrap.ts @@ -7,7 +7,6 @@ import { RpcApi } from "@/app/store/wshclientapi"; import { TabRpcClient } from "@/app/store/wshrpcutil"; import { PLATFORM, WOS, atoms, fetchWaveFile, getSettingsKeyAtom, globalStore, openLink } from "@/store/global"; import * as services from "@/store/services"; -import * as util from "@/util/util"; import { base64ToArray, fireAndForget } from "@/util/util"; import { SearchAddon } from "@xterm/addon-search"; import { SerializeAddon } from "@xterm/addon-serialize"; @@ -269,14 +268,6 @@ export class TermWrap { if (!this.loaded) { return; } - const b64data = util.stringToBase64(data); - const actionId = util.getNextActionId(); - RpcApi.ControllerInputCommand(TabRpcClient, { - blockid: this.blockId, - inputdata64: b64data, - feactionid: actionId, - pendingptyoffset: this.pendingPtyOffset, - }); this.sendDataHandler?.(data); } From f0546dbeade5e110bdf960a27eabb2114c6e5468 Mon Sep 17 00:00:00 2001 From: sawka Date: Fri, 14 Feb 2025 15:39:18 -0800 Subject: [PATCH 6/7] fix resize, remove wscmd --- frontend/app/view/term/termwrap.ts | 12 ++++---- frontend/types/gotypes.d.ts | 16 +--------- pkg/blockcontroller/blockcontroller.go | 2 ++ pkg/web/webcmd/webcmd.go | 41 +------------------------- pkg/web/ws.go | 35 ---------------------- 5 files changed, 10 insertions(+), 96 deletions(-) diff --git a/frontend/app/view/term/termwrap.ts b/frontend/app/view/term/termwrap.ts index 42c3b46d9..3cca779b6 100644 --- a/frontend/app/view/term/termwrap.ts +++ b/frontend/app/view/term/termwrap.ts @@ -2,12 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 import { getFileSubject } from "@/app/store/wps"; -import { sendWSCommand } from "@/app/store/ws"; import { RpcApi } from "@/app/store/wshclientapi"; import { TabRpcClient } from "@/app/store/wshrpcutil"; import { PLATFORM, WOS, atoms, fetchWaveFile, getSettingsKeyAtom, globalStore, openLink } from "@/store/global"; import * as services from "@/store/services"; -import { base64ToArray, fireAndForget } from "@/util/util"; +import { base64ToArray, fireAndForget, getNextActionId } from "@/util/util"; import { SearchAddon } from "@xterm/addon-search"; import { SerializeAddon } from "@xterm/addon-serialize"; import { WebLinksAddon } from "@xterm/addon-web-links"; @@ -377,12 +376,13 @@ export class TermWrap { this.fitAddon.fit(); if (oldRows !== this.terminal.rows || oldCols !== this.terminal.cols) { const termSize: TermSize = { rows: this.terminal.rows, cols: this.terminal.cols }; - const wsCommand: SetBlockTermSizeWSCommand = { - wscommand: "setblocktermsize", + const actionId = getNextActionId(); + RpcApi.ControllerInputCommand(TabRpcClient, { blockid: this.blockId, + feactionid: actionId, termsize: termSize, - }; - sendWSCommand(wsCommand); + pendingptyoffset: this.pendingPtyOffset, + }); } dlog("resize", `${this.terminal.rows}x${this.terminal.cols}`, `${oldRows}x${oldCols}`, this.hasResized); if (!this.hasResized) { diff --git a/frontend/types/gotypes.d.ts b/frontend/types/gotypes.d.ts index 7c5399a65..c73f54ea4 100644 --- a/frontend/types/gotypes.d.ts +++ b/frontend/types/gotypes.d.ts @@ -77,13 +77,6 @@ declare global { files: FileInfo[]; }; - // webcmd.BlockInputWSCommand - type BlockInputWSCommand = { - wscommand: "blockinput"; - blockid: string; - inputdata64: string; - }; - // waveobj.Client type Client = WaveObj & { windowids: string[]; @@ -671,13 +664,6 @@ declare global { winsize?: WinSize; }; - // webcmd.SetBlockTermSizeWSCommand - type SetBlockTermSizeWSCommand = { - wscommand: "setblocktermsize"; - blockid: string; - termsize: TermSize; - }; - // wconfig.SettingsType type SettingsType = { "app:*"?: boolean; @@ -1134,7 +1120,7 @@ declare global { type WSCommandType = { wscommand: string; - } & ( SetBlockTermSizeWSCommand | BlockInputWSCommand | WSRpcCommand ); + } & ( WSRpcCommand ); // eventbus.WSEventType type WSEventType = { diff --git a/pkg/blockcontroller/blockcontroller.go b/pkg/blockcontroller/blockcontroller.go index de5bde5d0..8d1905c62 100644 --- a/pkg/blockcontroller/blockcontroller.go +++ b/pkg/blockcontroller/blockcontroller.go @@ -747,6 +747,8 @@ func (bc *BlockController) manageRunningShellProcess(shellProc *shellexec.ShellP ok := bc.TestAndSetResizeActionId(ic.FeActionId) if ok { updateTermSize(shellProc, bc.BlockId, *ic.TermSize) + } else { + log.Printf("resize action id already processed or out of order: %s %s %v\n", bc.BlockId, ic.FeActionId, *ic.TermSize) } } } diff --git a/pkg/web/webcmd/webcmd.go b/pkg/web/webcmd/webcmd.go index bf732de0c..7f21c2f90 100644 --- a/pkg/web/webcmd/webcmd.go +++ b/pkg/web/webcmd/webcmd.go @@ -9,14 +9,11 @@ import ( "github.com/wavetermdev/waveterm/pkg/tsgen/tsgenmeta" "github.com/wavetermdev/waveterm/pkg/util/utilfn" - "github.com/wavetermdev/waveterm/pkg/waveobj" "github.com/wavetermdev/waveterm/pkg/wshutil" ) const ( - WSCommand_SetBlockTermSize = "setblocktermsize" - WSCommand_BlockInput = "blockinput" - WSCommand_Rpc = "rpc" + WSCommand_Rpc = "rpc" ) type WSCommandType interface { @@ -28,8 +25,6 @@ func WSCommandTypeUnionMeta() tsgenmeta.TypeUnionMeta { BaseType: reflect.TypeOf((*WSCommandType)(nil)).Elem(), TypeFieldName: "wscommand", Types: []reflect.Type{ - reflect.TypeOf(SetBlockTermSizeWSCommand{}), - reflect.TypeOf(BlockInputWSCommand{}), reflect.TypeOf(WSRpcCommand{}), }, } @@ -44,46 +39,12 @@ func (cmd *WSRpcCommand) GetWSCommand() string { return cmd.WSCommand } -type SetBlockTermSizeWSCommand struct { - WSCommand string `json:"wscommand" tstype:"\"setblocktermsize\""` - BlockId string `json:"blockid"` - TermSize waveobj.TermSize `json:"termsize"` -} - -func (cmd *SetBlockTermSizeWSCommand) GetWSCommand() string { - return cmd.WSCommand -} - -type BlockInputWSCommand struct { - WSCommand string `json:"wscommand" tstype:"\"blockinput\""` - BlockId string `json:"blockid"` - InputData64 string `json:"inputdata64"` -} - -func (cmd *BlockInputWSCommand) GetWSCommand() string { - return cmd.WSCommand -} - func ParseWSCommandMap(cmdMap map[string]any) (WSCommandType, error) { cmdType, ok := cmdMap["wscommand"].(string) if !ok { return nil, fmt.Errorf("no wscommand field in command map") } switch cmdType { - case WSCommand_SetBlockTermSize: - var cmd SetBlockTermSizeWSCommand - err := utilfn.DoMapStructure(&cmd, cmdMap) - if err != nil { - return nil, fmt.Errorf("error decoding SetBlockTermSizeWSCommand: %w", err) - } - return &cmd, nil - case WSCommand_BlockInput: - var cmd BlockInputWSCommand - err := utilfn.DoMapStructure(&cmd, cmdMap) - if err != nil { - return nil, fmt.Errorf("error decoding BlockInputWSCommand: %w", err) - } - return &cmd, nil case WSCommand_Rpc: var cmd WSRpcCommand err := utilfn.DoMapStructure(&cmd, cmdMap) diff --git a/pkg/web/ws.go b/pkg/web/ws.go index 41fa916fd..eaa294be6 100644 --- a/pkg/web/ws.go +++ b/pkg/web/ws.go @@ -19,7 +19,6 @@ import ( "github.com/wavetermdev/waveterm/pkg/eventbus" "github.com/wavetermdev/waveterm/pkg/panichandler" "github.com/wavetermdev/waveterm/pkg/web/webcmd" - "github.com/wavetermdev/waveterm/pkg/wshrpc" "github.com/wavetermdev/waveterm/pkg/wshutil" ) @@ -97,40 +96,6 @@ func processWSCommand(jmsg map[string]any, outputCh chan any, rpcInputCh chan [] return } switch cmd := wsCommand.(type) { - case *webcmd.SetBlockTermSizeWSCommand: - data := wshrpc.CommandBlockInputData{ - BlockId: cmd.BlockId, - TermSize: &cmd.TermSize, - } - rpcMsg := wshutil.RpcMessage{ - Command: wshrpc.Command_ControllerInput, - Data: data, - } - msgBytes, err := json.Marshal(rpcMsg) - if err != nil { - // this really should never fail since we just unmarshalled this value - log.Printf("[websocket] error marshalling rpc message: %v\n", err) - return - } - rpcInputCh <- msgBytes - - case *webcmd.BlockInputWSCommand: - data := wshrpc.CommandBlockInputData{ - BlockId: cmd.BlockId, - InputData64: cmd.InputData64, - } - rpcMsg := wshutil.RpcMessage{ - Command: wshrpc.Command_ControllerInput, - Data: data, - } - msgBytes, err := json.Marshal(rpcMsg) - if err != nil { - // this really should never fail since we just unmarshalled this value - log.Printf("[websocket] error marshalling rpc message: %v\n", err) - return - } - rpcInputCh <- msgBytes - case *webcmd.WSRpcCommand: rpcMsg := cmd.Message if rpcMsg == nil { From 8abb704348ac4a7487232b636d939e1fa9731d4b Mon Sep 17 00:00:00 2001 From: sawka Date: Fri, 14 Feb 2025 16:29:15 -0800 Subject: [PATCH 7/7] set up atomic for PtyProcessedToOffset, add to input union --- pkg/blockcontroller/blockcontroller.go | 35 ++++++++++++++++++-------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/pkg/blockcontroller/blockcontroller.go b/pkg/blockcontroller/blockcontroller.go index 8d1905c62..ea5b3d904 100644 --- a/pkg/blockcontroller/blockcontroller.go +++ b/pkg/blockcontroller/blockcontroller.go @@ -68,10 +68,11 @@ var globalLock = &sync.Mutex{} var blockControllerMap = make(map[string]*BlockController) type BlockInputUnion struct { - InputData []byte `json:"inputdata,omitempty"` - SigName string `json:"signame,omitempty"` - TermSize *waveobj.TermSize `json:"termsize,omitempty"` - FeActionId string `json:"feactionid,omitempty"` + InputData []byte `json:"inputdata,omitempty"` + SigName string `json:"signame,omitempty"` + TermSize *waveobj.TermSize `json:"termsize,omitempty"` + FeActionId string `json:"feactionid,omitempty"` + PtyProcessedToOffset int64 `json:"ptyprocessedtooffset,omitempty"` } type BlockController struct { @@ -87,7 +88,7 @@ type BlockController struct { ShellProcExitCode int RunLock *atomic.Bool StatusVersion int - ProcessedToOffset int64 + ProcessedToOffset *atomic.Int64 LastResizeActionId string } @@ -751,6 +752,17 @@ func (bc *BlockController) manageRunningShellProcess(shellProc *shellexec.ShellP log.Printf("resize action id already processed or out of order: %s %s %v\n", bc.BlockId, ic.FeActionId, *ic.TermSize) } } + if ic.PtyProcessedToOffset != 0 { + for { + curOffset := bc.ProcessedToOffset.Load() + if ic.PtyProcessedToOffset <= curOffset { + break + } + if bc.ProcessedToOffset.CompareAndSwap(curOffset, ic.PtyProcessedToOffset) { + break + } + } + } } }() go func() { @@ -1015,12 +1027,13 @@ func getOrCreateBlockController(tabId string, blockId string, controllerName str bc = blockControllerMap[blockId] if bc == nil { bc = &BlockController{ - Lock: &sync.Mutex{}, - ControllerType: controllerName, - TabId: tabId, - BlockId: blockId, - ShellProcStatus: Status_Init, - RunLock: &atomic.Bool{}, + Lock: &sync.Mutex{}, + ControllerType: controllerName, + TabId: tabId, + BlockId: blockId, + ShellProcStatus: Status_Init, + RunLock: &atomic.Bool{}, + ProcessedToOffset: &atomic.Int64{}, } blockControllerMap[blockId] = bc createdController = true