Release 3.8.2.11: idle rev-cache, port-safe Connect, single-instance tray UX.
ci / test (macos-latest) (push) Canceled after 0s
ci / test (ubuntu-latest) (push) Canceled after 0s
ci / test (windows-latest) (push) Canceled after 0s

Faster unchanged polls; orphan-core cleanup on listen ports; clearer busy-port errors; cores only from binDir; incremental server list; CSP without Google Fonts; single-instance activates existing window; close-to-tray without kill-others or balloon.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
M4
2026-08-01 17:27:47 +03:00
co-authored by Cursor
parent fed1ace33e
commit 57d719f02f
45 changed files with 876 additions and 285 deletions
+26 -1
View File
@@ -16,6 +16,8 @@ import (
"vpnclient/internal/config"
"vpnclient/internal/corebin"
"vpnclient/internal/linknorm"
"vpnclient/internal/listenutil"
"vpnclient/internal/netcheck"
"vpnclient/internal/protocols/awg"
"vpnclient/internal/protocols/hysteria2"
"vpnclient/internal/protocols/naive"
@@ -108,12 +110,19 @@ func (m *Manager) Connect(ctx context.Context, profileName string) error {
stderr := m.stderr
m.mu.Unlock()
socksHP, _ := profileCopy.SOCKSListenHostPort()
httpHP, _ := profileCopy.HTTPListenHostPort()
listenAddrs := listenutil.ListenAddrs(socksHP, httpHP)
if err := listenutil.EnsureFree(binDir, listenAddrs...); err != nil {
return err
}
engine, err := m.newEngine(profileCopy.Protocol)
if err != nil {
return err
}
if err := engine.Start(ctx, profileCopy, binDir); err != nil {
return err
return listenutil.ClassifyStartFailure(string(profileCopy.Protocol), err, listenAddrs...)
}
m.mu.Lock()
@@ -626,6 +635,22 @@ func (m *Manager) Profiles() []config.ProfileInfo {
return m.cfg.ListProfiles()
}
// PingTargets returns name/protocol/host endpoints without copying proxy secrets.
func (m *Manager) PingTargets() []netcheck.Target {
m.mu.Lock()
defer m.mu.Unlock()
list := m.cfg.ListProfilesForPoll()
out := make([]netcheck.Target, 0, len(list))
for _, p := range list {
out = append(out, netcheck.Target{
Name: p.Name,
Protocol: config.Protocol(p.Protocol),
Host: p.Host,
})
}
return out
}
// Hy2Options are editable Hysteria 2 extras for the active profile.
type Hy2Options struct {
Congestion string `json:"congestion"`