Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

skywire-cli vpn subcommands + separate-systray #1317

Merged
merged 16 commits into from
Aug 14, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
14 changes: 7 additions & 7 deletions cmd/skywire-cli/commands/visor/transports.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ var lsTpCmd = &cobra.Command{
Run: func(_ *cobra.Command, _ []string) {
transports, err := clirpc.RpcClient().Transports(filterTypes, filterPubKeys, showLogs)
internal.Catch(err)
printTransports(transports...)
PrintTransports(transports...)
},
}

Expand All @@ -92,7 +92,7 @@ var idCmd = &cobra.Command{
tpID := internal.ParseUUID("transport-id", args[0])
tp, err := clirpc.RpcClient().Transport(tpID)
internal.Catch(err)
printTransports(tp)
PrintTransports(tp)
},
}

Expand Down Expand Up @@ -148,7 +148,7 @@ var addTpCmd = &cobra.Command{
logger.WithError(err).Warnf("Failed to establish %v transport", transportType)
}
}
printTransports(tp)
PrintTransports(tp)
},
}

Expand All @@ -163,7 +163,7 @@ var rmTpCmd = &cobra.Command{
},
}

func printTransports(tps ...*visor.TransportSummary) {
func PrintTransports(tps ...*visor.TransportSummary) {
sortTransports(tps...)
w := tabwriter.NewWriter(os.Stdout, 0, 0, 5, ' ', tabwriter.TabIndent)
_, err := fmt.Fprintln(w, "type\tid\tremote\tmode\tlabel")
Expand Down Expand Up @@ -206,16 +206,16 @@ var discTpCmd = &cobra.Command{
if rc := clirpc.RpcClient(); tpPK.Null() {
entry, err := rc.DiscoverTransportByID(uuid.UUID(tpID))
internal.Catch(err)
printTransportEntries(entry)
PrintTransportEntries(entry)
} else {
entries, err := rc.DiscoverTransportsByPK(tpPK)
internal.Catch(err)
printTransportEntries(entries...)
PrintTransportEntries(entries...)
}
},
}

func printTransportEntries(entries ...*transport.Entry) {
func PrintTransportEntries(entries ...*transport.Entry) {
w := tabwriter.NewWriter(os.Stdout, 0, 0, 5, ' ', tabwriter.TabIndent)
_, err := fmt.Fprintln(w, "id\ttype\tedge1\tedge2")
internal.Catch(err)
Expand Down
129 changes: 122 additions & 7 deletions cmd/skywire-cli/commands/vpn/vvpn.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,47 @@ package clivpn

import (
"encoding/json"
"io/ioutil"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the file name intentional?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my reasoning behind this naming scheme is to avoid making generic names for files or imports like "vpn.go" or "package vpn" as surely these exist somewhere else in the source already, and I would not want to pollute search results for such files and package names.

Is it your suggestion to change it?

"net/http"
"strings"
"time"

"fmt"
"log"
"os"
"strings"

"github.com/spf13/cobra"
"github.com/toqueteos/webbrowser"

utilenv "github.com/skycoin/skywire-utilities/pkg/skyenv"
skyenv "github.com/skycoin/skywire/pkg/skyenv"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May be a good move to get this to skywire-utilities repo as well.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the skyenv is here just getting the default name of the app binary "vpn-client"

that could be redundantly defined in skywire-utilities to avoid the import in this instance, but considering that the vpn-client app itself s defined in skycoin/skywire I think it prudent to keep it here.

"github.com/skycoin/skywire/pkg/visor/visorconfig"
clirpc "github.com/skycoin/skywire/cmd/skywire-cli/commands/rpc"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason we are naming this import here? Is RPC not fine? I dont see us importing the stdlib rpc package here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, is the file name intentional?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it was an attempt to avoid confusion with any other package named rpc and specify that this is the one that is associated with or provided by the cli subcommands

that same rpc client function was in a few different files

"github.com/skycoin/skywire/pkg/servicedisc"
"github.com/skycoin/skywire/cmd/skywire-cli/internal"
"github.com/skycoin/skywire/pkg/transport/network"
"github.com/skycoin/skywire/pkg/visor"
"github.com/skycoin/skywire/cmd/skywire-cli/commands/visor"


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesnt appear to be your issue, but please remove the commented import.

//"github.com/skycoin/skywire-utilities/pkg/cipher"


)

var timeout time.Duration

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Format your code please.


func init() {
RootCmd.AddCommand(
vpnListCmd,
vpnUICmd,
vpnURLCmd,
vpnStartCmd,
)
vpnListCmd.Flags().StringVarP(&ver, "ver", "v", "1.0.1", "filter results by version")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we get the default value for the version from the build tag instead maybe?

vpnListCmd.Flags().StringVarP(&country, "country", "c", "", "filter results by country")
vpnListCmd.Flags().BoolVarP(&stats, "stats", "s", false, "return only a count of the resuts")
vpnListCmd.Flags().BoolVarP(&systray, "systray", "y", false, "format results for systray")

}


Expand Down Expand Up @@ -113,11 +127,65 @@ var vpnListCmd = &cobra.Command{
}
}
}
if len(a) > 0 {
servers = a
a = []servicedisc.Service{}
servers = a
a = []servicedisc.Service{}
}
var u uptime
var s []string
if len(servers) == 0 {
fmt.Printf("No VPN Servers found\n")
os.Exit(0)
}
for _, i := range servers {
s = append(s, strings.Replace(i.Addr.String(), ":44", "", 1)+",")
}
//https://ut.skywire.skycoin.com/uptimes?visors=
urlstr := []string{utilenv.UptimeTrackerAddr, "/uptimes?visors="}
for _, i := range s {
urlstr = append(urlstr, i)
}
serviceConf := strings.Join(urlstr, "")
httpclient := http.Client{
Timeout: time.Second * 2, // Timeout after 2 seconds
}
//create the http request
req, err := http.NewRequest(http.MethodGet, serviceConf, nil)
if err != nil {
logger.WithError(err).Fatal("Failed to create http request\n")
}
req.Header.Add("Cache-Control", "no-cache")
//check for errors in the response
res, err := httpclient.Do(req)
if err != nil {
logger.Error("Failed to fetch online status for visor")
} else {
// nil error from client.Do(req)
if res.Body != nil {
defer res.Body.Close() //nolint
}
body, err := ioutil.ReadAll(res.Body)
if err != nil {
logger.WithError(err).Fatal("Failed to read response\n")
}
//fill in services struct with the response
err = json.Unmarshal(body, &u)
if err == nil {
for _, i := range u {
if i.Online {
for _, j := range servers {
if j.Addr.String() == i.Key {
a = append(a, j)
}
}
}
}
}
}
if len(a) > 0 {
servers = a
a = []servicedisc.Service{}
}

if stats {
fmt.Printf("%d VPN Servers\n", len(servers))
os.Exit(0)
Expand All @@ -141,7 +209,54 @@ var vpnListCmd = &cobra.Command{
}

fmt.Printf("%s", j)

// fmt.Println(servers)
},
}

