Release 2.7.3.1: harden proxy recovery, updates and local API.
Restore orphaned system proxy after crash, require update SHA-256, add macOS /api auth token, fix UDP ping false positives, HTTPS-only subscriptions, and keep the UI responsive during connect. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -58,10 +58,11 @@ func main() {
|
||||
}()
|
||||
}
|
||||
|
||||
ln, uiURL, err := apphost.ListenLocal()
|
||||
ln, uiURL, token, err := apphost.ListenLocal()
|
||||
if err != nil {
|
||||
fatalf("listen: %v", err)
|
||||
}
|
||||
a.APIToken = token
|
||||
srv := &http.Server{Handler: a.Handler()}
|
||||
go func() {
|
||||
_ = srv.Serve(ln)
|
||||
|
||||
@@ -203,7 +203,7 @@ func (a *app) getState() (uiState, error) {
|
||||
CoreReady: coreReady,
|
||||
CorePath: corePath,
|
||||
ConfigPath: a.cfgPath,
|
||||
Profiles: cfg.ListProfiles(),
|
||||
Profiles: config.RedactProfileList(cfg.ListProfiles()),
|
||||
Version: update.DisplayVersion(),
|
||||
Update: a.updateStatus,
|
||||
Pings: append([]netcheck.Result(nil), a.pings...),
|
||||
@@ -263,30 +263,36 @@ func (a *app) connect() error {
|
||||
// If already connected to another profile, disconnects first.
|
||||
func (a *app) connectProfile(name string) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
|
||||
name = strings.TrimSpace(name)
|
||||
st := a.mgr.Status()
|
||||
if st.Connected {
|
||||
if name == "" || st.Profile == name {
|
||||
a.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
a.mu.Unlock()
|
||||
if err := a.mgr.Disconnect(); err != nil {
|
||||
return err
|
||||
}
|
||||
a.mu.Lock()
|
||||
}
|
||||
if name != "" {
|
||||
if err := a.mgr.SetActiveProfile(name); err != nil {
|
||||
a.mu.Unlock()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if p, err := a.mgr.Config().ActiveProfile(); err != nil {
|
||||
a.mu.Unlock()
|
||||
return err
|
||||
} else if strings.TrimSpace(p.Proxy) == "" {
|
||||
a.mu.Unlock()
|
||||
return fmt.Errorf("сначала вставьте ссылку сервера")
|
||||
}
|
||||
a.mu.Unlock()
|
||||
|
||||
// Do not hold a.mu across EnsureCore/Connect — getState polling would freeze the UI.
|
||||
if _, err := a.mgr.EnsureCore(""); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -301,8 +307,6 @@ func (a *app) disconnect() error {
|
||||
}
|
||||
|
||||
func (a *app) installCore() (string, error) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
paths, err := a.mgr.EnsureAllCores()
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -352,32 +356,40 @@ func (a *app) pingBest(autoConnect bool) (pingBestResult, error) {
|
||||
out.BestMs = best.Ms
|
||||
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
st := a.mgr.Status()
|
||||
alreadyBest := st.Connected && st.Profile == best.Name
|
||||
if st.Connected && !alreadyBest {
|
||||
a.mu.Unlock()
|
||||
if err := a.mgr.Disconnect(); err != nil {
|
||||
return out, err
|
||||
}
|
||||
a.mu.Lock()
|
||||
}
|
||||
if !alreadyBest {
|
||||
if err := a.mgr.SetActiveProfile(best.Name); err != nil {
|
||||
a.mu.Unlock()
|
||||
return out, err
|
||||
}
|
||||
}
|
||||
out.Selected = true
|
||||
if !autoConnect {
|
||||
a.mu.Unlock()
|
||||
return out, nil
|
||||
}
|
||||
if alreadyBest {
|
||||
a.mu.Unlock()
|
||||
out.Connected = true
|
||||
return out, nil
|
||||
}
|
||||
if p, err := a.mgr.Config().ActiveProfile(); err != nil {
|
||||
a.mu.Unlock()
|
||||
return out, err
|
||||
} else if strings.TrimSpace(p.Proxy) == "" {
|
||||
a.mu.Unlock()
|
||||
return out, fmt.Errorf("пустая ссылка у лучшего сервера")
|
||||
}
|
||||
a.mu.Unlock()
|
||||
|
||||
if _, err := a.mgr.EnsureCore(""); err != nil {
|
||||
return out, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user