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
+11 -9
View File
@@ -1,7 +1,7 @@
package corebin
import (
"os"
"strings"
"sync"
)
@@ -15,6 +15,11 @@ func CacheKey(binDir, proto string) string {
return binDir + "\x00" + proto
}
// VirtualPath reports paths that are not on-disk binaries (e.g. embedded AWG).
func VirtualPath(path string) bool {
return strings.HasPrefix(path, "embedded-")
}
// Get returns a cached absolute path if present.
func Get(key string) (string, bool) {
mu.Lock()
@@ -33,22 +38,19 @@ func Set(key, path string) {
mu.Unlock()
}
// Invalidate clears all cached paths (call after EnsureCore / binDir change).
// Invalidate clears all cached paths (call after EnsureCore / binDir change / failed Start).
func Invalidate() {
mu.Lock()
cache = map[string]string{}
mu.Unlock()
}
// Resolve caches the result of fn under key. Stale paths (missing on disk) are refreshed.
// Resolve caches the result of fn under key.
// Hot-path polls trust the cache until Invalidate (no per-poll os.Stat).
// Embedded/virtual paths never touch the filesystem.
func Resolve(key string, fn func() (string, error)) (string, error) {
if path, ok := Get(key); ok {
if _, err := os.Stat(path); err == nil {
return path, nil
}
mu.Lock()
delete(cache, key)
mu.Unlock()
return path, nil
}
path, err := fn()
if err != nil {
+29 -15
View File
@@ -6,7 +6,7 @@ import (
"testing"
)
func TestResolveCacheAndStale(t *testing.T) {
func TestResolveTrustsCacheWithoutStat(t *testing.T) {
Invalidate()
dir := t.TempDir()
path := filepath.Join(dir, "core")
@@ -20,26 +20,40 @@ func TestResolveCacheAndStale(t *testing.T) {
return path, nil
}
if p, err := Resolve(key, fn); err != nil || p != path || calls != 1 {
t.Fatalf("first: path=%q calls=%d err=%v", p, calls, err)
t.Fatalf("first: %q %v calls=%d", p, err, calls)
}
_ = os.Remove(path) // missing on disk — cache still trusted until Invalidate
if p, err := Resolve(key, fn); err != nil || p != path || calls != 1 {
t.Fatalf("cached: path=%q calls=%d err=%v", p, calls, err)
t.Fatalf("cached without Stat: %q %v calls=%d", p, err, calls)
}
_ = os.Remove(path)
if _, err := Resolve(key, fn); err != nil {
// fn returns removed path; Resolve still succeeds but next Stat misses
t.Fatalf("unexpected err after delete before recreate: %v", err)
Invalidate()
if _, err := Resolve(key, fn); err == nil && calls != 2 {
// fn returns deleted path; Resolve still succeeds
}
if calls != 2 {
t.Fatalf("expected refresh call, got %d", calls)
t.Fatalf("after Invalidate expected refresh, calls=%d", calls)
}
if err := os.WriteFile(path, []byte("y"), 0o755); err != nil {
t.Fatal(err)
}
func TestVirtualEmbeddedAWG(t *testing.T) {
Invalidate()
key := CacheKey("/bin", "awg")
calls := 0
p, err := Resolve(key, func() (string, error) {
calls++
return "embedded-amneziawg-go", nil
})
if err != nil || p != "embedded-amneziawg-go" || calls != 1 {
t.Fatalf("%q %v calls=%d", p, err, calls)
}
if p, err := Resolve(key, fn); err != nil || p != path {
t.Fatalf("after recreate: %q %v", p, err)
if !VirtualPath(p) {
t.Fatal("expected virtual")
}
if ProtoKey("vless") != "xray" || ProtoKey("naive") != "naive" {
t.Fatal("ProtoKey")
p2, err := Resolve(key, func() (string, error) {
calls++
return "embedded-amneziawg-go", nil
})
if err != nil || p2 != p || calls != 1 {
t.Fatalf("second: %q calls=%d", p2, calls)
}
}
}