diff --git a/cmd/apps/skysocks-client/skysocks-client.go b/cmd/apps/skysocks-client/skysocks-client.go index 34bf8311b7..6d03b53631 100644 --- a/cmd/apps/skysocks-client/skysocks-client.go +++ b/cmd/apps/skysocks-client/skysocks-client.go @@ -33,6 +33,7 @@ const ( var r = netutil.NewRetrier(nil, time.Second, netutil.DefaultMaxBackoff, 0, 1) func dialServer(ctx context.Context, appCl *app.Client, pk cipher.PubKey) (net.Conn, error) { + appCl.SetDetailedStatus(appserver.AppDetailedStatusStarting) //nolint var conn net.Conn err := r.Do(ctx, func() error { var err error @@ -89,7 +90,6 @@ func main() { } fmt.Printf("Connected to %v\n", pk) - client, err := skysocks.NewClient(conn, appCl) if err != nil { print(fmt.Sprintf("Failed to create a new client: %v\n", err)) @@ -98,6 +98,7 @@ func main() { } fmt.Printf("Serving proxy client %v\n", *addr) + setAppStatus(appCl, appserver.AppDetailedStatusRunning) if err := client.ListenAndServe(*addr); err != nil { print(fmt.Sprintf("Error serving proxy client: %v\n", err)) diff --git a/cmd/skywire-cli/commands/root.go b/cmd/skywire-cli/commands/root.go index ae02ec4e74..57dd9328f8 100644 --- a/cmd/skywire-cli/commands/root.go +++ b/cmd/skywire-cli/commands/root.go @@ -22,6 +22,7 @@ import ( clirtfind "github.com/skycoin/skywire/cmd/skywire-cli/commands/rtfind" cliskyfwd "github.com/skycoin/skywire/cmd/skywire-cli/commands/skyfwd" cliskyrev "github.com/skycoin/skywire/cmd/skywire-cli/commands/skyrev" + cliskysocksc "github.com/skycoin/skywire/cmd/skywire-cli/commands/skysocksc" clisurvey "github.com/skycoin/skywire/cmd/skywire-cli/commands/survey" clivisor "github.com/skycoin/skywire/cmd/skywire-cli/commands/visor" clivpn "github.com/skycoin/skywire/cmd/skywire-cli/commands/vpn" @@ -188,6 +189,7 @@ func init() { climdisc.RootCmd, clicompletion.RootCmd, clilog.RootCmd, + cliskysocksc.RootCmd, treeCmd, docCmd, ) diff --git a/cmd/skywire-cli/commands/skysocksc/root.go b/cmd/skywire-cli/commands/skysocksc/root.go new file mode 100644 index 0000000000..ecdb76e73d --- /dev/null +++ b/cmd/skywire-cli/commands/skysocksc/root.go @@ -0,0 +1,12 @@ +// Package skysocksc root.go +package skysocksc + +import ( + "github.com/spf13/cobra" +) + +// RootCmd contains commands that interact with the skywire-visor +var RootCmd = &cobra.Command{ + Use: "skysocksc", + Short: "controls for Skysocks client", +} diff --git a/cmd/skywire-cli/commands/skysocksc/skysocksc.go b/cmd/skywire-cli/commands/skysocksc/skysocksc.go new file mode 100644 index 0000000000..5a35d034f3 --- /dev/null +++ b/cmd/skywire-cli/commands/skysocksc/skysocksc.go @@ -0,0 +1,122 @@ +// Package skysocksc cmd/skywire-cli/commands/skysocksc/skysocks.go +package skysocksc + +import ( + "bytes" + "fmt" + "os" + "text/tabwriter" + "time" + + "github.com/spf13/cobra" + + clirpc "github.com/skycoin/skywire/cmd/skywire-cli/commands/rpc" + "github.com/skycoin/skywire/cmd/skywire-cli/internal" + "github.com/skycoin/skywire/pkg/app/appserver" +) + +var pk string + +func init() { + RootCmd.PersistentFlags().StringVar(&clirpc.Addr, "rpc", "localhost:3435", "RPC server address") + RootCmd.AddCommand( + skysockscStartCmd, + skysockscStopCmd, + skysockscStatusCmd, + ) + skysockscStartCmd.Flags().StringVar(&pk, "pk", "", "skysocks server public key") +} + +var skysockscStartCmd = &cobra.Command{ + Use: "start", + Short: "start the skysocks-client", + Args: cobra.MinimumNArgs(0), + Run: func(cmd *cobra.Command, args []string) { + rpcClient, err := clirpc.Client(cmd.Flags()) + if err != nil { + os.Exit(1) + } + internal.Catch(cmd.Flags(), rpcClient.StartSkysocksClient(pk)) + internal.PrintOutput(cmd.Flags(), nil, "Starting.") + startProcess := true + for startProcess { + time.Sleep(time.Second * 1) + internal.PrintOutput(cmd.Flags(), nil, ".") + states, err := rpcClient.Apps() + internal.Catch(cmd.Flags(), err) + + type output struct { + AppError string `json:"app_error,omitempty"` + } + + for _, state := range states { + if state.Name == "skysocks-client" { + if state.Status == appserver.AppStatusRunning { + startProcess = false + internal.PrintOutput(cmd.Flags(), nil, fmt.Sprintln("\nRunning!")) + } + if state.Status == appserver.AppStatusErrored { + startProcess = false + out := output{ + AppError: state.DetailedStatus, + } + internal.PrintOutput(cmd.Flags(), out, fmt.Sprintln("\nError! > "+state.DetailedStatus)) + } + } + } + } + }, +} + +var skysockscStopCmd = &cobra.Command{ + Use: "stop", + Short: "stop the skysocks-client", + Run: func(cmd *cobra.Command, _ []string) { + rpcClient, err := clirpc.Client(cmd.Flags()) + if err != nil { + os.Exit(1) + } + internal.Catch(cmd.Flags(), rpcClient.StopSkysocksClient()) + internal.PrintOutput(cmd.Flags(), "OK", fmt.Sprintln("OK")) + }, +} + +var skysockscStatusCmd = &cobra.Command{ + Use: "status", + Short: "skysocks-client status", + Run: func(cmd *cobra.Command, _ []string) { + rpcClient, err := clirpc.Client(cmd.Flags()) + if err != nil { + os.Exit(1) + } + states, err := rpcClient.Apps() + internal.Catch(cmd.Flags(), err) + + var b bytes.Buffer + w := tabwriter.NewWriter(&b, 0, 0, 5, ' ', tabwriter.TabIndent) + internal.Catch(cmd.Flags(), err) + type appState struct { + Status string `json:"status"` + } + var jsonAppStatus appState + for _, state := range states { + if state.Name == "skysocks-client" { + + status := "stopped" + if state.Status == appserver.AppStatusRunning { + status = "running" + } + if state.Status == appserver.AppStatusErrored { + status = "errored" + } + jsonAppStatus = appState{ + Status: status, + } + _, err = fmt.Fprintf(w, "%s\n", status) + internal.Catch(cmd.Flags(), err) + } + } + internal.Catch(cmd.Flags(), w.Flush()) + internal.PrintOutput(cmd.Flags(), jsonAppStatus, b.String()) + }, +} diff --git a/internal/skysocks/client.go b/internal/skysocks/client.go index 0aed1cbef6..2a72c5f2e9 100644 --- a/internal/skysocks/client.go +++ b/internal/skysocks/client.go @@ -12,7 +12,6 @@ import ( "github.com/skycoin/yamux" "github.com/skycoin/skywire/pkg/app" - "github.com/skycoin/skywire/pkg/app/appserver" "github.com/skycoin/skywire/pkg/router" "github.com/skycoin/skywire/pkg/skyenv" ) @@ -61,9 +60,6 @@ func (c *Client) ListenAndServe(addr string) error { fmt.Printf("Listening skysocks client on %s", addr) c.listener = l - if c.appCl != nil { - c.setAppStatus(appserver.AppDetailedStatusRunning) - } for { select { @@ -174,12 +170,6 @@ func (c *Client) ListenIPC(client *ipc.Client) { }) } -func (c *Client) setAppStatus(status appserver.AppDetailedStatus) { - if err := c.appCl.SetDetailedStatus(string(status)); err != nil { - print(fmt.Sprintf("Failed to set status %v: %v\n", status, err)) - } -} - func (c *Client) setAppError(appErr error) { if err := c.appCl.SetError(appErr.Error()); err != nil { print(fmt.Sprintf("Failed to set error %v: %v\n", appErr, err)) diff --git a/pkg/servicedisc/types.go b/pkg/servicedisc/types.go index 3aeff758e8..b3d44ec58e 100644 --- a/pkg/servicedisc/types.go +++ b/pkg/servicedisc/types.go @@ -19,8 +19,7 @@ import ( const ( // ServiceTypeSkysocks stands for the skysocks discovery. ServiceTypeSkysocks = "skysocks" - // ServiceTypeProxy stands for the proxy discovery. - // proxy and skysock are same + // ServiceTypeProxy stands for the proxy discovery. Proxy and Skysocks are same ServiceTypeProxy = "proxy" // ServiceTypeVPN stands for the VPN discovery. ServiceTypeVPN = "vpn" diff --git a/pkg/visor/api.go b/pkg/visor/api.go index f25004f95d..af11c2433d 100644 --- a/pkg/visor/api.go +++ b/pkg/visor/api.go @@ -87,6 +87,10 @@ type API interface { StopVPNClient(appName string) error VPNServers(version, country string) ([]servicedisc.Service, error) + //skysocks-client controls + StartSkysocksClient(pk string) error + StopSkysocksClient() error + //transports TransportTypes() ([]string, error) Transports(types []string, pks []cipher.PubKey, logs bool) ([]*TransportSummary, error) @@ -511,6 +515,61 @@ func (v *Visor) StopVPNClient(appName string) error { return ErrProcNotAvailable } +// StartSkysocksClient implements API. +func (v *Visor) StartSkysocksClient(serverKey string) error { + var envs []string + if v.tpM == nil { + return ErrTrpMangerNotAvailable + } + + if len(v.conf.Launcher.Apps) == 0 { + return errors.New("no skysocks-client app configuration found") + } + + for index, app := range v.conf.Launcher.Apps { + if app.Name == visorconfig.SkysocksClientName { + if v.GetSkysocksClientAddress() == "" && serverKey == "" { + return errors.New("Skysocks server pub key is missing") + } + + if serverKey != "" { + var pk cipher.PubKey + if err := pk.Set(serverKey); err != nil { + return err + } + v.SetAppPK(visorconfig.SkysocksClientName, pk) //nolint + // we set the args in memory and pass it in `v.appL.StartApp` + // unlike the api method `StartApp` where `nil` is passed in `v.appL.StartApp` as args + // but the args are set in the config + v.conf.Launcher.Apps[index].Args = []string{"-srv", pk.Hex()} + } else { + var pk cipher.PubKey + if err := pk.Set(v.GetSkysocksClientAddress()); err != nil { + return err + } + v.conf.Launcher.Apps[index].Args = []string{"-srv", pk.Hex()} + } + + // check process manager availability + if v.procM != nil { + return v.appL.StartApp(visorconfig.SkysocksClientName, v.conf.Launcher.Apps[index].Args, envs) + } + return ErrProcNotAvailable + } + } + return errors.New("no skysocks-client app configuration found") +} + +// StopSkysocksClient implements API. +func (v *Visor) StopSkysocksClient() error { + // check process manager availability + if v.procM != nil { + _, err := v.appL.StopApp(visorconfig.SkysocksClientName) //nolint:errcheck + return err + } + return ErrProcNotAvailable +} + // SetAppDetailedStatus implements API. func (v *Visor) SetAppDetailedStatus(appName, status string) error { proc, ok := v.procM.ProcByName(appName) @@ -553,7 +612,7 @@ func (v *Visor) SetAutoStart(appName string, autoStart bool) error { } v.log.Infof("Saving auto start = %v for app %v to config", autoStart, appName) - return v.conf.UpdateAppAutostart(appName, autoStart) + return v.conf.UpdateAppAutostart(v.appL, appName, autoStart) } // SetAppPassword implements API. @@ -578,7 +637,7 @@ func (v *Visor) SetAppPassword(appName, password string) error { const ( passcodeArgName = "-passcode" ) - if err := v.conf.UpdateAppArg(appName, passcodeArgName, password); err != nil { + if err := v.conf.UpdateAppArg(v.appL, appName, passcodeArgName, password); err != nil { return err } @@ -598,7 +657,7 @@ func (v *Visor) SetAppNetworkInterface(appName, netifc string) error { const ( netifcArgName = "--netifc" ) - if err := v.conf.UpdateAppArg(appName, netifcArgName, netifc); err != nil { + if err := v.conf.UpdateAppArg(v.appL, appName, netifcArgName, netifc); err != nil { return err } @@ -618,7 +677,7 @@ func (v *Visor) SetAppKillswitch(appName string, killswitch bool) error { const ( killSwitchArg = "--killswitch" ) - if err := v.conf.UpdateAppArg(appName, killSwitchArg, killswitch); err != nil { + if err := v.conf.UpdateAppArg(v.appL, appName, killSwitchArg, killswitch); err != nil { return err } @@ -638,7 +697,7 @@ func (v *Visor) SetAppSecure(appName string, isSecure bool) error { const ( secureArgName = "--secure" ) - if err := v.conf.UpdateAppArg(appName, secureArgName, isSecure); err != nil { + if err := v.conf.UpdateAppArg(v.appL, appName, secureArgName, isSecure); err != nil { return err } v.log.Infof("Updated %v secure state", appName) @@ -667,7 +726,7 @@ func (v *Visor) SetAppPK(appName string, pk cipher.PubKey) error { const ( pkArgName = "-srv" ) - if err := v.conf.UpdateAppArg(appName, pkArgName, pk.String()); err != nil { + if err := v.conf.UpdateAppArg(v.appL, appName, pkArgName, pk.String()); err != nil { return err } @@ -697,7 +756,7 @@ func (v *Visor) SetAppDNS(appName string, dnsAddr string) error { pkArgName = "-dns" ) - if err := v.conf.UpdateAppArg(appName, pkArgName, dnsAddr); err != nil { + if err := v.conf.UpdateAppArg(v.appL, appName, pkArgName, dnsAddr); err != nil { return err } @@ -1274,6 +1333,20 @@ func (v *Visor) GetVPNClientAddress() string { return "" } +// GetSkysocksClientAddress get PK address of server set on skysocks-client +func (v *Visor) GetSkysocksClientAddress() string { + for _, v := range v.conf.Launcher.Apps { + if v.Name == visorconfig.SkysocksClientAddr { + for index := range v.Args { + if v.Args[index] == "-srv" { + return v.Args[index+1] + } + } + } + } + return "" +} + // IsDMSGClientReady return availability of dsmg client func (v *Visor) IsDMSGClientReady() (bool, error) { if v.isDTMReady() { diff --git a/pkg/visor/rpc.go b/pkg/visor/rpc.go index c9a172a8e3..f14c26c7f8 100644 --- a/pkg/visor/rpc.go +++ b/pkg/visor/rpc.go @@ -286,6 +286,20 @@ func (r *RPC) StopVPNClient(name *string, _ *struct{}) (err error) { return r.visor.StopVPNClient(*name) } +// StartSkysocksClient starts SkysocksClient App +func (r *RPC) StartSkysocksClient(pk string, _ *struct{}) (err error) { + defer rpcutil.LogCall(r.log, "StartSkysocksClient", pk)(nil, &err) + + return r.visor.StartSkysocksClient(pk) +} + +// StopSkysocksClient stops SkysocksClient App +func (r *RPC) StopSkysocksClient(_ *struct{}, _ *struct{}) (err error) { + defer rpcutil.LogCall(r.log, "StopSkysocksClient", nil)(nil, &err) + + return r.visor.StopSkysocksClient() +} + // RestartApp restarts App with provided name. func (r *RPC) RestartApp(name *string, _ *struct{}) (err error) { defer rpcutil.LogCall(r.log, "RestartApp", name)(nil, &err) diff --git a/pkg/visor/rpc_client.go b/pkg/visor/rpc_client.go index c84a33b331..945cd32347 100644 --- a/pkg/visor/rpc_client.go +++ b/pkg/visor/rpc_client.go @@ -188,6 +188,16 @@ func (rc *rpcClient) StopVPNClient(appName string) error { return rc.Call("StopVPNClient", &appName, &struct{}{}) } +// StartSkysocksClient calls StartSkysocksClient. +func (rc *rpcClient) StartSkysocksClient(pk string) error { + return rc.Call("StartSkysocksClient", pk, &struct{}{}) +} + +// StopSkysocksClient calls StopSkysocksClient. +func (rc *rpcClient) StopSkysocksClient() error { + return rc.Call("StopSkysocksClient", &struct{}{}, &struct{}{}) +} + // SetAppDetailedStatus sets app's detailed state. func (rc *rpcClient) SetAppDetailedStatus(appName, status string) error { return rc.Call("SetAppDetailedStatus", &SetAppStatusIn{ @@ -821,6 +831,16 @@ func (*mockRPCClient) StopVPNClient(string) error { return nil } +// StartSkysocksClient implements API. +func (*mockRPCClient) StartSkysocksClient(string) error { + return nil +} + +// StopSkysocksClient implements API. +func (*mockRPCClient) StopSkysocksClient() error { + return nil +} + // SetAppDetailedStatus sets app's detailed state. func (mc *mockRPCClient) SetAppDetailedStatus(appName, status string) error { return mc.do(true, func() error { diff --git a/pkg/visor/visorconfig/v1.go b/pkg/visor/visorconfig/v1.go index 1fc5652ed7..c758399c86 100644 --- a/pkg/visor/visorconfig/v1.go +++ b/pkg/visor/visorconfig/v1.go @@ -8,6 +8,7 @@ import ( "github.com/skycoin/skywire-utilities/pkg/cipher" "github.com/skycoin/skywire/pkg/app/appserver" + "github.com/skycoin/skywire/pkg/app/launcher" "github.com/skycoin/skywire/pkg/dmsgc" "github.com/skycoin/skywire/pkg/transport" "github.com/skycoin/skywire/pkg/transport/network" @@ -106,8 +107,8 @@ func Reload() (*V1, error) { // UpdateAppAutostart modifies a single app's autostart value within the config and also the given // // The updated config gets flushed to file if there are any changes. -func (v1 *V1) UpdateAppAutostart(appName string, autoStart bool) error { - // func (v1 *V1) UpdateAppAutostart(launch *appserver.AppLauncherConfig, appName string, autoStart bool) error { +// func (v1 *V1) UpdateAppAutostart(appName string, autoStart bool) error { +func (v1 *V1) UpdateAppAutostart(launch *launcher.AppLauncher, appName string, autoStart bool) error { v1.mu.Lock() defer v1.mu.Unlock() conf := v1.Launcher @@ -122,21 +123,19 @@ func (v1 *V1) UpdateAppAutostart(appName string, autoStart bool) error { if !changed { return nil } - /* - launch.ResetConfig(appserver.AppLauncherConfig{ - VisorPK: v1.PK, - Apps: conf.Apps, - ServerAddr: conf.ServerAddr, - DisplayNodeIP: conf.DisplayNodeIP, - }) - */ + launch.ResetConfig(launcher.AppLauncherConfig{ + VisorPK: v1.PK, + Apps: conf.Apps, + ServerAddr: conf.ServerAddr, + DisplayNodeIP: conf.DisplayNodeIP, + }) return v1.flush(v1) } // UpdateAppArg updates the cli flag of the specified app config and also within the // The updated config gets flushed to file if there are any changes. -func (v1 *V1) UpdateAppArg(appName, argName string, value interface{}) error { - // func (v1 *V1) UpdateAppArg(launch *appserver.AppLauncher, appName, argName string, value interface{}) error { +// func (v1 *V1) UpdateAppArg(appName, argName string, value interface{}) error { +func (v1 *V1) UpdateAppArg(launch *launcher.AppLauncher, appName, argName string, value interface{}) error { v1.mu.Lock() defer v1.mu.Unlock() @@ -155,14 +154,12 @@ func (v1 *V1) UpdateAppArg(appName, argName string, value interface{}) error { if !configChanged { return nil } - /* - launch.ResetConfig(appserver.AppLauncherConfig{ - VisorPK: v1.PK, - Apps: conf.Apps, - ServerAddr: conf.ServerAddr, - DisplayNodeIP: conf.DisplayNodeIP, - }) - */ + launch.ResetConfig(launcher.AppLauncherConfig{ + VisorPK: v1.PK, + Apps: conf.Apps, + ServerAddr: conf.ServerAddr, + DisplayNodeIP: conf.DisplayNodeIP, + }) return v1.flush(v1) } diff --git a/vendor/github.com/godbus/dbus/v5/conn.go b/vendor/github.com/godbus/dbus/v5/conn.go index 69978ea26a..8080f3e918 100644 --- a/vendor/github.com/godbus/dbus/v5/conn.go +++ b/vendor/github.com/godbus/dbus/v5/conn.go @@ -432,7 +432,7 @@ func (conn *Conn) inWorker() { case TypeSignal: conn.handleSignal(sequence, msg) case TypeMethodCall: - go conn.handleCall(msg) +conn.handleCall(msg) } }