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

VPN Control Buttons in Systray #1124

Merged
merged 34 commits into from
Apr 11, 2022
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
4c3a852
update systray to 1.2.0
mrpalide Feb 28, 2022
a2ee40b
add icons
mrpalide Feb 28, 2022
8c11669
make getHTTPClient for systray
mrpalide Mar 2, 2022
39d2d77
alpha testing
mrpalide Mar 4, 2022
f48e687
merge develop into
mrpalide Mar 4, 2022
ca8b036
go mod tidy | go mod vendor
mrpalide Mar 4, 2022
c2d62cd
improve buttons
mrpalide Mar 8, 2022
9d64c94
remove useless icons
mrpalide Mar 8, 2022
f53e5c9
improve logs
mrpalide Mar 8, 2022
71c2378
improve buttons 2
mrpalide Mar 8, 2022
8b20609
change launcher from cmd to powershell
mrpalide Mar 8, 2022
cd60095
merge develop into
mrpalide Mar 8, 2022
2dfa48a
go mod tidy | go mod vendor
mrpalide Mar 8, 2022
a070f8f
update check hypervisor running endpoint
mrpalide Mar 8, 2022
4442488
add extension to windows systray build
mrpalide Mar 8, 2022
7c4fdaa
fix windows systray build name
mrpalide Mar 8, 2022
59a7223
change on/off to connect/disconnect
mrpalide Mar 8, 2022
8da66a1
fix nil pointer error during quit button of systray
mrpalide Mar 8, 2022
3c61f07
Update systray-builds readme
mrpalide Mar 9, 2022
3b6b698
update systray from 1.2.0 to 1.2.1
mrpalide Mar 9, 2022
bdbec6b
move rpcClient in related buttons, not main of systray
mrpalide Mar 9, 2022
9388238
downgrade systray version from 1.2.1 to 1.1.0
mrpalide Mar 16, 2022
e85d7c8
upgrade systray version from 1.1.0 to 1.2.1
mrpalide Mar 18, 2022
2d06434
merge develop into
mrpalide Mar 23, 2022
a322d2e
remove transports cache, and check transports before make route
mrpalide Mar 23, 2022
a0ed03a
Merge branch 'develop' into feature/improve-systray
mrpalide Apr 7, 2022
f213f22
Merge branch 'develop' into feature/improve-systray
mrpalide Apr 7, 2022
a6cdddc
fix some issues
mrpalide Apr 7, 2022
fe25eef
fix dmsg imports
mrpalide Apr 7, 2022
9d70fc0
fix some issues 2
mrpalide Apr 7, 2022
2662f90
Merge develop into
mrpalide Apr 10, 2022
77c1825
clean useless part of skywire-visor
mrpalide Apr 10, 2022
15d7930
typo fixing
mrpalide Apr 11, 2022
82c773b
typo fixing
mrpalide Apr 11, 2022
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
1 change: 0 additions & 1 deletion cmd/skywire-visor/commands/systray.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ func runApp(args ...string) {
}()

conf := initConfig(l, args, confPath)

