Release 3.8.2.11: idle rev-cache, port-safe Connect, single-instance tray UX.
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:
@@ -16,6 +16,7 @@ const githubAPILatest = "https://api.github.com/repos/apernet/hysteria/releases/
|
||||
// ResolveBinary finds hysteria client binary.
|
||||
func ResolveBinary(binDir string) (string, error) {
|
||||
names := candidateNames()
|
||||
// Only trusted binDir (not beside the app exe) — avoids local binary plant.
|
||||
candidates := []string{}
|
||||
for _, name := range names {
|
||||
candidates = append(candidates,
|
||||
@@ -24,12 +25,6 @@ func ResolveBinary(binDir string) (string, error) {
|
||||
filepath.Join(binDir, "hysteria", name),
|
||||
)
|
||||
}
|
||||
if exe, err := os.Executable(); err == nil {
|
||||
dir := filepath.Dir(exe)
|
||||
for _, name := range names {
|
||||
candidates = append(candidates, filepath.Join(dir, name), filepath.Join(dir, "bin", name))
|
||||
}
|
||||
}
|
||||
for _, c := range candidates {
|
||||
if st, err := os.Stat(c); err == nil && !st.IsDir() {
|
||||
return c, nil
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"time"
|
||||
|
||||
"vpnclient/internal/config"
|
||||
"vpnclient/internal/listenutil"
|
||||
)
|
||||
|
||||
// Engine runs the official apernet/hysteria client (Hysteria 2).
|
||||
@@ -102,7 +103,11 @@ func (e *Engine) Start(ctx context.Context, profile config.Profile, binDir strin
|
||||
var startErr error
|
||||
select {
|
||||
case <-done:
|
||||
startErr = fmt.Errorf("hysteria2: process exited immediately; check URI/password and binary")
|
||||
socks, _ := profile.SOCKSListenHostPort()
|
||||
httpL, _ := profile.HTTPListenHostPort()
|
||||
startErr = listenutil.ClassifyStartFailure("hysteria2",
|
||||
fmt.Errorf("hysteria2: process exited immediately; check URI/password and binary"),
|
||||
socks, httpL)
|
||||
case <-ctx.Done():
|
||||
_ = e.Stop()
|
||||
startErr = ctx.Err()
|
||||
|
||||
@@ -21,14 +21,11 @@ func ResolveBinary(binDir string) (string, error) {
|
||||
if runtime.GOOS == "windows" {
|
||||
name = "naive.exe"
|
||||
}
|
||||
// Only trusted binDir (not beside the app exe) — avoids local binary plant.
|
||||
candidates := []string{
|
||||
filepath.Join(binDir, name),
|
||||
filepath.Join(binDir, "naiveproxy", name),
|
||||
}
|
||||
if exe, err := os.Executable(); err == nil {
|
||||
candidates = append(candidates, filepath.Join(filepath.Dir(exe), name))
|
||||
candidates = append(candidates, filepath.Join(filepath.Dir(exe), "bin", name))
|
||||
}
|
||||
for _, c := range candidates {
|
||||
if st, err := os.Stat(c); err == nil && !st.IsDir() {
|
||||
return c, nil
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"time"
|
||||
|
||||
"vpnclient/internal/config"
|
||||
"vpnclient/internal/listenutil"
|
||||
)
|
||||
|
||||
// Engine runs the official Chromium-based naive binary.
|
||||
@@ -105,7 +106,11 @@ func (e *Engine) Start(ctx context.Context, profile config.Profile, binDir strin
|
||||
var startErr error
|
||||
select {
|
||||
case <-done:
|
||||
startErr = fmt.Errorf("naive: process exited immediately; check proxy URI, credentials, and binary")
|
||||
socks, _ := profile.SOCKSListenHostPort()
|
||||
httpL, _ := profile.HTTPListenHostPort()
|
||||
startErr = listenutil.ClassifyStartFailure("naive",
|
||||
fmt.Errorf("naive: process exited immediately; check proxy URI, credentials, and binary"),
|
||||
socks, httpL)
|
||||
case <-ctx.Done():
|
||||
_ = e.Stop()
|
||||
startErr = ctx.Err()
|
||||
|
||||
@@ -17,15 +17,12 @@ const githubAPILatest = "https://api.github.com/repos/XTLS/Xray-core/releases/la
|
||||
|
||||
// ResolveBinary finds xray executable.
|
||||
func ResolveBinary(binDir string) (string, error) {
|
||||
// Only trusted binDir (not beside the app exe) — avoids local binary plant.
|
||||
for _, name := range candidateNames() {
|
||||
candidates := []string{
|
||||
filepath.Join(binDir, name),
|
||||
filepath.Join(binDir, "xray", name),
|
||||
}
|
||||
if exe, err := os.Executable(); err == nil {
|
||||
dir := filepath.Dir(exe)
|
||||
candidates = append(candidates, filepath.Join(dir, name), filepath.Join(dir, "bin", name))
|
||||
}
|
||||
for _, c := range candidates {
|
||||
if st, err := os.Stat(c); err == nil && !st.IsDir() {
|
||||
return c, nil
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"time"
|
||||
|
||||
"vpnclient/internal/config"
|
||||
"vpnclient/internal/listenutil"
|
||||
)
|
||||
|
||||
// Engine runs official XTLS/Xray-core for VLESS / VMess / Trojan.
|
||||
@@ -106,7 +107,11 @@ func (e *Engine) Start(ctx context.Context, profile config.Profile, binDir strin
|
||||
var startErr error
|
||||
select {
|
||||
case <-done:
|
||||
startErr = fmt.Errorf("xray: process exited immediately; check link and install-core (xray)")
|
||||
socks, _ := profile.SOCKSListenHostPort()
|
||||
httpL, _ := profile.HTTPListenHostPort()
|
||||
startErr = listenutil.ClassifyStartFailure("xray",
|
||||
fmt.Errorf("xray: process exited immediately; check link and install-core (xray)"),
|
||||
socks, httpL)
|
||||
case <-ctx.Done():
|
||||
_ = e.Stop()
|
||||
startErr = ctx.Err()
|
||||
|
||||
Reference in New Issue
Block a user