var vpnStartCmd = &cobra.Command{
Use: "start",
Short: "start the vpn for <public-key>",
Args: cobra.MinimumNArgs(1),
Run: func(_ *cobra.Command, args []string) {
pk := internal.ParsePK("remote-public-key", args[0])
var tp *visor.TransportSummary
var err error
transportTypes := []network.Type{
network.STCP,
network.STCPR,
network.SUDPH,
network.DMSG,
}
for _, transportType := range transportTypes {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will almost necessarily fail for most transports here. Why are we trying to establish 4 transports? In my opinion, we should leave auto transport establishment to the router module as it has a substantially better view of current transports etc.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the currently available cli interface; the method I have used is the same as is used by skywire-cli tp add - sans the for loop

Is what you described provided by some other cli command currently? if so, what?

tp, err = clirpc.RpcClient().AddTransport(pk, string(transportType), timeout)
if err == nil {
logger.Infof("Established %v transport to %v", transportType, pk)
} else {
logger.WithError(err).Warnf("Failed to establish %v transport", transportType)
}
}
clivisor.PrintTransports(tp)
fmt.Println("%s", args[0])
internal.Catch(clirpc.RpcClient().StartVPNClient(args[0]))
fmt.Println("OK")
},
}

var vpnStopCmd = &cobra.Command{
Use: "stop",
Short: "stop the vpn",
Args: cobra.MinimumNArgs(1),
Run: func(_ *cobra.Command, args []string) {
internal.Catch(clirpc.RpcClient().StopVPNClient(skyenv.VPNClientName))
fmt.Println("OK")
},
}


type uptime []struct {
Key string `json:"key"`
Uptime int `json:"uptime"`
Downtime int `json:"downtime"`
Percentage float64 `json:"percentage"`
Online bool `json:"online"`
}
1 change: 1 addition & 0 deletions cmd/skywire-visor/commands/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ func runVisor(conf *visorconfig.V1) {
conf.Hypervisors = append(conf.Hypervisors, pubkey)
}
}
fmt.Printf("%+v\n", conf.Launcher.Apps[0].Args)

