Release 3.8.2.3: cheaper poll I/O, batched macOS sysproxy, no Connect Clone.

Trust corebin cache without Stat; batch networksetup; ActiveProxyURI instead of Config.Clone.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
M4
2026-07-30 03:02:19 +03:00
co-authored by Cursor
parent 838f9e340b
commit d1570b23d3
22 changed files with 159 additions and 100 deletions
+10 -2
View File
@@ -325,7 +325,7 @@ func WriteExample(path string) error {
return Save(path, Example())
}
// Save writes config as indented JSON.
// Save writes config as indented JSON (atomic replace).
func Save(path string, cfg Config) error {
if err := cfg.Validate(); err != nil {
return err
@@ -341,7 +341,15 @@ func Save(path string, cfg Config) error {
return err
}
}
return os.WriteFile(path, data, 0o600)
tmp := path + ".tmp"
if err := os.WriteFile(tmp, data, 0o600); err != nil {
return err
}
if err := os.Rename(tmp, path); err != nil {
_ = os.Remove(tmp)
return err
}
return nil
}
// SetActiveProxy updates the active profile proxy URI.
+19 -2
View File
@@ -3,6 +3,7 @@ package config
import (
"fmt"
"strings"
"sync"
)
// ProfileInfo is a safe summary for UI lists (no secrets beyond proxy URI the user already owns).
@@ -14,6 +15,22 @@ type ProfileInfo struct {
Active bool `json:"active"`
}
// hostCache avoids re-parsing large AWG conf bodies on every UI poll.
var hostCache sync.Map // proxy URI/conf → host string
func cachedProxyHost(proxy string) string {
proxy = strings.TrimSpace(proxy)
if proxy == "" {
return ""
}
if v, ok := hostCache.Load(proxy); ok {
return v.(string)
}
h := proxyHost(proxy)
hostCache.Store(proxy, h)
return h
}
// ListProfiles returns UI-friendly profile summaries.
func (c *Config) ListProfiles() []ProfileInfo {
out := make([]ProfileInfo, 0, len(c.Profiles))
@@ -22,7 +39,7 @@ func (c *Config) ListProfiles() []ProfileInfo {
Name: p.Name,
Protocol: string(p.Protocol),
Proxy: p.Proxy,
Host: proxyHost(p.Proxy),
Host: cachedProxyHost(p.Proxy),
Active: p.Name == c.Active,
})
}
@@ -36,7 +53,7 @@ func (c *Config) ListProfilesForPoll() []ProfileInfo {
out = append(out, ProfileInfo{
Name: p.Name,
Protocol: string(p.Protocol),
Host: proxyHost(p.Proxy),
Host: cachedProxyHost(p.Proxy),
Active: p.Name == c.Active,
})
}