From 7445bffc9c645ae92b8e8d563d3354cd2424c869 Mon Sep 17 00:00:00 2001 From: Mohammed <79150699+mrpalide@users.noreply.github.com> Date: Sat, 22 Oct 2022 17:21:20 +0330 Subject: [PATCH] Improve systray VPN button initialization (#1380) * check dmsg-client ready or not for vpn button | add retrying when vpn servers couldn't fetch each 10 seconds * go get dmsg@develop and skywire-utilities@develop * update dmsg@develop --- internal/gui/gui.go | 56 +++++++++++++++++++++++++++++++---------- pkg/visor/api.go | 13 ++++++++++ pkg/visor/rpc.go | 9 +++++++ pkg/visor/rpc_client.go | 12 +++++++++ 4 files changed, 77 insertions(+), 13 deletions(-) diff --git a/internal/gui/gui.go b/internal/gui/gui.go index 0364aa5ab2..c5316ac128 100644 --- a/internal/gui/gui.go +++ b/internal/gui/gui.go @@ -182,6 +182,8 @@ func initVpnClientBtn(conf *visorconfig.V1, httpClient *http.Client, logger *log rpcC = rpcClient(conf, rpc_logger) mVPNClient = systray.AddMenuItem("VPN", "VPN Client Submenu") + mVPNClient.Disable() + go mVPNClientEnable(rpcC, logger.PackageLogger("systray:vpn_button")) // VPN Status mVPNStatus = mVPNClient.AddSubMenuItem("Status: Disconnected", "VPN Client Status") mVPNStatus.Disable() @@ -189,12 +191,21 @@ func initVpnClientBtn(conf *visorconfig.V1, httpClient *http.Client, logger *log // VPN Connect/Disconnect Button mVPNButton = mVPNClient.AddSubMenuItem("Connect", "VPN Client Switch Button") // VPN Public Servers List - mVPNServersList := mVPNClient.AddSubMenuItem("Servers", "VPN Client Servers") - mVPNServers := []*systray.MenuItem{} - for _, server := range getAvailPublicVPNServers(conf, httpClient, logger.PackageLogger("systray:servers")) { - mVPNServers = append(mVPNServers, mVPNServersList.AddSubMenuItemCheckbox(server, "", false)) + go serversBtn(conf, rpcC, httpClient, logger.PackageLogger("systray:vpn-servers")) +} + +func mVPNClientEnable(rpcC visor.API, logger *logging.Logger) { + logger.Info("Initializing...") + for { + isReady, _ := rpcC.IsDMSGClientReady() + if isReady { + mVPNClient.Enable() + logger.Info("Initialized.") + return + } + logger.Warn("DMSG-Client not ready yet, will check in next 10 seconds.") + time.Sleep(10 * time.Second) } - go serversBtn(conf, mVPNServers, rpcC) } func vpnStatusBtn(conf *visorconfig.V1, rpcClient visor.API) { @@ -231,9 +242,27 @@ func vpnStatusBtn(conf *visorconfig.V1, rpcClient visor.API) { } } -func serversBtn(conf *visorconfig.V1, servers []*systray.MenuItem, rpcClient visor.API) { +func serversBtn(conf *visorconfig.V1, rpcClient visor.API, httpC *http.Client, logger *logging.Logger) { + // fetching and create vpn-servers lists + mVPNServersList := mVPNClient.AddSubMenuItem("Servers", "VPN Client Servers") + mVPNServers := []*systray.MenuItem{} + for { + servers, err := getAvailPublicVPNServers(conf, httpC, logger) + if err != nil { + logger.Warnf("cannot fetch vpn-servers due to: %s", err.Error()) + } + if len(servers) > 0 { + for _, server := range servers { + mVPNServers = append(mVPNServers, mVPNServersList.AddSubMenuItemCheckbox(server, "", false)) + } + break + } + time.Sleep(10 * time.Second) + } + + // add btnChannel for each vpn server button btnChannel := make(chan int) - for index, server := range servers { + for index, server := range mVPNServers { go func(chn chan int, server *systray.MenuItem, index int) { for { select { @@ -244,11 +273,12 @@ func serversBtn(conf *visorconfig.V1, servers []*systray.MenuItem, rpcClient vis }(btnChannel, server, index) } + // logic of choosing server from list for { - selectedServer := servers[<-btnChannel] + selectedServer := mVPNServers[<-btnChannel] serverTempValue := strings.Split(selectedServer.String(), ",")[2] serverPK := serverTempValue[2 : len(serverTempValue)-7] - for _, server := range servers { + for _, server := range mVPNServers { server.Uncheck() server.Enable() } @@ -295,7 +325,7 @@ func handleVPNLinkButton(conf *visorconfig.V1) { } // getAvailPublicVPNServers gets all available public VPN server from service discovery URL -func getAvailPublicVPNServers(conf *visorconfig.V1, httpC *http.Client, logger *logging.Logger) []string { +func getAvailPublicVPNServers(conf *visorconfig.V1, httpC *http.Client, logger *logging.Logger) ([]string, error) { svrConfig := servicedisc.Config{ Type: servicedisc.ServiceTypeVPN, PK: conf.PK, @@ -306,7 +336,7 @@ func getAvailPublicVPNServers(conf *visorconfig.V1, httpC *http.Client, logger * vpnServers, err := sdClient.Services(context.Background(), 0, "", "") if err != nil { logger.Error("Error getting vpn servers: ", err) - return nil + return nil, err } serverAddrs := make([]string, len(vpnServers)) for idx, server := range vpnServers { @@ -316,7 +346,7 @@ func getAvailPublicVPNServers(conf *visorconfig.V1, httpC *http.Client, logger * serverAddrs[idx] = server.Addr.PubKey().String() + " | NA" } } - return serverAddrs + return serverAddrs, nil } func getHTTPClient(conf *visorconfig.V1, ctx context.Context, logger *logging.MasterLogger) *http.Client { @@ -335,7 +365,7 @@ func getHTTPClient(conf *visorconfig.V1, ctx context.Context, logger *logging.Ma keys = append(keys, pk) entries := direct.GetAllEntries(keys, servers) dClient := direct.NewClient(entries, logger.PackageLogger("systray:dmsghttp_direct_client")) - dmsgDC, closeDmsg, err := direct.StartDmsg(ctx, logger.PackageLogger("systray:dsmghttp_dmsgDC"), + dmsgDC, closeDmsg, err := direct.StartDmsg(ctx, logger.PackageLogger("systray:dmsghttp_dmsgDC"), pk, sk, dClient, dmsg.DefaultConfig()) if err != nil { return &http.Client{} diff --git a/pkg/visor/api.go b/pkg/visor/api.go index 8146bd4459..25919a527e 100644 --- a/pkg/visor/api.go +++ b/pkg/visor/api.go @@ -90,6 +90,8 @@ type API interface { SetPersistentTransports([]transport.PersistentTransports) error GetLogRotationInterval() (visorconfig.Duration, error) SetLogRotationInterval(visorconfig.Duration) error + + IsDMSGClientReady() (bool, error) } // HealthCheckable resource returns its health status as an integer @@ -912,3 +914,14 @@ func (v *Visor) GetVPNClientAddress() string { } return "" } + +// IsDMSGClientReady return availability of dsmg client +func (v *Visor) IsDMSGClientReady() (bool, error) { + if v.isDTMReady() { + dmsgTracker, _ := v.dtm.Get(v.conf.PK) //nolint + if dmsgTracker.ServerPK.Hex()[:5] != "00000" { + return true, nil + } + } + return false, errors.New("dmsg client is not ready") +} diff --git a/pkg/visor/rpc.go b/pkg/visor/rpc.go index f671bb91b3..96a59a23c4 100644 --- a/pkg/visor/rpc.go +++ b/pkg/visor/rpc.go @@ -608,3 +608,12 @@ func (r *RPC) RemoteVisors(_ *struct{}, out *[]string) (err error) { } return err } + +// IsDMSGClientReady return status of dmsg client +func (r *RPC) IsDMSGClientReady(_ *struct{}, out *bool) (err error) { + defer rpcutil.LogCall(r.log, "IsDMSGClientReady", nil)(out, &err) + + status, err := r.visor.IsDMSGClientReady() + *out = status + return err +} diff --git a/pkg/visor/rpc_client.go b/pkg/visor/rpc_client.go index 09fd548825..e9a6abe026 100644 --- a/pkg/visor/rpc_client.go +++ b/pkg/visor/rpc_client.go @@ -455,6 +455,13 @@ func (rc *rpcClient) RemoteVisors() ([]string, error) { return output, nil } +// IsDMSGClientReady return availability of dsmg client +func (rc *rpcClient) IsDMSGClientReady() (bool, error) { + var out bool + err := rc.Call("IsDMSGClientReady", &struct{}{}, &out) + return out, err +} + // MockRPCClient mocks API. type mockRPCClient struct { startedAt time.Time @@ -1037,3 +1044,8 @@ func (mc *mockRPCClient) VPNServers(_, _ string) ([]servicedisc.Service, error) func (mc *mockRPCClient) RemoteVisors() ([]string, error) { return []string{}, nil } + +// IsDMSGClientReady implements API. +func (mc *mockRPCClient) IsDMSGClientReady() (bool, error) { + return false, nil +}