ctx, cancel := cmdutil.SignalContext(context.Background(), log)
vis, ok := visor.NewVisor(ctx, conf, restartCtx)
Expand Down
46 changes: 46 additions & 0 deletions pkg/visor/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ type API interface {
Apps() ([]*appserver.AppState, error)
StartApp(appName string) error
StopApp(appName string) error
StartVPNClient(pubkey string) error
StopVPNClient(appName string) error
SetAppDetailedStatus(appName, state string) error
SetAppError(appName, stateErr string) error
RestartApp(appName string) error
Expand Down Expand Up @@ -355,6 +357,50 @@ func (v *Visor) StopApp(appName string) error {
return ErrProcNotAvailable
}


// StartVPNClient implements API.
func (v *Visor) StartVPNClient(pubkey string) error {
var envs []string
var err error
// todo: can we use some kind of app start hook that will be used for both autostart
// and start? Reason: this is also called in init for autostart
// check transport manager availability
if v.tpM == nil {
return ErrTrpMangerNotAvailable
}
v.conf.Launcher.Apps[0].Args = []string{"-srv", pubkey}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do we know the first app is the VPN?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this code equivalent to what we do when we call the VPN start cli command typically?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was mostly adapted from the adjacent functions and the skywire cli visor app start / stop commands

I know it's the first app for myself but there are instances where it may not even exist and then this would cause panic. Will solve that.

for _, i := range v.conf.Launcher.Apps[0].Args {
v.log.Infof(i)

}
maker := vpnEnvMaker(v.conf, v.dmsgC, v.dmsgDC, v.tpM.STCPRRemoteAddrs())
envs, err = maker()
if err != nil {
return err
}

// if v.GetVPNClientAddress() == "" {
// return errors.New("VPN server pub key is missing")
// }

// check process manager availability
if v.procM != nil {
return v.appL.StartApp(skyenv.VPNClientName, nil, envs)
}
return ErrProcNotAvailable
}

// StopVPNClient implements API.
func (v *Visor) StopVPNClient(appName string) error {
// check process manager availability
if v.procM != nil {
_, err := v.appL.StopApp(skyenv.VPNClientName) //nolint:errcheck
return err
}
return ErrProcNotAvailable
}


// SetAppDetailedStatus implements API.
func (v *Visor) SetAppDetailedStatus(appName, status string) error {
proc, ok := v.procM.ProcByName(appName)
Expand Down
16 changes: 16 additions & 0 deletions pkg/visor/rpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import (
"github.com/skycoin/skywire/pkg/transport/network"
"github.com/skycoin/skywire/pkg/util/rpcutil"
"github.com/skycoin/skywire/pkg/servicedisc"
// "github.com/skycoin/skywire/pkg/skyenv"


)

Expand Down Expand Up @@ -220,6 +222,20 @@ func (r *RPC) StopApp(name *string, _ *struct{}) (err error) {
return r.visor.StopApp(*name)
}

// StartVPNClient starts VPNClient App
func (r *RPC) StartVPNClient(pubkey *string, _ *struct{}) (err error) {
defer rpcutil.LogCall(r.log, "StartApp", pubkey)(nil, &err)

return r.visor.StartVPNClient(*pubkey)
}

// StopVPNClient stops VPNClient App
func (r *RPC) StopVPNClient(name *string, _ *struct{}) (err error) {
defer rpcutil.LogCall(r.log, "StopApp", name)(nil, &err)

return r.visor.StopVPNClient(*name)
}

// RestartApp restarts App with provided name.
func (r *RPC) RestartApp(name *string, _ *struct{}) (err error) {
defer rpcutil.LogCall(r.log, "RestartApp", name)(nil, &err)
Expand Down
20 changes: 20 additions & 0 deletions pkg/visor/rpc_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,16 @@ func (rc *rpcClient) StopApp(appName string) error {
return rc.Call("StopApp", &appName, &struct{}{})
}

// StartVPNClient calls StartVPNClient.
func (rc *rpcClient) StartVPNClient(pubkey string) error {
return rc.Call("StartVPNClient", &pubkey, &struct{}{})
}

// StopVPNClient calls StopVPNClient.
func (rc *rpcClient) StopVPNClient(appName string) error {
return rc.Call("StopVPNClient", &appName, &struct{}{})
}

// SetAppDetailedStatus sets app's detailed state.
func (rc *rpcClient) SetAppDetailedStatus(appName, status string) error {
return rc.Call("SetAppDetailedStatus", &SetAppStatusIn{
Expand Down Expand Up @@ -634,6 +644,16 @@ func (*mockRPCClient) StopApp(string) error {
return nil
}

// StartVPNClient implements API.
func (*mockRPCClient) StartVPNClient(string) error {
return nil
}

// StopVPNClient implements API.
func (*mockRPCClient) StopVPNClient(string) error {
return nil
}

// SetAppDetailedStatus sets app's detailed state.
func (mc *mockRPCClient) SetAppDetailedStatus(appName, status string) error {
return mc.do(true, func() error {
Expand Down