Release 3.8.1.1: lighter idle UI poll, core cache, multicore ping.
Reduce idle CPU (cheap PollUI, binary cache, logbuf cap, DOM fingerprint), speed ping/AWG HostPort, CopyBuffer pool; ship arm64 build and update notes. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+49
-47
@@ -1,7 +1,6 @@
|
||||
package apphost
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
@@ -18,6 +17,8 @@ import (
|
||||
"vpnclient/internal/appui"
|
||||
"vpnclient/internal/config"
|
||||
"vpnclient/internal/core"
|
||||
"vpnclient/internal/corebin"
|
||||
"vpnclient/internal/logbuf"
|
||||
"vpnclient/internal/netcheck"
|
||||
"vpnclient/internal/protocols/awg"
|
||||
"vpnclient/internal/protocols/hysteria2"
|
||||
@@ -31,7 +32,7 @@ type App struct {
|
||||
mu sync.Mutex
|
||||
Mgr *core.Manager
|
||||
CfgPath string
|
||||
LogBuf *bytes.Buffer
|
||||
LogBuf *logbuf.Buffer
|
||||
UpdateStatus update.Status
|
||||
Pings []netcheck.Result
|
||||
OpenURL func(string) error
|
||||
@@ -67,7 +68,7 @@ type PingBestResult struct {
|
||||
Connected bool `json:"connected"`
|
||||
}
|
||||
|
||||
func New(mgr *core.Manager, cfgPath string, logBuf *bytes.Buffer) *App {
|
||||
func New(mgr *core.Manager, cfgPath string, logBuf *logbuf.Buffer) *App {
|
||||
return &App{
|
||||
Mgr: mgr,
|
||||
CfgPath: cfgPath,
|
||||
@@ -89,71 +90,53 @@ func (a *App) GetEditState() (UIState, error) {
|
||||
}
|
||||
|
||||
func (a *App) getState(includeSecrets bool) (UIState, error) {
|
||||
// Hold App.mu only for fields mutated by update/ping handlers.
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
upd := a.UpdateStatus
|
||||
pings := append([]netcheck.Result(nil), a.Pings...)
|
||||
cfgPath := a.CfgPath
|
||||
a.mu.Unlock()
|
||||
|
||||
st := a.Mgr.Status()
|
||||
cfg := a.Mgr.Config()
|
||||
proxy := ""
|
||||
active := cfg.Active
|
||||
if p, err := cfg.ActiveProfile(); err == nil {
|
||||
proxy = p.Proxy
|
||||
active = p.Name
|
||||
}
|
||||
poll := a.Mgr.PollUI(includeSecrets)
|
||||
st := poll.Status
|
||||
proxy := poll.ActiveProxy
|
||||
if !includeSecrets {
|
||||
proxy = config.RedactProxyURI(proxy)
|
||||
}
|
||||
corePath := ""
|
||||
coreReady := false
|
||||
if p, err := cfg.ActiveProfile(); err == nil {
|
||||
switch p.Protocol {
|
||||
case config.ProtocolHysteria2:
|
||||
if path, err := hysteria2.ResolveBinary(a.Mgr.BinDir()); err == nil {
|
||||
corePath, coreReady = path, true
|
||||
}
|
||||
case config.ProtocolAWG:
|
||||
if path, err := awg.ResolveBinary(a.Mgr.BinDir()); err == nil {
|
||||
corePath, coreReady = path, true
|
||||
}
|
||||
case config.ProtocolVLESS, config.ProtocolVMess, config.ProtocolTrojan:
|
||||
if path, err := xray.ResolveBinary(a.Mgr.BinDir()); err == nil {
|
||||
corePath, coreReady = path, true
|
||||
}
|
||||
default:
|
||||
if path, err := naive.ResolveBinary(a.Mgr.BinDir()); err == nil {
|
||||
corePath, coreReady = path, true
|
||||
}
|
||||
}
|
||||
} else if path, err := naive.ResolveBinary(a.Mgr.BinDir()); err == nil {
|
||||
corePath, coreReady = path, true
|
||||
}
|
||||
hy2 := a.Mgr.ActiveHy2Options()
|
||||
hy2 := poll.Hy2
|
||||
if !includeSecrets {
|
||||
hy2.ObfsPassword = ""
|
||||
}
|
||||
|
||||
corePath, coreReady := resolveCoreCached(poll.BinDir, poll.ActiveProtocol)
|
||||
|
||||
profiles := poll.Profiles
|
||||
if includeSecrets {
|
||||
// Editor needs state.Proxy; list still omits other profiles' URIs.
|
||||
profiles = config.RedactProfileList(profiles)
|
||||
}
|
||||
|
||||
out := UIState{
|
||||
Connected: st.Connected,
|
||||
Profile: st.Profile,
|
||||
ActiveProfile: active,
|
||||
ActiveProfile: poll.Active,
|
||||
Protocol: string(st.Protocol),
|
||||
HTTPProxy: st.HTTPProxy,
|
||||
SOCKSProxy: st.SOCKSProxy,
|
||||
SystemProxy: cfg.SystemProxy,
|
||||
SystemProxy: poll.SystemProxy,
|
||||
Proxy: proxy,
|
||||
CoreReady: coreReady,
|
||||
CorePath: corePath,
|
||||
ConfigPath: a.CfgPath,
|
||||
Profiles: config.RedactProfileList(cfg.ListProfiles()),
|
||||
ConfigPath: cfgPath,
|
||||
Profiles: profiles,
|
||||
Version: update.DisplayVersion(),
|
||||
Update: a.UpdateStatus,
|
||||
Pings: append([]netcheck.Result(nil), a.Pings...),
|
||||
Subscription: cfg.SubscriptionURL,
|
||||
Update: upd,
|
||||
Pings: pings,
|
||||
Subscription: poll.Subscription,
|
||||
Hy2: hy2,
|
||||
}
|
||||
if out.Protocol == "" {
|
||||
if p, err := cfg.ActiveProfile(); err == nil {
|
||||
out.Protocol = string(p.Protocol)
|
||||
}
|
||||
out.Protocol = string(poll.ActiveProtocol)
|
||||
}
|
||||
if st.Connected {
|
||||
out.SystemProxy = st.SystemProxy
|
||||
@@ -161,6 +144,25 @@ func (a *App) getState(includeSecrets bool) (UIState, error) {
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func resolveCoreCached(binDir string, proto config.Protocol) (path string, ready bool) {
|
||||
key := corebin.CacheKey(binDir, corebin.ProtoKey(string(proto)))
|
||||
var err error
|
||||
switch proto {
|
||||
case config.ProtocolHysteria2:
|
||||
path, err = corebin.Resolve(key, func() (string, error) { return hysteria2.ResolveBinary(binDir) })
|
||||
case config.ProtocolAWG:
|
||||
path, err = corebin.Resolve(key, func() (string, error) { return awg.ResolveBinary(binDir) })
|
||||
case config.ProtocolVLESS, config.ProtocolVMess, config.ProtocolTrojan:
|
||||
path, err = corebin.Resolve(key, func() (string, error) { return xray.ResolveBinary(binDir) })
|
||||
default:
|
||||
path, err = corebin.Resolve(key, func() (string, error) { return naive.ResolveBinary(binDir) })
|
||||
}
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
return path, true
|
||||
}
|
||||
|
||||
func (a *App) SaveProfile(name, proxy string, systemProxy bool) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
|
||||
Reference in New Issue
Block a user