From e69a81858d77f790c193258dd6082966edcec1a6 Mon Sep 17 00:00:00 2001 From: nange Date: Thu, 25 Jan 2024 17:52:38 +0800 Subject: [PATCH] feat: display ping latency with server on server menu item of system tray --- background.go | 39 +++++++++++++++++++++++++++------ cmd/easyss/tray.go | 54 +++++++++++++++++++++++++++++++--------------- easyss.go | 6 ++++++ go.mod | 4 ++-- go.sum | 12 +++++------ 5 files changed, 84 insertions(+), 31 deletions(-) diff --git a/background.go b/background.go index 8b6ecfb7..ea2b0188 100644 --- a/background.go +++ b/background.go @@ -30,6 +30,9 @@ func (ss *Easyss) background() { } ticker2 := time.NewTicker(time.Duration(n) * time.Second) defer ticker2.Stop() + + go ss.pingOnce() + for { select { case <-ticker.C: @@ -37,11 +40,7 @@ func (ss *Easyss) background() { receiveSize := ss.stat.BytesReceive.Load() / (1024 * 1024) log.Info("[EASYSS_BACKGROUND]", "send_size(MB)", sendSize, "receive_size(MB)", receiveSize) case <-ticker2.C: - since, err := ss.pingTest() - if err != nil { - continue - } - log.Info("[EASYSS_BACKGROUND] ping easyss-server", "latency", since.String()) + go ss.pingOnce() case <-tickerExec.C: go ss.cmdInterval(ss.config.CMDInterval) case <-closing: @@ -50,7 +49,35 @@ func (ss *Easyss) background() { } } -func (ss *Easyss) pingTest() (time.Duration, error) { +func (ss *Easyss) pingOnce() { + var since time.Duration + var err error + for i := 1; i <= 3; i++ { + since, err = ss.pingLatency() + if err != nil { + time.Sleep(time.Duration(i) * time.Second) + continue + } + break + } + if err != nil { + log.Error("[EASYSS_BACKGROUND] ping", "err", err) + select { + case ss.pingLatCh <- "error": + default: + } + return + } + + since = (since / time.Millisecond) * time.Millisecond + select { + case ss.pingLatCh <- since.String(): + default: + } + log.Info("[EASYSS_BACKGROUND] ping", "latency", since.String()) +} + +func (ss *Easyss) pingLatency() (time.Duration, error) { conn, err := ss.AvailableConn(true) if err != nil { log.Error("[EASYSS_BACKGROUND] got available conn for ping test", "err", err) diff --git a/cmd/easyss/tray.go b/cmd/easyss/tray.go index 64c76ab0..25a534d5 100644 --- a/cmd/easyss/tray.go +++ b/cmd/easyss/tray.go @@ -7,6 +7,7 @@ import ( "os" "runtime" "sync" + "time" "github.com/getlantern/systray" "github.com/nange/easyss/v2" @@ -60,18 +61,15 @@ func (st *SysTray) AddSelectServerMenu() { var subMenuItems []*systray.MenuItem addrs := st.SS().ServerListAddrs() - if len(addrs) > 0 { - for _, addr := range addrs { - item := selectServer.AddSubMenuItemCheckbox(addr, "服务器地址", false) - subMenuItems = append(subMenuItems, item) - if addr == st.SS().ServerAddr() { - item.Check() - } - } - } else { - item := selectServer.AddSubMenuItemCheckbox(st.SS().ServerAddr(), "服务器地址", false) + if len(addrs) == 0 { + addrs = []string{st.SS().ServerAddr()} + } + for _, addr := range addrs { + item := selectServer.AddSubMenuItemCheckbox(addr, "服务器地址", false) subMenuItems = append(subMenuItems, item) - item.Check() + if addr == st.SS().ServerAddr() { + item.Check() + } } for i, item := range subMenuItems { @@ -107,28 +105,50 @@ func (st *SysTray) AddSelectServerMenu() { }(i, item) } + + // display server ping latency on menu item + go func() { + ticker := time.NewTicker(5 * time.Second) + defer ticker.Stop() + for { + ch := st.SS().PingLatencyCh() + select { + case lat := <-ch: + for i, subItem := range subMenuItems { + if subItem.Checked() { + addr := addrs[i] + subItem.SetTitle(fmt.Sprintf("%s %s", addr, lat)) + break + } + } + case <-ticker.C: + case <-st.closing: + return + } + } + }() } func (st *SysTray) AddProxyRuleMenu() (*systray.MenuItem, *systray.MenuItem, *systray.MenuItem) { - proxyMenue := systray.AddMenuItem("代理规则", "请选择") + proxyMenu := systray.AddMenuItem("代理规则", "请选择") - auto := proxyMenue.AddSubMenuItemCheckbox("自动(自定义规则+绕过大陆IP域名)", "自动判断请求是否走代理", false) + auto := proxyMenu.AddSubMenuItemCheckbox("自动(自定义规则+绕过大陆IP域名)", "自动判断请求是否走代理", false) if st.SS().ProxyRule() == easyss.ProxyRuleAuto { auto.Check() } - autoBlock := proxyMenue.AddSubMenuItemCheckbox("自动+屏蔽广告跟踪", "自动判断请求是否走代理或者屏蔽", false) + autoBlock := proxyMenu.AddSubMenuItemCheckbox("自动+屏蔽广告跟踪", "自动判断请求是否走代理或者屏蔽", false) if st.SS().ProxyRule() == easyss.ProxyRuleAutoBlock { autoBlock.Check() } - reverseAuto := proxyMenue.AddSubMenuItemCheckbox("反向自动(国外访问国内)", "适用国外访问国内IP域名", false) - proxy := proxyMenue.AddSubMenuItemCheckbox("代理全部(绕过局域网地址)", "代理除局域网地址的所有请求", false) + reverseAuto := proxyMenu.AddSubMenuItemCheckbox("反向自动(国外访问国内)", "适用国外访问国内IP域名", false) + proxy := proxyMenu.AddSubMenuItemCheckbox("代理全部(绕过局域网地址)", "代理除局域网地址的所有请求", false) if st.SS().ProxyRule() == easyss.ProxyRuleProxy { proxy.Check() } - direct := proxyMenue.AddSubMenuItemCheckbox("直接连接", "所有请求直接连接,不走代理", false) + direct := proxyMenu.AddSubMenuItemCheckbox("直接连接", "所有请求直接连接,不走代理", false) if st.SS().ProxyRule() == easyss.ProxyRuleDirect { direct.Check() } diff --git a/easyss.go b/easyss.go index 0c8ef337..e75de39d 100644 --- a/easyss.go +++ b/easyss.go @@ -201,6 +201,9 @@ type Easyss struct { // only used for http outbound proto httpOutboundClient *req.Client + // used for system tray display + pingLatCh chan string + // the mu Mutex to protect below fields mu *sync.RWMutex tcpPool easypool.Pool @@ -218,6 +221,7 @@ func New(config *Config) (*Easyss, error) { stat: &Statistics{}, dnsCache: freecache.NewCache(DefaultDNSCacheSize), directDNSCache: freecache.NewCache(DefaultDNSCacheSize), + pingLatCh: make(chan string, 1), closing: make(chan struct{}, 1), mu: &sync.RWMutex{}, } @@ -589,6 +593,8 @@ func (ss *Easyss) ServerList() []ServerConfig { return ss.config.ServerList } +func (ss *Easyss) PingLatencyCh() chan string { return ss.pingLatCh } + func (ss *Easyss) ServerListAddrs() []string { var list []string for _, s := range ss.config.ServerList { diff --git a/go.mod b/go.mod index 46c302ff..5110a8ab 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/imroc/req/v3 v3.42.3 github.com/klauspost/compress v1.17.4 github.com/libp2p/go-netroute v0.2.1 - github.com/miekg/dns v1.1.57 + github.com/miekg/dns v1.1.58 github.com/nange/easypool v1.3.1 github.com/oschwald/geoip2-golang v1.9.0 github.com/refraction-networking/utls v1.6.1 @@ -76,7 +76,7 @@ require ( golang.org/x/sys v0.16.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.16.1 // indirect + golang.org/x/tools v0.17.0 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect golang.zx2c4.com/wireguard v0.0.0-20231022001213-2e0774f246fb // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 5b772537..3032fc86 100644 --- a/go.sum +++ b/go.sum @@ -93,8 +93,8 @@ github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30= github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE= github.com/miekg/dns v1.1.51/go.mod h1:2Z9d3CP1LQWihRZUf29mQ19yDThaI4DAYzte2CaQW5c= -github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= -github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk= +github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= +github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= github.com/nange/easypool v1.3.1 h1:H08lgMheGnJJtHmj9DQqQJ0ALLYm9YgId88QQcP/8nI= github.com/nange/easypool v1.3.1/go.mod h1:thcZ8jRQmaMuhSsmUhbjUUvqQsZOZa6fZFxqnGTNEmw= github.com/onsi/ginkgo/v2 v2.13.2 h1:Bi2gGVkfn6gQcjNjZJVO8Gf0FHzMPf2phUei9tejVMs= @@ -180,8 +180,8 @@ golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= -golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -211,8 +211,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= -golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA= -golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= +golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=