Release 2.7.0: macOS GUI app with the same UI as Windows.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Navis
2026-07-29 16:00:55 +03:00
co-authored by Cursor
parent 6255a0d39b
commit 2d4a797eb1
28 changed files with 703 additions and 59 deletions
+104
View File
@@ -0,0 +1,104 @@
//go:build darwin
package main
import (
"bytes"
"fmt"
"log"
"net/http"
"os"
"os/exec"
"os/signal"
"path/filepath"
"syscall"
"time"
"vpnclient/internal/apphost"
"vpnclient/internal/config"
"vpnclient/internal/core"
"vpnclient/internal/update"
)
func main() {
if update.MaybeFinishUpdate(os.Args[1:]) {
return
}
update.CleanupStaleDownloads()
log.SetFlags(log.LstdFlags | log.Lshortfile)
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 := &bytes.Buffer{}
mgr, err := core.NewManager(cfgPath, cfg, logBuf)
if err != nil {
fatalf("%v", err)
}
a := apphost.New(mgr, cfgPath, logBuf)
a.OpenURL = func(u string) error {
return exec.Command("open", u).Start()
}
a.OnAfterUpdate = func() {
go func() {
time.Sleep(300 * time.Millisecond)
os.Exit(0)
}()
}
ln, uiURL, err := apphost.ListenLocal()
if err != nil {
fatalf("listen: %v", err)
}
srv := &http.Server{Handler: a.Handler()}
go func() {
_ = srv.Serve(ln)
}()
go a.AutoCheckUpdate()
if err := openAppWindow(uiURL); err != nil {
log.Printf("open UI: %v — откройте вручную: %s", err, uiURL)
fmt.Println(uiURL)
} else {
log.Printf("Navis UI: %s", uiURL)
}
sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
<-sig
_ = mgr.Disconnect()
_ = srv.Close()
}
func openAppWindow(uiURL string) error {
// Prefer Chromium-based --app window (looks like a desktop client).
for _, app := range []string{"Google Chrome", "Chromium", "Microsoft Edge", "Brave Browser", "Arc"} {
cmd := exec.Command("open", "-na", app, "--args", "--app="+uiURL, "--new-window")
if err := cmd.Start(); err == nil {
return nil
}
}
// Fallback: default browser
return exec.Command("open", uiURL).Start()
}
func fatalf(format string, args ...any) {
msg := fmt.Sprintf(format, args...)
log.Println(msg)
_ = exec.Command("osascript", "-e", fmt.Sprintf(`display alert "Navis" message %q`, msg)).Run()
os.Exit(1)
}
// Ensure we keep a reference for potential future dock icon path helpers.
var _ = filepath.Separator
+3 -3
View File
@@ -1,4 +1,4 @@
//go:build !windows
//go:build !windows && !darwin
package main
@@ -8,7 +8,7 @@ import (
)
func main() {
fmt.Fprintln(os.Stderr, "Navis GUI (WebView2) is Windows-only.")
fmt.Fprintln(os.Stderr, "On macOS use the CLI binary: ./Navis connect | install-core | check-update")
fmt.Fprintln(os.Stderr, "Navis GUI supports Windows (WebView2) and macOS.")
fmt.Fprintln(os.Stderr, "On this OS use the CLI: ./Navis connect | install-core | check-update")
os.Exit(1)
}