systray.Run(gui.GetOnGUIReady(sysTrayIcon, conf), gui.OnGUIQuit)

}
Expand Down
1 change: 1 addition & 0 deletions docs/systray-builds.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ $ sudo dnf install gtk3-devel libappindicator-gtk3-devel
```bash
$ sudo pacman -S libappindicator-gtk3 gtk3
```
also need install `libayatana-appindicator`. You can install it by [AUR](https://aur.archlinux.org/packages/libayatana-appindicator).

Other distros might require the installation of said library in their own respective name.

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ require (
github.com/getlantern/golog v0.0.0-20201105130739-9586b8bde3a9 // indirect
github.com/getlantern/hidden v0.0.0-20201229170000-e66e7f878730 // indirect
github.com/getlantern/ops v0.0.0-20200403153110-8476b16edcd6 // indirect
github.com/getlantern/systray v1.1.0
github.com/getlantern/systray v1.2.0
github.com/google/go-github v17.0.0+incompatible
github.com/google/uuid v1.1.2
github.com/gorilla/securecookie v1.1.1
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,8 @@ github.com/getlantern/hidden v0.0.0-20201229170000-e66e7f878730/go.mod h1:6mmzY2
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA=
github.com/getlantern/ops v0.0.0-20200403153110-8476b16edcd6 h1:QthAQCekS1YOeYWSvoHI6ZatlG4B+GBDLxV/2ZkBsTA=
github.com/getlantern/ops v0.0.0-20200403153110-8476b16edcd6/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA=
github.com/getlantern/systray v1.1.0 h1:U0wCEqseLi2ok1fE6b88gJklzriavPJixZysZPkZd/Y=
github.com/getlantern/systray v1.1.0/go.mod h1:AecygODWIsBquJCJFop8MEQcJbWFfw/1yWbVabNgpCM=
github.com/getlantern/systray v1.2.0 h1:MsAdOcmOnm4V+r3HFONDszdZeoj7E3q2dEvsPdsxXtI=
github.com/getlantern/systray v1.2.0/go.mod h1:AecygODWIsBquJCJFop8MEQcJbWFfw/1yWbVabNgpCM=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
Expand Down
264 changes: 225 additions & 39 deletions internal/gui/gui.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
package gui

import (
"context"
"embed"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"strings"
"sync"
Expand All @@ -16,10 +18,19 @@ import (

"github.com/gen2brain/dlgs"
"github.com/getlantern/systray"
"github.com/sirupsen/logrus"
"github.com/skycoin/dmsg"
"github.com/skycoin/dmsg/cipher"
"github.com/skycoin/dmsg/direct"
dmsgdisc "github.com/skycoin/dmsg/disc"
"github.com/skycoin/dmsg/dmsgget"
"github.com/skycoin/dmsg/dmsghttp"
"github.com/skycoin/skycoin/src/util/logging"
"github.com/toqueteos/webbrowser"

"github.com/skycoin/skywire/pkg/servicedisc"
"github.com/skycoin/skywire/pkg/skyenv"
"github.com/skycoin/skywire/pkg/visor"
"github.com/skycoin/skywire/pkg/visor/visorconfig"
)

Expand All @@ -33,8 +44,8 @@ var log = logging.NewMasterLogger()
var (
stopVisorFnMx sync.Mutex
stopVisorFn func()
//vpnClientStatusMu sync.Mutex
//vpnClientStatus bool
closeDmsgDC func()
rpcC visor.API
)

var (
Expand All @@ -44,27 +55,39 @@ var (
var (
mAdvancedButton *systray.MenuItem
mOpenHypervisor *systray.MenuItem
//mVPNClient *systray.MenuItem
mVPNLink *systray.MenuItem
mUninstall *systray.MenuItem
mQuit *systray.MenuItem
mVPNClient *systray.MenuItem
mVPNStatus *systray.MenuItem
mVPNLink *systray.MenuItem
mVPNButton *systray.MenuItem
mUninstall *systray.MenuItem
mQuit *systray.MenuItem
)

// GetOnGUIReady creates func to run on GUI startup.
func GetOnGUIReady(icon []byte, conf *visorconfig.V1) func() {
doneCh := make(chan bool, 1)
logger := logging.NewMasterLogger()
logger.SetLevel(logrus.InfoLevel)

httpC := getHTTPClient(conf, context.Background(), logger)

rpc_logger := logger.PackageLogger("systray:rpc_client")
hvAddr := getHVAddr(conf)
for !isHypervisorRunning(hvAddr) {
rpc_logger.Info("Waiting for RPC get ready...")
time.Sleep(2 * time.Second)
}
rpcC = rpcClient(conf, rpc_logger)

return func() {
systray.SetTemplateIcon(icon, icon)

systray.SetTooltip("Skywire")

initOpenVPNLinkBtn(conf)
initAdvancedButton(conf)
//initVpnClientBtn()
initVpnClientBtn(conf, httpC, rpcC, logger)
initQuitBtn()

//go updateVPNConnectionStatus(conf, doneCh)

go handleUserInteraction(conf, doneCh)
}
}
Expand Down Expand Up @@ -96,7 +119,6 @@ func Stop() {
if !atomic.CompareAndSwapInt32(&guiStopped, 0, 1) {
return
}

stopVisor()
systray.Quit()
}
Expand Down Expand Up @@ -168,13 +190,102 @@ func initOpenVPNLinkBtn(vc *visorconfig.V1) {
}()
}

//func initVpnClientBtn() {
// mVPNClient = systray.AddMenuItem("VPN", "VPN Client Connection")
//}
func initVpnClientBtn(conf *visorconfig.V1, httpClient *http.Client, rpcClient visor.API, logger *logging.MasterLogger) {
mVPNClient := systray.AddMenuItem("VPN", "VPN Client Submenu")
// VPN Status
mVPNStatus = mVPNClient.AddSubMenuItem("Status: Disconnect", "VPN Client Status")
mVPNStatus.Disable()
go vpnStatusBtn(conf, rpcClient)
// VPN On/Off Button
mVPNButton = mVPNClient.AddSubMenuItem("On", "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, mVPNServers, rpcClient)
}

func vpnStatusBtn(conf *visorconfig.V1, rpcClient visor.API) {
for {
stats, _ := rpcClient.GetAppConnectionsSummary(skyenv.VPNClientName)
if len(stats) == 1 {
if stats[0].IsAlive {
mVPNStatus.SetTitle("Status: Connected")
mVPNButton.SetTitle("Off")
ersonp marked this conversation as resolved.
Show resolved Hide resolved
mVPNButton.Enable()
} else {
mVPNStatus.SetTitle("Status: Connecting...")
mVPNButton.SetTitle("Off")
ersonp marked this conversation as resolved.
Show resolved Hide resolved
mVPNButton.Disable()
}
} else {
mVPNStatus.SetTitle("Status: Disconnected")
mVPNButton.SetTitle("On")
mVPNButton.Enable()
}
time.Sleep(3 * time.Second)
}
}

func serversBtn(conf *visorconfig.V1, servers []*systray.MenuItem, rpcClient visor.API) {
btnChannel := make(chan int)
for index, server := range servers {
go func(chn chan int, server *systray.MenuItem, index int) {

select {
case <-server.ClickedCh:
chn <- index
}
}(btnChannel, server, index)
}

for {
selectedServer := servers[<-btnChannel]
serverTempValue := strings.Split(selectedServer.String(), ",")[2]
serverPK := serverTempValue[2 : len(serverTempValue)-5]
for _, server := range servers {
server.Uncheck()
server.Enable()
}
selectedServer.Check()
selectedServer.Disable()
pk := cipher.PubKey{}
if err := pk.UnmarshalText([]byte(serverPK)); err != nil {
continue
}

rpcClient.StopApp(skyenv.VPNClientName)
rpcClient.SetAppPK(skyenv.VPNClientName, pk)
rpcClient.StartApp(skyenv.VPNClientName)
}
}

//func handleVpnClientButton(conf *visorconfig.V1) {
// //mVPNClient.AddSubMenuItem()
//}
func handleVPNButton(conf *visorconfig.V1, rpcClient visor.API) {
stats, _ := rpcClient.GetAppConnectionsSummary(skyenv.VPNClientName)
if len(stats) == 1 {
if stats[0].IsAlive {
mVPNStatus.SetTitle("Status: Disconnecting...")
mVPNButton.Disable()
mVPNButton.SetTitle("On")
if err := rpcClient.StopApp(skyenv.VPNClientName); err != nil {
mVPNStatus.SetTitle("Status: Connected")
mVPNButton.Enable()
mVPNButton.SetTitle("Off")
}
}
} else {
mVPNStatus.SetTitle("Status: Connecting...")
mVPNButton.Disable()
mVPNButton.SetTitle("Off")
if err := rpcClient.StartApp(skyenv.VPNClientName); err != nil {
mVPNStatus.SetTitle("Status: Disconnected")
mVPNButton.Enable()
mVPNButton.SetTitle("On")
}
}
}

func handleVPNLinkButton(conf *visorconfig.V1) {
vpnAddr := getVPNAddr(conf)
Expand All @@ -190,26 +301,91 @@ func handleVPNLinkButton(conf *visorconfig.V1) {
}
}

// GetAvailPublicVPNServers gets all available public VPN server from service discovery URL
// func GetAvailPublicVPNServers(conf *visorconfig.V1) []string {
// sdClient := servicedisc.NewClient(log, servicedisc.Config{
// Type: servicedisc.ServiceTypeVPN,
// PK: conf.PK,
// SK: conf.SK,
// DiscAddr: conf.Launcher.ServiceDisc,
// })
// //ctx, _ := context.WithTimeout(context.Background(), 7*time.Second)
// vpnServers, err := sdClient.Services(context.Background(), 0)
// if err != nil {
// log.Error("Error getting public vpn servers: ", err)
// return nil
// }
// serverAddrs := make([]string, len(vpnServers))
// for idx, server := range vpnServers {
// serverAddrs[idx] = server.Addr.PubKey().String()
// }
// return serverAddrs
// }
// getAvailPublicVPNServers gets all available public VPN server from service discovery URL
func getAvailPublicVPNServers(conf *visorconfig.V1, httpC *http.Client, logger *logging.Logger) []string {

svrConfig := servicedisc.Config{
Type: servicedisc.ServiceTypeVPN,
PK: conf.PK,
SK: conf.SK,
DiscAddr: conf.Launcher.ServiceDisc,
}
sdClient := servicedisc.NewClient(log, log, svrConfig, httpC, "")
vpnServers, err := sdClient.Services(context.Background(), 0)
if err != nil {
logger.Error("Error getting vpn servers: ", err)
return nil
}
serverAddrs := make([]string, len(vpnServers))
for idx, server := range vpnServers {
serverAddrs[idx] = server.Addr.PubKey().String() + ";" + server.Geo.Country
}
return serverAddrs
}

func getHTTPClient(conf *visorconfig.V1, ctx context.Context, logger *logging.MasterLogger) *http.Client {
var serviceURL dmsgget.URL
serviceURL.Fill(conf.Launcher.ServiceDisc)
if serviceURL.Scheme == "dmsg" {
var keys cipher.PubKeys
servers := conf.Dmsg.Servers
var delegatedServers []cipher.PubKey

if len(servers) == 0 {
return &http.Client{}
}

pk, sk := cipher.GenerateKeyPair()
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"),
pk, sk, dClient, dmsg.DefaultConfig())
if err != nil {
return &http.Client{}
}
dmsgHTTP := http.Client{Transport: dmsghttp.MakeHTTPTransport(ctx, dmsgDC)}

servers, err = dClient.AvailableServers(ctx)
if err != nil {
closeDmsg()
return &http.Client{}
}

for _, server := range servers {
delegatedServers = append(delegatedServers, server.Static)
}

clientEntry := &dmsgdisc.Entry{
Client: &dmsgdisc.Client{
DelegatedServers: delegatedServers,
},
Static: serviceURL.Addr.PK,
}

err = dClient.PostEntry(ctx, clientEntry)
if err != nil {
closeDmsg()
return &http.Client{}
}
closeDmsgDC = closeDmsg
return &dmsgHTTP
}
return &http.Client{}
}

func isSetVPNClientPKExist(conf *visorconfig.V1) bool {
for _, v := range conf.Launcher.Apps {
if v.Name == skyenv.VPNClientName {
for index := range v.Args {
if v.Args[index] == "-srv" {
return true
}
}
}
}
return false
}

func initUninstallBtn() {
if !checkIsPackage() {
Expand All @@ -226,8 +402,8 @@ func handleUserInteraction(conf *visorconfig.V1, doneCh chan<- bool) {
select {
case <-mOpenHypervisor.ClickedCh:
handleOpenHypervisor(conf)
//case <-mVPNClient.ClickedCh:
// handleVpnClientButton(conf)
case <-mVPNButton.ClickedCh:
handleVPNButton(conf, rpcC)
case <-mVPNLink.ClickedCh:
handleVPNLinkButton(conf)
case <-mUninstall.ClickedCh:
Expand Down Expand Up @@ -269,6 +445,7 @@ func handleUninstall() {

func stopVisor() {
stopVisorFnMx.Lock()
closeDmsgDC()
stop := stopVisorFn
stopVisorFnMx.Unlock()

Expand Down Expand Up @@ -346,3 +523,12 @@ func getVPNAddr(conf *visorconfig.V1) string {

return hvAddr + "/#/vpn/" + conf.PK.Hex() + "/status"
}

func rpcClient(conf *visorconfig.V1, logger *logging.Logger) visor.API {
const rpcDialTimeout = time.Second * 5
conn, err := net.DialTimeout("tcp", conf.CLIAddr, rpcDialTimeout)
if err != nil {
logger.Fatal("RPC connection failed:", err)
}
return visor.NewRPCClient(logger, conn, visor.RPCPrefix, 0)
}
2 changes: 1 addition & 1 deletion scripts/win_installer/skywire.bat
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
@Echo Off
%1 mshta vbscript:CreateObject("Shell.Application").ShellExecute("cmd.exe","/c %~s0 ::","","runas",1)(window.close)&&exit
%1 mshta vbscript:CreateObject("Shell.Application").ShellExecute("powershell.exe","/c %~s0 ::","","runas",1)(window.close)&&exit
cd /d "%~dp0"
if exist vpn-client.exe (
if not exist "apps\" (
Expand Down
Loading