Files
navi/cmd/vpnapp/gui_desktop.go
T
M4andCursor 2ad376b49e
ci / test (macos-latest) (push) Waiting to run
ci / test (ubuntu-latest) (push) Waiting to run
ci / test (windows-latest) (push) Waiting to run
Release 3.8.2.5: cheaper idle UI poll and tighter hot paths.
Delta getState by rev, pause when hidden, cancellable background loops,
hostCache bounds, unlock PollUI around engine status, corebin singleflight,
PingAll worker pool.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-01 16:13:59 +03:00

115 lines
2.5 KiB
Go

//go:build windows || darwin
package main
import (
"log"
"net/http"
"os"
"os/signal"
"runtime"
"time"
"github.com/crgimenes/glaze"
"vpnclient/internal/apphost"
"vpnclient/internal/config"
"vpnclient/internal/core"
"vpnclient/internal/logbuf"
"vpnclient/internal/trayhost"
"vpnclient/internal/update"
)
func main() {
if update.MaybeFinishUpdate(os.Args[1:]) {
return
}
update.CleanupStaleDownloads()
log.SetFlags(log.LstdFlags | log.Lshortfile)
log.Printf("Navis %s · GOMAXPROCS=%d NumCPU=%d", update.DisplayVersion(), runtime.GOMAXPROCS(0), runtime.NumCPU())
cfgPath, err := config.LocateConfig()
if err != nil {
fatalf("Не удалось найти путь конфига: %v", err)
}
if _, err := os.Stat(cfgPath); os.IsNotExist(err) {
if err := config.WriteExample(cfgPath); err != nil {
fatalf("Не удалось создать конфиг: %v", err)
}
}
cfg, err := config.Load(cfgPath)
if err != nil {
fatalf("Ошибка конфига %s: %v", cfgPath, err)
}
logBuf := logbuf.New(0)
mgr, err := core.NewManager(cfgPath, cfg, logBuf)
if err != nil {
fatalf("%v", err)
}
a := apphost.New(mgr, cfgPath, logBuf)
a.OpenURL = openExternal
a.OnAfterUpdate = func() {
// Hard-exit so the OS unlocks the binary for replacement.
go func() {
time.Sleep(300 * time.Millisecond)
_ = a.Disconnect()
os.Exit(0)
}()
}
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)
}()
a.StartBackground()
trayhost.Start("Navis", trayhost.Hooks{
Connect: func() { _ = a.Connect() },
Disconnect: func() { _ = a.Disconnect() },
Quit: func() {
_ = a.Disconnect()
os.Exit(0)
},
IsUp: func() bool { return a.Mgr.Status().Connected },
})
go a.AutoCheckUpdate()
w, err := glaze.New(false)
if err != nil || w == nil {
log.Printf("webview unavailable (%v); opening default browser", err)
if err2 := openExternal(uiURL); err2 != nil {
_ = srv.Close()
fatalf("Не удалось открыть интерфейс:\n%v\n%v\n%s", err, err2, uiURL)
}
log.Printf("Navis UI: %s", uiURL)
sig := make(chan os.Signal, 1)
signal.Notify(sig, shutdownSignals()...)
<-sig
a.Shutdown()
_ = mgr.Disconnect()
_ = srv.Close()
return
}
defer func() {
a.Shutdown()
_ = mgr.Disconnect()
_ = srv.Close()
w.Destroy()
}()
w.SetTitle("Navis")
w.SetSize(500, 900, glaze.HintNone)
decorateWindow(w)
w.Navigate(uiURL)
log.Printf("Navis UI: %s", uiURL)
w.Run()
}