mirror of
https://github.com/wavetermdev/waveterm.git
synced 2024-12-21 16:38:23 +01:00
wsh connreinstall (#317)
This commit is contained in:
parent
fa69406550
commit
afd83f0f6f
38
cmd/wsh/cmd/wshcmd-connreinstall.go
Normal file
38
cmd/wsh/cmd/wshcmd-connreinstall.go
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright 2024, Command Line Inc.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/wavetermdev/thenextwave/pkg/remote"
|
||||
"github.com/wavetermdev/thenextwave/pkg/wshrpc"
|
||||
"github.com/wavetermdev/thenextwave/pkg/wshrpc/wshclient"
|
||||
)
|
||||
|
||||
var connReinstallCmd = &cobra.Command{
|
||||
Use: "connreinstall",
|
||||
Short: "reinstall wsh on a connection",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: connReinstallRun,
|
||||
PreRunE: preRunSetupRpcClient,
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(connReinstallCmd)
|
||||
}
|
||||
|
||||
func connReinstallRun(cmd *cobra.Command, args []string) {
|
||||
connName := args[0]
|
||||
_, err := remote.ParseOpts(connName)
|
||||
if err != nil {
|
||||
WriteStderr("[error] cannot parse connection name: %v\n", err)
|
||||
return
|
||||
}
|
||||
err = wshclient.ConnReinstallWshCommand(RpcClient, connName, &wshrpc.RpcOpts{Timeout: 60000})
|
||||
if err != nil {
|
||||
WriteStderr("[error] getting metadata: %v\n", err)
|
||||
return
|
||||
}
|
||||
WriteStdout("wsh reinstalled on connection %q\n", connName)
|
||||
}
|
@ -17,6 +17,26 @@ class WshServerType {
|
||||
return WOS.wshServerRpcHelper_call("authenticate", data, opts);
|
||||
}
|
||||
|
||||
// command "conndisconnect" [call]
|
||||
ConnDisconnectCommand(data: string, opts?: RpcOpts): Promise<void> {
|
||||
return WOS.wshServerRpcHelper_call("conndisconnect", data, opts);
|
||||
}
|
||||
|
||||
// command "connensure" [call]
|
||||
ConnEnsureCommand(data: string, opts?: RpcOpts): Promise<void> {
|
||||
return WOS.wshServerRpcHelper_call("connensure", data, opts);
|
||||
}
|
||||
|
||||
// command "connforceconnect" [call]
|
||||
ConnForceConnectCommand(data: string, opts?: RpcOpts): Promise<void> {
|
||||
return WOS.wshServerRpcHelper_call("connforceconnect", data, opts);
|
||||
}
|
||||
|
||||
// command "connreinstallwsh" [call]
|
||||
ConnReinstallWshCommand(data: string, opts?: RpcOpts): Promise<void> {
|
||||
return WOS.wshServerRpcHelper_call("connreinstallwsh", data, opts);
|
||||
}
|
||||
|
||||
// command "controllerinput" [call]
|
||||
ControllerInputCommand(data: CommandBlockInputData, opts?: RpcOpts): Promise<void> {
|
||||
return WOS.wshServerRpcHelper_call("controllerinput", data, opts);
|
||||
|
1
frontend/types/gotypes.d.ts
vendored
1
frontend/types/gotypes.d.ts
vendored
@ -154,6 +154,7 @@ declare global {
|
||||
status: string;
|
||||
connection: string;
|
||||
connected: boolean;
|
||||
hasconnected: boolean;
|
||||
error?: string;
|
||||
};
|
||||
|
||||
|
@ -53,6 +53,7 @@ type SSHConn struct {
|
||||
ConnController *ssh.Session
|
||||
Error string
|
||||
HasWaiter *atomic.Bool
|
||||
LastConnectTime int64
|
||||
}
|
||||
|
||||
func GetAllConnStatus() []wshrpc.ConnStatus {
|
||||
@ -73,6 +74,7 @@ func (conn *SSHConn) DeriveConnStatus() wshrpc.ConnStatus {
|
||||
Status: conn.Status,
|
||||
Connected: conn.Status == Status_Connected,
|
||||
Connection: conn.Opts.String(),
|
||||
HasConnected: (conn.LastConnectTime > 0),
|
||||
Error: conn.Error,
|
||||
}
|
||||
}
|
||||
@ -243,7 +245,15 @@ func (conn *SSHConn) StartConnServer() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (conn *SSHConn) checkAndInstallWsh(ctx context.Context, clientDisplayName string) error {
|
||||
type WshInstallOpts struct {
|
||||
Force bool
|
||||
NoUserPrompt bool
|
||||
}
|
||||
|
||||
func (conn *SSHConn) CheckAndInstallWsh(ctx context.Context, clientDisplayName string, opts *WshInstallOpts) error {
|
||||
if opts == nil {
|
||||
opts = &WshInstallOpts{}
|
||||
}
|
||||
client := conn.GetClient()
|
||||
if client == nil {
|
||||
return fmt.Errorf("client is nil")
|
||||
@ -251,12 +261,15 @@ func (conn *SSHConn) checkAndInstallWsh(ctx context.Context, clientDisplayName s
|
||||
// check that correct wsh extensions are installed
|
||||
expectedVersion := fmt.Sprintf("wsh v%s", wavebase.WaveVersion)
|
||||
clientVersion, err := remote.GetWshVersion(client)
|
||||
if err == nil && clientVersion == expectedVersion {
|
||||
if err == nil && clientVersion == expectedVersion && !opts.Force {
|
||||
return nil
|
||||
}
|
||||
var queryText string
|
||||
var title string
|
||||
if err != nil {
|
||||
if opts.Force {
|
||||
queryText = fmt.Sprintf("ReInstalling Wave Shell Extensions (%s) on `%s`\n", wavebase.WaveVersion, clientDisplayName)
|
||||
title = "Install Wave Shell Extensions"
|
||||
} else if err != nil {
|
||||
queryText = fmt.Sprintf("Wave requires Wave Shell Extensions to be \n"+
|
||||
"installed on `%s` \n"+
|
||||
"to ensure a seamless experience. \n\n"+
|
||||
@ -269,6 +282,7 @@ func (conn *SSHConn) checkAndInstallWsh(ctx context.Context, clientDisplayName s
|
||||
"Would you like to update?", clientDisplayName, clientVersion, expectedVersion)
|
||||
title = "Update Wave Shell Extensions"
|
||||
}
|
||||
if !opts.NoUserPrompt {
|
||||
request := &userinput.UserInputRequest{
|
||||
ResponseType: "confirm",
|
||||
QueryText: queryText,
|
||||
@ -280,6 +294,7 @@ func (conn *SSHConn) checkAndInstallWsh(ctx context.Context, clientDisplayName s
|
||||
if err != nil || !response.Confirm {
|
||||
return err
|
||||
}
|
||||
}
|
||||
log.Printf("attempting to install wsh to `%s`", clientDisplayName)
|
||||
clientOs, err := remote.GetClientOs(client)
|
||||
if err != nil {
|
||||
@ -337,6 +352,7 @@ func (conn *SSHConn) Connect(ctx context.Context) error {
|
||||
conn.close_nolock()
|
||||
} else {
|
||||
conn.Status = Status_Connected
|
||||
conn.LastConnectTime = time.Now().UnixMilli()
|
||||
}
|
||||
})
|
||||
conn.FireConnChangeEvent()
|
||||
@ -363,7 +379,7 @@ func (conn *SSHConn) connectInternal(ctx context.Context) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
installErr := conn.checkAndInstallWsh(ctx, clientDisplayName)
|
||||
installErr := conn.CheckAndInstallWsh(ctx, clientDisplayName, nil)
|
||||
if installErr != nil {
|
||||
return fmt.Errorf("conncontroller %s wsh install error: %v", conn.GetName(), installErr)
|
||||
}
|
||||
@ -385,14 +401,13 @@ func (conn *SSHConn) waitForDisconnect() {
|
||||
}
|
||||
err := client.Wait()
|
||||
conn.WithLock(func() {
|
||||
if err != nil {
|
||||
if conn.Status != Status_Disconnected {
|
||||
// don't set the error if our status is disconnected (because this error was caused by an explicit close)
|
||||
conn.Status = Status_Error
|
||||
// disconnects happen for a variety of reasons (like network, etc. and are typically transient)
|
||||
// so we just set the status to "disconnected" here (not error)
|
||||
// don't overwrite any existing error (or error status)
|
||||
if err != nil && conn.Error == "" {
|
||||
conn.Error = err.Error()
|
||||
}
|
||||
} else {
|
||||
// not sure if this is possible, because I think Wait() always returns an error (although that's not in the docs)
|
||||
if conn.Status != Status_Error {
|
||||
conn.Status = Status_Disconnected
|
||||
}
|
||||
conn.close_nolock()
|
||||
|
@ -24,6 +24,30 @@ func AuthenticateCommand(w *wshutil.WshRpc, data string, opts *wshrpc.RpcOpts) (
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// command "conndisconnect", wshserver.ConnDisconnectCommand
|
||||
func ConnDisconnectCommand(w *wshutil.WshRpc, data string, opts *wshrpc.RpcOpts) error {
|
||||
_, err := sendRpcRequestCallHelper[any](w, "conndisconnect", data, opts)
|
||||
return err
|
||||
}
|
||||
|
||||
// command "connensure", wshserver.ConnEnsureCommand
|
||||
func ConnEnsureCommand(w *wshutil.WshRpc, data string, opts *wshrpc.RpcOpts) error {
|
||||
_, err := sendRpcRequestCallHelper[any](w, "connensure", data, opts)
|
||||
return err
|
||||
}
|
||||
|
||||
// command "connforceconnect", wshserver.ConnForceConnectCommand
|
||||
func ConnForceConnectCommand(w *wshutil.WshRpc, data string, opts *wshrpc.RpcOpts) error {
|
||||
_, err := sendRpcRequestCallHelper[any](w, "connforceconnect", data, opts)
|
||||
return err
|
||||
}
|
||||
|
||||
// command "connreinstallwsh", wshserver.ConnReinstallWshCommand
|
||||
func ConnReinstallWshCommand(w *wshutil.WshRpc, data string, opts *wshrpc.RpcOpts) error {
|
||||
_, err := sendRpcRequestCallHelper[any](w, "connreinstallwsh", data, opts)
|
||||
return err
|
||||
}
|
||||
|
||||
// command "controllerinput", wshserver.ControllerInputCommand
|
||||
func ControllerInputCommand(w *wshutil.WshRpc, data wshrpc.CommandBlockInputData, opts *wshrpc.RpcOpts) error {
|
||||
_, err := sendRpcRequestCallHelper[any](w, "controllerinput", data, opts)
|
||||
|
@ -63,6 +63,11 @@ const (
|
||||
Command_RemoteWriteFile = "remotewritefile"
|
||||
Command_RemoteFileDelete = "remotefiledelete"
|
||||
Command_RemoteFileJoiin = "remotefilejoin"
|
||||
|
||||
Command_ConnEnsure = "connensure"
|
||||
Command_ConnReinstallWsh = "connreinstallwsh"
|
||||
Command_ConnForceConnect = "connforceconnect"
|
||||
Command_ConnDisconnect = "conndisconnect"
|
||||
)
|
||||
|
||||
type RespOrErrorUnion[T any] struct {
|
||||
@ -98,6 +103,12 @@ type WshRpcInterface interface {
|
||||
TestCommand(ctx context.Context, data string) error
|
||||
SetConfigCommand(ctx context.Context, data wconfig.MetaSettingsType) error
|
||||
|
||||
// connection functions
|
||||
ConnEnsureCommand(ctx context.Context, connName string) error
|
||||
ConnReinstallWshCommand(ctx context.Context, connName string) error
|
||||
ConnForceConnectCommand(ctx context.Context, connName string) error
|
||||
ConnDisconnectCommand(ctx context.Context, connName string) error
|
||||
|
||||
// eventrecv is special, it's handled internally by WshRpc with EventListener
|
||||
EventRecvCommand(ctx context.Context, data WaveEvent) error
|
||||
|
||||
@ -347,5 +358,6 @@ type ConnStatus struct {
|
||||
Status string `json:"status"`
|
||||
Connection string `json:"connection"`
|
||||
Connected bool `json:"connected"`
|
||||
HasConnected bool `json:"hasconnected"` // true if it has *ever* connected successfully
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ import (
|
||||
"github.com/wavetermdev/thenextwave/pkg/blockcontroller"
|
||||
"github.com/wavetermdev/thenextwave/pkg/eventbus"
|
||||
"github.com/wavetermdev/thenextwave/pkg/filestore"
|
||||
"github.com/wavetermdev/thenextwave/pkg/remote"
|
||||
"github.com/wavetermdev/thenextwave/pkg/remote/conncontroller"
|
||||
"github.com/wavetermdev/thenextwave/pkg/waveai"
|
||||
"github.com/wavetermdev/thenextwave/pkg/waveobj"
|
||||
"github.com/wavetermdev/thenextwave/pkg/wconfig"
|
||||
@ -467,3 +469,27 @@ func (ws *WshServer) SetConfigCommand(ctx context.Context, data wconfig.MetaSett
|
||||
log.Printf("SETCONFIG: %v\n", data)
|
||||
return wconfig.SetBaseConfigValue(data.MetaMapType)
|
||||
}
|
||||
|
||||
func (ws *WshServer) ConnEnsureCommand(ctx context.Context, connName string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ws *WshServer) ConnDisconnectCommand(ctx context.Context, connName string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ws *WshServer) ConnForceConnectCommand(ctx context.Context, connName string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ws *WshServer) ConnReinstallWshCommand(ctx context.Context, connName string) error {
|
||||
connOpts, err := remote.ParseOpts(connName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing connection name: %w", err)
|
||||
}
|
||||
conn := conncontroller.GetConn(ctx, connOpts, false)
|
||||
if conn == nil {
|
||||
return fmt.Errorf("connection not found: %s", connName)
|
||||
}
|
||||
return conn.CheckAndInstallWsh(ctx, connName, &conncontroller.WshInstallOpts{Force: true, NoUserPrompt: true})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user