Release 3.10.0+1: sidebar UI (Home / Profiles / Settings / Logs / About), remembered account with 50 GB monthly renew + auto-renew, Windows VPN mode (wintun + tun2socks).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Navis
2026-08-01 18:34:25 +03:00
co-authored by Cursor
parent 77bd7da861
commit 01fac376ba
25 changed files with 1803 additions and 602 deletions
+36 -3
View File
@@ -61,6 +61,10 @@ type uiState struct {
Hy2 core.Hy2Options `json:"hy2"`
StorePackaged bool `json:"store_packaged,omitempty"`
ProvisionReady bool `json:"provision_ready,omitempty"`
Account *remnawave.Account `json:"account,omitempty"`
Mode string `json:"mode"`
VPNSupported bool `json:"vpn_mode_supported"`
VPNActive bool `json:"vpn_active"`
}
func main() {
@@ -107,14 +111,15 @@ func main() {
// Do NOT auto-download cores on startup — silent network+write looks like malware to AV.
// Sidebar layout (Hiddify-style) needs a wider window than the old column UI.
w := webview2.NewWithOptions(webview2.WebViewOptions{
Debug: false,
AutoFocus: true,
DataPath: dataPath,
WindowOptions: webview2.WindowOptions{
Title: "Navis 2",
Width: 500,
Height: 900,
Width: 920,
Height: 680,
Center: true,
IconId: 1,
},
@@ -129,7 +134,7 @@ func main() {
}()
applyWindowIcon(w.Window())
w.SetSize(500, 900, webview2.HintNone)
w.SetSize(920, 680, webview2.HintNone)
mustBind(w, "getState", a.getState)
mustBind(w, "connect", a.connect)
@@ -150,8 +155,12 @@ func main() {
mustBind(w, "saveRemnawave", a.saveRemnawave)
mustBind(w, "importRemnawave", a.importRemnawave)
mustBind(w, "provisionUser", a.provisionUser)
mustBind(w, "renewAccount", a.renewAccount)
mustBind(w, "setMode", a.setMode)
mustBind(w, "getLogs", a.getLogs)
go a.autoCheckUpdate()
mgr.StartAutoRenew(6 * time.Hour)
w.SetHtml(appui.IndexHTML)
w.Run()
@@ -221,6 +230,10 @@ func (a *app) getState() (uiState, error) {
Hy2: a.mgr.ActiveHy2Options(),
StorePackaged: update.IsStorePackaged(),
ProvisionReady: a.mgr.ProvisionConfigured(),
Account: a.mgr.Account(),
Mode: a.mgr.Mode(),
VPNSupported: a.mgr.VPNModeSupported(),
VPNActive: st.VPNActive,
}
if out.Protocol == "" {
if p, err := cfg.ActiveProfile(); err == nil {
@@ -348,6 +361,26 @@ func (a *app) provisionUser(username string) (core.ProvisionOutcome, error) {
return a.mgr.ProvisionAccess(username)
}
func (a *app) renewAccount() (core.ProvisionOutcome, error) {
return a.mgr.RenewAccount()
}
func (a *app) setMode(mode string) error {
return a.mgr.SetMode(strings.TrimSpace(mode))
}
func (a *app) getLogs() (string, error) {
if a.logBuf == nil {
return "", nil
}
const maxTail = 64 * 1024
b := a.logBuf.Bytes()
if len(b) > maxTail {
b = b[len(b)-maxTail:]
}
return string(b), nil
}
type pingBestResult struct {
Pings []netcheck.Result `json:"pings"`
BestName string `json:"best_name,omitempty"`