Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 1 addition & 48 deletions cmd/test/test-main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,53 +3,6 @@

package main

import (
"context"
"fmt"
"log"

"github.com/wavetermdev/waveterm/pkg/vdom"
"github.com/wavetermdev/waveterm/pkg/wshutil"
)

func Page(ctx context.Context, props map[string]any) any {
clicked, setClicked := vdom.UseState(ctx, false)
var clickedDiv *vdom.VDomElem
if clicked {
clickedDiv = vdom.Bind(`<div>clicked</div>`, nil)
}
clickFn := func() {
log.Printf("run clickFn\n")
setClicked(true)
}
return vdom.Bind(
`
<div>
<h1>hello world</h1>
<Button onClick="#bind:clickFn">hello</Button>
<bind key="clickedDiv"/>
</div>
`,
map[string]any{"clickFn": clickFn, "clickedDiv": clickedDiv},
)
}

func Button(ctx context.Context, props map[string]any) any {
ref := vdom.UseVDomRef(ctx)
clName, setClName := vdom.UseState(ctx, "button")
vdom.UseEffect(ctx, func() func() {
fmt.Printf("Button useEffect\n")
setClName("button mounted")
return nil
}, nil)
return vdom.Bind(`
<div className="#bind:clName" ref="#bind:ref" onClick="#bind:onClick">
<bind key="children"/>
</div>
`, map[string]any{"clName": clName, "ref": ref, "onClick": props["onClick"], "children": props["children"]})
}

