Skip to content

Commit ba5f929

Browse files
authored
conn updates 3 (#1711)
lots of misc connection refactoring / fixes: * adds blocklogger as a way to writing logging information from the backend directly to the a terminal block * use blocklogger in conncontroller * use blocklogger in sshclient * fix remote name in password prompt * use sh -c to get around shell weirdness * remove cmd.exe special cases * use GetWatcher().GetFullConfig() rather than re-reading the config file * change order of things we do when establishing a connection. ask for wsh up front. then do domain socket, then connserver * reduce number of sessions required in the common case when wsh is already installed. running the connserver is now a "multi-command" which checks if it is installed, then asks for the version * send jwt token over stdin instead of in initial command string * fix focus bug for frontend conn modal * track more information in connstatus * simplify wshinstall function * add nowshreason * other misc cleanup
1 parent 37929d9 commit ba5f929

File tree

22 files changed

+678
-237
lines changed

22 files changed

+678
-237
lines changed

cmd/server/main-server.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717

1818
"github.com/wavetermdev/waveterm/pkg/authkey"
1919
"github.com/wavetermdev/waveterm/pkg/blockcontroller"
20+
"github.com/wavetermdev/waveterm/pkg/blocklogger"
2021
"github.com/wavetermdev/waveterm/pkg/filestore"
2122
"github.com/wavetermdev/waveterm/pkg/panichandler"
2223
"github.com/wavetermdev/waveterm/pkg/remote/conncontroller"
@@ -297,6 +298,7 @@ func main() {
297298
go stdinReadWatch()
298299
go telemetryLoop()
299300
configWatcher()
301+
blocklogger.InitBlockLogger()
300302
webListener, err := web.MakeTCPListener("web")
301303
if err != nil {
302304
log.Printf("error creating web listener: %v\n", err)

cmd/wsh/cmd/wshcmd-conn.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,11 @@ func connReinstallRun(cmd *cobra.Command, args []string) error {
128128
if err := validateConnectionName(connName); err != nil {
129129
return err
130130
}
131-
err := wshclient.ConnReinstallWshCommand(RpcClient, connName, &wshrpc.RpcOpts{Timeout: 60000})
131+
data := wshrpc.ConnExtData{
132+
ConnName: connName,
133+
LogBlockId: RpcContext.BlockId,
134+
}
135+
err := wshclient.ConnReinstallWshCommand(RpcClient, data, &wshrpc.RpcOpts{Timeout: 60000})
132136
if err != nil {
133137
return fmt.Errorf("reinstalling connection: %w", err)
134138
}
@@ -173,7 +177,11 @@ func connConnectRun(cmd *cobra.Command, args []string) error {
173177
if err := validateConnectionName(connName); err != nil {
174178
return err
175179
}
176-
err := wshclient.ConnConnectCommand(RpcClient, wshrpc.ConnRequest{Host: connName}, &wshrpc.RpcOpts{Timeout: 60000})
180+
data := wshrpc.ConnRequest{
181+
Host: connName,
182+
LogBlockId: RpcContext.BlockId,
183+
}
184+
err := wshclient.ConnConnectCommand(RpcClient, data, &wshrpc.RpcOpts{Timeout: 60000})
177185
if err != nil {
178186
return fmt.Errorf("connecting connection: %w", err)
179187
}
@@ -186,7 +194,11 @@ func connEnsureRun(cmd *cobra.Command, args []string) error {
186194
if err := validateConnectionName(connName); err != nil {
187195
return err
188196
}
189-
err := wshclient.ConnEnsureCommand(RpcClient, connName, &wshrpc.RpcOpts{Timeout: 60000})
197+
data := wshrpc.ConnExtData{
198+
ConnName: connName,
199+
LogBlockId: RpcContext.BlockId,
200+
}
201+
err := wshclient.ConnEnsureCommand(RpcClient, data, &wshrpc.RpcOpts{Timeout: 60000})
190202
if err != nil {
191203
return fmt.Errorf("ensuring connection: %w", err)
192204
}

cmd/wsh/cmd/wshcmd-ssh.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ func sshRun(cmd *cobra.Command, args []string) (rtnErr error) {
3939
}
4040
// first, make a connection independent of the block
4141
connOpts := wshrpc.ConnRequest{
42-
Host: sshArg,
42+
Host: sshArg,
43+
LogBlockId: blockId,
4344
Keywords: wshrpc.ConnKeywords{
4445
SshIdentityFile: identityFiles,
4546
},

frontend/app/block/blockframe.tsx

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ import {
2323
getSettingsKeyAtom,
2424
getUserName,
2525
globalStore,
26-
refocusNode,
2726
useBlockAtom,
2827
WOS,
2928
} from "@/app/store/global";
29+
import { globalRefocusWithTimeout } from "@/app/store/keymodel";
3030
import { RpcApi } from "@/app/store/wshclientapi";
3131
import { TabRpcClient } from "@/app/store/wshrpcutil";
3232
import { ErrorBoundary } from "@/element/errorboundary";
@@ -356,7 +356,11 @@ const ConnStatusOverlay = React.memo(
356356
}, [width, connStatus, setShowError]);
357357

358358
const handleTryReconnect = React.useCallback(() => {
359-
const prtn = RpcApi.ConnConnectCommand(TabRpcClient, { host: connName }, { timeout: 60000 });
359+
const prtn = RpcApi.ConnConnectCommand(
360+
TabRpcClient,
361+
{ host: connName, logblockid: nodeModel.blockId },
362+
{ timeout: 60000 }
363+
);
360364
prtn.catch((e) => console.log("error reconnecting", connName, e));
361365
}, [connName]);
362366

@@ -541,7 +545,11 @@ const BlockFrame_Default_Component = (props: BlockFrameProps) => {
541545
const connName = blockData?.meta?.connection;
542546
if (!util.isBlank(connName)) {
543547
console.log("ensure conn", nodeModel.blockId, connName);
544-
RpcApi.ConnEnsureCommand(TabRpcClient, connName, { timeout: 60000 }).catch((e) => {
548+
RpcApi.ConnEnsureCommand(
549+
TabRpcClient,
550+
{ connname: connName, logblockid: nodeModel.blockId },
551+
{ timeout: 60000 }
552+
).catch((e) => {
545553
console.log("error ensuring connection", nodeModel.blockId, connName, e);
546554
});
547555
}
@@ -691,7 +699,11 @@ const ChangeConnectionBlockModal = React.memo(
691699
meta: { connection: connName, file: newCwd },
692700
});
693701
try {
694-
await RpcApi.ConnEnsureCommand(TabRpcClient, connName, { timeout: 60000 });
702+
await RpcApi.ConnEnsureCommand(
703+
TabRpcClient,
704+
{ connname: connName, logblockid: blockId },
705+
{ timeout: 60000 }
706+
);
695707
} catch (e) {
696708
console.log("error connecting", blockId, connName, e);
697709
}
@@ -756,7 +768,7 @@ const ChangeConnectionBlockModal = React.memo(
756768
onSelect: async (_: string) => {
757769
const prtn = RpcApi.ConnConnectCommand(
758770
TabRpcClient,
759-
{ host: connStatus.connection },
771+
{ host: connStatus.connection, logblockid: blockId },
760772
{ timeout: 60000 }
761773
);
762774
prtn.catch((e) => console.log("error reconnecting", connStatus.connection, e));
@@ -879,12 +891,13 @@ const ChangeConnectionBlockModal = React.memo(
879891
} else {
880892
changeConnection(rowItem.value);
881893
globalStore.set(changeConnModalAtom, false);
894+
globalRefocusWithTimeout(10);
882895
}
883896
}
884897
if (keyutil.checkKeyPressed(waveEvent, "Escape")) {
885898
globalStore.set(changeConnModalAtom, false);
886899
setConnSelected("");
887-
refocusNode(blockId);
900+
globalRefocusWithTimeout(10);
888901
return true;
889902
}
890903
if (keyutil.checkKeyPressed(waveEvent, "ArrowUp")) {
@@ -916,6 +929,7 @@ const ChangeConnectionBlockModal = React.memo(
916929
onSelect={(selected: string) => {
917930
changeConnection(selected);
918931
globalStore.set(changeConnModalAtom, false);
932+
globalRefocusWithTimeout(10);
919933
}}
920934
selectIndex={rowIndex}
921935
autoFocus={isNodeFocused}

frontend/app/store/keymodel.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,12 @@ function handleCmdI() {
146146
globalRefocus();
147147
}
148148

149+
function globalRefocusWithTimeout(timeoutVal: number) {
150+
setTimeout(() => {
151+
globalRefocus();
152+
}, timeoutVal);
153+
}
154+
149155
function globalRefocus() {
150156
const layoutModel = getLayoutModelForStaticTab();
151157
const focusedNode = globalStore.get(layoutModel.focusedNode);
@@ -403,6 +409,7 @@ export {
403409
getAllGlobalKeyBindings,
404410
getSimpleControlShiftAtom,
405411
globalRefocus,
412+
globalRefocusWithTimeout,
406413
registerControlShiftStateUpdateHandler,
407414
registerElectronReinjectKeyHandler,
408415
registerGlobalKeys,

frontend/app/store/wshclientapi.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class RpcApiType {
3838
}
3939

4040
// command "connensure" [call]
41-
ConnEnsureCommand(client: WshClient, data: string, opts?: RpcOpts): Promise<void> {
41+
ConnEnsureCommand(client: WshClient, data: ConnExtData, opts?: RpcOpts): Promise<void> {
4242
return client.wshRpcCall("connensure", data, opts);
4343
}
4444

@@ -48,7 +48,7 @@ class RpcApiType {
4848
}
4949

5050
// command "connreinstallwsh" [call]
51-
ConnReinstallWshCommand(client: WshClient, data: string, opts?: RpcOpts): Promise<void> {
51+
ConnReinstallWshCommand(client: WshClient, data: ConnExtData, opts?: RpcOpts): Promise<void> {
5252
return client.wshRpcCall("connreinstallwsh", data, opts);
5353
}
5454

@@ -57,6 +57,11 @@ class RpcApiType {
5757
return client.wshRpcCall("connstatus", null, opts);
5858
}
5959

60+
// command "controllerappendoutput" [call]
61+
ControllerAppendOutputCommand(client: WshClient, data: CommandControllerAppendOutputData, opts?: RpcOpts): Promise<void> {
62+
return client.wshRpcCall("controllerappendoutput", data, opts);
63+
}
64+
6065
// command "controllerinput" [call]
6166
ControllerInputCommand(client: WshClient, data: CommandBlockInputData, opts?: RpcOpts): Promise<void> {
6267
return client.wshRpcCall("controllerinput", data, opts);

frontend/app/view/preview/preview.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ export class PreviewModel implements ViewModel {
364364
this.connection = atom<Promise<string>>(async (get) => {
365365
const connName = get(this.blockAtom)?.meta?.connection;
366366
try {
367-
await RpcApi.ConnEnsureCommand(TabRpcClient, connName, { timeout: 60000 });
367+
await RpcApi.ConnEnsureCommand(TabRpcClient, { connname: connName }, { timeout: 60000 });
368368
globalStore.set(this.connectionError, "");
369369
} catch (e) {
370370
globalStore.set(this.connectionError, e as string);

frontend/app/view/term/term.tsx

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,45 @@ class TermViewModel implements ViewModel {
682682
},
683683
});
684684
}
685+
const debugConn = blockData?.meta?.["term:conndebug"];
686+
fullMenu.push({
687+
label: "Debug Connection",
688+
submenu: [
689+
{
690+
label: "Off",
691+
type: "checkbox",
692+
checked: !debugConn,
693+
click: () => {
694+
RpcApi.SetMetaCommand(TabRpcClient, {
695+
oref: WOS.makeORef("block", this.blockId),
696+
meta: { "term:conndebug": null },
697+
});
698+
},
699+
},
700+
{
701+
label: "Info",
702+
type: "checkbox",
703+
checked: debugConn == "info",
704+
click: () => {
705+
RpcApi.SetMetaCommand(TabRpcClient, {
706+
oref: WOS.makeORef("block", this.blockId),
707+
meta: { "term:conndebug": "info" },
708+
});
709+
},
710+
},
711+
{
712+
label: "Verbose",
713+
type: "checkbox",
714+
checked: debugConn == "debug",
715+
click: () => {
716+
RpcApi.SetMetaCommand(TabRpcClient, {
717+
oref: WOS.makeORef("block", this.blockId),
718+
meta: { "term:conndebug": "debug" },
719+
});
720+
},
721+
},
722+
],
723+
});
685724
return fullMenu;
686725
}
687726
}

frontend/types/gotypes.d.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,12 @@ declare global {
125125
view: string;
126126
};
127127

128+
// wshrpc.CommandControllerAppendOutputData
129+
type CommandControllerAppendOutputData = {
130+
blockid: string;
131+
data64: string;
132+
};
133+
128134
// wshrpc.CommandControllerResyncData
129135
type CommandControllerResyncData = {
130136
forcerestart?: boolean;
@@ -286,11 +292,18 @@ declare global {
286292
metamaptype: MetaType;
287293
};
288294

295+
// wshrpc.ConnExtData
296+
type ConnExtData = {
297+
connname: string;
298+
logblockid?: string;
299+
};
300+
289301
// wshrpc.ConnKeywords
290302
type ConnKeywords = {
291303
"conn:wshenabled"?: boolean;
292304
"conn:askbeforewshinstall"?: boolean;
293305
"conn:overrideconfig"?: boolean;
306+
"conn:wshpath"?: string;
294307
"display:hidden"?: boolean;
295308
"display:order"?: number;
296309
"term:*"?: boolean;
@@ -317,6 +330,7 @@ declare global {
317330
type ConnRequest = {
318331
host: string;
319332
keywords?: ConnKeywords;
333+
logblockid?: string;
320334
};
321335

322336
// wshrpc.ConnStatus
@@ -329,6 +343,8 @@ declare global {
329343
activeconnnum: number;
330344
error?: string;
331345
wsherror?: string;
346+
nowshreason?: string;
347+
wshversion?: string;
332348
};
333349

334350
// wshrpc.CpuDataRequest
@@ -494,6 +510,7 @@ declare global {
494510
"term:vdomtoolbarblockid"?: string;
495511
"term:transparency"?: number;
496512
"term:allowbracketedpaste"?: boolean;
513+
"term:conndebug"?: string;
497514
"web:zoom"?: number;
498515
"web:hidenav"?: boolean;
499516
"markdown:fontsize"?: number;

pkg/blockcontroller/blockcontroller.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"sync/atomic"
1717
"time"
1818

19+
"github.com/wavetermdev/waveterm/pkg/blocklogger"
1920
"github.com/wavetermdev/waveterm/pkg/filestore"
2021
"github.com/wavetermdev/waveterm/pkg/panichandler"
2122
"github.com/wavetermdev/waveterm/pkg/remote"
@@ -375,9 +376,7 @@ func (bc *BlockController) setupAndStartShellProcess(rc *RunShellOpts, blockMeta
375376
} else {
376377
shellProc, err = shellexec.StartRemoteShellProc(rc.TermSize, cmdStr, cmdOpts, conn)
377378
if err != nil {
378-
conn.WithLock(func() {
379-
conn.WshError = err.Error()
380-
})
379+
conn.SetWshError(err)
381380
conn.WshEnabled.Store(false)
382381
log.Printf("error starting remote shell proc with wsh: %v", err)
383382
log.Print("attempting install without wsh")
@@ -759,6 +758,13 @@ func getOrCreateBlockController(tabId string, blockId string, controllerName str
759758
return bc
760759
}
761760

761+
func formatConnNameForLog(connName string) string {
762+
if connName == "" {
763+
return "local"
764+
}
765+
return connName
766+
}
767+
762768
func ResyncController(ctx context.Context, tabId string, blockId string, rtOpts *waveobj.RuntimeOpts, force bool) error {
763769
if tabId == "" || blockId == "" {
764770
return fmt.Errorf("invalid tabId or blockId passed to ResyncController")
@@ -769,6 +775,7 @@ func ResyncController(ctx context.Context, tabId string, blockId string, rtOpts
769775
}
770776
if force {
771777
StopBlockController(blockId)
778+
time.Sleep(100 * time.Millisecond) // TODO see if we can remove this (the "process finished with exit code" message comes out after we start reconnecting otherwise)
772779
}
773780
connName := blockData.Meta.GetString(waveobj.MetaKey_Connection, "")
774781
controllerName := blockData.Meta.GetString(waveobj.MetaKey_Controller, "")
@@ -784,8 +791,10 @@ func ResyncController(ctx context.Context, tabId string, blockId string, rtOpts
784791
if curBc != nil {
785792
bcStatus := curBc.GetRuntimeStatus()
786793
if bcStatus.ShellProcStatus == Status_Running && bcStatus.ShellProcConnName != connName {
794+
blocklogger.Infof(ctx, "\n[conndebug] stopping blockcontroller due to conn change %q => %q\n", formatConnNameForLog(bcStatus.ShellProcConnName), formatConnNameForLog(connName))
787795
log.Printf("stopping blockcontroller %s due to conn change\n", blockId)
788796
StopBlockControllerAndSetStatus(blockId, Status_Init)
797+
time.Sleep(100 * time.Millisecond) // TODO see if we can remove this (the "process finished with exit code" message comes out after we start reconnecting otherwise)
789798
}
790799
}
791800
// now if there is a conn, ensure it is connected

0 commit comments

Comments
 (0)