func main() {
wshutil.SetTermRawModeAndInstallShutdownHandlers(true)
defer wshutil.RestoreTermState()

}
5 changes: 1 addition & 4 deletions cmd/wsh/cmd/wshcmd-root.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,7 @@ func OutputHelpMessage(cmd *cobra.Command) {
func preRunSetupRpcClient(cmd *cobra.Command, args []string) error {
jwtToken := os.Getenv(wshutil.WaveJwtTokenVarName)
if jwtToken == "" {
wshutil.SetTermRawModeAndInstallShutdownHandlers(true)
UsingTermWshMode = true
RpcClient, WrappedStdin = wshutil.SetupTerminalRpcClient(nil, "wshcmd-termclient")
return nil
return fmt.Errorf("wsh must be run inside a Wave-managed SSH session (WAVETERM_JWT not found)")
}
err := setupRpcClient(nil, jwtToken)
if err != nil {
Expand Down
65 changes: 0 additions & 65 deletions frontend/app/view/term/termwrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,68 +52,6 @@ type TermWrapOptions = {
nodeModel?: BlockNodeModel;
};

function handleOscWaveCommand(data: string, blockId: string, loaded: boolean): boolean {
if (!loaded) {
return true;
}
if (!data || data.length === 0) {
console.log("Invalid Wave OSC command received (empty)");
return true;
}

// Expected formats:
// "setmeta;{JSONDATA}"
// "setmeta;[wave-id];{JSONDATA}"
const parts = data.split(";");
if (parts[0] !== "setmeta") {
console.log("Invalid Wave OSC command received (bad command)", data);
return true;
}
let jsonPayload: string;
let waveId: string | undefined;
if (parts.length === 2) {
jsonPayload = parts[1];
} else if (parts.length >= 3) {
waveId = parts[1];
jsonPayload = parts.slice(2).join(";");
} else {
console.log("Invalid Wave OSC command received (1 part)", data);
return true;
}

let meta: any;
try {
meta = JSON.parse(jsonPayload);
} catch (e) {
console.error("Invalid JSON in Wave OSC command:", e);
return true;
}

if (waveId) {
// Resolve the wave id to an ORef using our ResolveIdsCommand.
fireAndForget(() => {
return RpcApi.ResolveIdsCommand(TabRpcClient, { blockid: blockId, ids: [waveId] })
.then((response: { resolvedids: { [key: string]: any } }) => {
const oref = response.resolvedids[waveId];
if (!oref) {
console.error("Failed to resolve wave id:", waveId);
return;
}
services.ObjectService.UpdateObjectMeta(oref, meta);
})
.catch((err: any) => {
console.error("Error resolving wave id", waveId, err);
});
});
} else {
// No wave id provided; update using the current block id.
fireAndForget(() => {
return services.ObjectService.UpdateObjectMeta(WOS.makeORef("block", blockId), meta);
});
}
return true;
}

// for xterm OSC handlers, we return true always because we "own" the OSC number.
// even if data is invalid we don't want to propagate to other handlers.
function handleOsc52Command(data: string, blockId: string, loaded: boolean, termWrap: TermWrap): boolean {
Expand Down Expand Up @@ -538,9 +476,6 @@ export class TermWrap {
this.terminal.parser.registerOscHandler(52, (data: string) => {
return handleOsc52Command(data, this.blockId, this.loaded, this);
});
this.terminal.parser.registerOscHandler(9283, (data: string) => {
return handleOscWaveCommand(data, this.blockId, this.loaded);
});
this.terminal.parser.registerOscHandler(16162, (data: string) => {
return handleOsc16162Command(data, this.blockId, this.loaded, this);
});
Expand Down
24 changes: 1 addition & 23 deletions pkg/blockcontroller/shellcontroller.go
Original file line number Diff line number Diff line change
Expand Up @@ -513,14 +513,6 @@ func (bc *ShellController) manageRunningShellProcess(shellProc *shellexec.ShellP
shellInputCh := make(chan *BlockInputUnion, 32)
bc.ShellInputCh = shellInputCh

// make esc sequence wshclient wshProxy
// we don't need to authenticate this wshProxy since it is coming direct
wshProxy := wshutil.MakeRpcProxy(fmt.Sprintf("controller:%s", bc.BlockId))
controllerLinkId, err := wshutil.DefaultRouter.RegisterTrustedLeaf(wshProxy, wshutil.MakeControllerRouteId(bc.BlockId))
if err != nil {
return fmt.Errorf("cannot register controller route: %w", err)
}
ptyBuffer := wshutil.MakePtyBuffer(wshutil.WaveOSCPrefix, shellProc.Cmd, wshProxy.FromRemoteCh)
go func() {
// handles regular output from the pty (goes to the blockfile and xterm)
defer func() {
Expand All @@ -546,7 +538,7 @@ func (bc *ShellController) manageRunningShellProcess(shellProc *shellexec.ShellP
}()
buf := make([]byte, 4096)
for {
nr, err := ptyBuffer.Read(buf)
nr, err := shellProc.Cmd.Read(buf)
if nr > 0 {
err := HandleAppendBlockFile(bc.BlockId, wavebase.BlockFile_Term, buf[:nr])
if err != nil {
Expand Down Expand Up @@ -577,27 +569,13 @@ func (bc *ShellController) manageRunningShellProcess(shellProc *shellexec.ShellP
}
}
}()
go func() {
defer func() {
panichandler.PanicHandler("blockcontroller:shellproc-output-loop", recover())
}()
// handles outputCh -> shellInputCh
for msg := range wshProxy.ToRemoteCh {
encodedMsg, err := wshutil.EncodeWaveOSCBytes(wshutil.WaveServerOSC, msg)
if err != nil {
log.Printf("error encoding OSC message: %v\n", err)
}
shellInputCh <- &BlockInputUnion{InputData: encodedMsg}
}
}()
go func() {
defer func() {
panichandler.PanicHandler("blockcontroller:shellproc-wait-loop", recover())
}()
// wait for the shell to finish
var exitCode int
defer func() {
wshutil.DefaultRouter.UnregisterLink(controllerLinkId)
bc.UpdateControllerAndSendUpdate(func() bool {
if bc.ProcStatus == Status_Running {
bc.ProcStatus = Status_Done
Expand Down
90 changes: 1 addition & 89 deletions pkg/wshutil/wshutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,11 @@ import (
"log"
"net"
"os"
"os/signal"
"path/filepath"
"runtime"
"strings"
"sync"
"sync/atomic"
"syscall"

"github.com/golang-jwt/jwt/v5"
"github.com/wavetermdev/waveterm/pkg/baseds"
Expand All @@ -28,7 +26,6 @@ import (
"github.com/wavetermdev/waveterm/pkg/wavebase"
"github.com/wavetermdev/waveterm/pkg/wavejwt"
"github.com/wavetermdev/waveterm/pkg/wshrpc"
"golang.org/x/term"
)

// these should both be 5 characters
Expand Down Expand Up @@ -126,102 +123,17 @@ func EncodeWaveOSCMessageEx(oscNum string, msg *RpcMessage) ([]byte, error) {
return EncodeWaveOSCBytes(oscNum, barr)
}

var termModeLock = sync.Mutex{}
var termIsRaw bool
var origTermState *term.State
var shutdownSignalHandlersInstalled bool
var shutdownOnce sync.Once
var extraShutdownFunc atomic.Pointer[func()]

func DoShutdown(reason string, exitCode int, quiet bool) {
shutdownOnce.Do(func() {
defer os.Exit(exitCode)
RestoreTermState()
extraFn := extraShutdownFunc.Load()
if extraFn != nil {
(*extraFn)()
}
if !quiet && reason != "" {
log.Printf("shutting down: %s\r\n", reason)
log.Printf("shutting down: %s\n", reason)
}
})
}

func installShutdownSignalHandlers(quiet bool) {
termModeLock.Lock()
defer termModeLock.Unlock()
if shutdownSignalHandlersInstalled {
return
}
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGHUP, syscall.SIGTERM, syscall.SIGINT)
go func() {
defer func() {
panichandler.PanicHandlerNoTelemetry("installShutdownSignalHandlers", recover())
}()
for sig := range sigCh {
DoShutdown(fmt.Sprintf("got signal %v", sig), 1, quiet)
break
}
}()
}

func SetTermRawModeAndInstallShutdownHandlers(quietShutdown bool) {
SetTermRawMode()
installShutdownSignalHandlers(quietShutdown)
}

func SetExtraShutdownFunc(fn func()) {
extraShutdownFunc.Store(&fn)
}

func SetTermRawMode() {
termModeLock.Lock()
defer termModeLock.Unlock()
if termIsRaw {
return
}
origState, err := term.MakeRaw(int(os.Stdin.Fd()))
if err != nil {
fmt.Fprintf(os.Stderr, "Error setting raw mode: %v\n", err)
return
}
origTermState = origState
termIsRaw = true
}

func RestoreTermState() {
termModeLock.Lock()
defer termModeLock.Unlock()
if !termIsRaw || origTermState == nil {
return
}
term.Restore(int(os.Stdin.Fd()), origTermState)
termIsRaw = false
}

// returns (wshRpc, wrappedStdin)
func SetupTerminalRpcClient(serverImpl ServerImpl, debugStr string) (*WshRpc, io.Reader) {
messageCh := make(chan baseds.RpcInputChType, DefaultInputChSize)
outputCh := make(chan []byte, DefaultOutputChSize)
ptyBuf := MakePtyBuffer(WaveServerOSCPrefix, os.Stdin, messageCh)
rpcClient := MakeWshRpcWithChannels(messageCh, outputCh, wshrpc.RpcContext{}, serverImpl, debugStr)
go func() {
defer func() {
panichandler.PanicHandler("SetupTerminalRpcClient", recover())
}()
for msg := range outputCh {
barr, err := EncodeWaveOSCBytes(WaveOSC, msg)
if err != nil {
fmt.Fprintf(os.Stderr, "Error encoding OSC message: %v\n", err)
continue
}
os.Stdout.Write(barr)
}
}()
return rpcClient, ptyBuf
}

func SetupPacketRpcClient(input io.Reader, output io.Writer, serverImpl ServerImpl, debugStr string) (*WshRpc, chan []byte) {
messageCh := make(chan baseds.RpcInputChType, DefaultInputChSize)
outputCh := make(chan []byte, DefaultOutputChSize)
Expand Down
Loading