mirror of
https://github.com/netbirdio/netbird.git
synced 2026-07-18 12:39:54 +00:00
- **Wails v3 application** (`client/ui`) with a React + TypeScript + Tailwind frontend replacing the Fyne UI: main connection view, exit-node switcher, networks/peers browser with detail panels, profile management, settings (general, network, SSH, security, troubleshooting, appearance), debug-bundle creation, and a first-run welcome flow. - **Internationalization**: go-i18n bundle with 9 locales (en, de, es, fr, hu, it, pt, ru, zh-CN) shared between the tray and the frontend. - **New system tray** implementation with per-platform theme-aware icons, including a native XEmbed host for Linux (`xembed_tray_linux.c`) and a Linux theme watcher. - **Session handling**: auth session watcher (`client/internal/auth/sessionwatch`), pending login flow, session-expiration dialog and tray notifications, and `netbird login` improvements. - **Daemon API extensions** (`daemon.proto`): status stream subscription, event stream, networks/exit-node selection endpoints, and richer full status — with probe throttling on the daemon side to protect against UI-driven request storms. - **UI preferences store** persisted per profile, autostart management via the daemon (single source of truth in HKCU on Windows). - **Build system**: Taskfile-based builds per platform (macOS, Linux, Windows), Docker cross-compilation images, MSIX/NSIS/nfpm/AppImage packaging, and a new `frontend-ui` CI workflow. Co-authored-by: Zoltan Papp <zoltan.pmail@gmail.com> Co-authored-by: Eduard Gert <kontakt@eduardgert.de> Co-authored-by: braginini <bangvalo@gmail.com> Co-authored-by: Pascal Fischer <32096965+pascal-fischer@users.noreply.github.com> Co-authored-by: riccardom <riccardomanfrin@gmail.com>
98 lines
2.5 KiB
Go
98 lines
2.5 KiB
Go
//go:build !android && !ios && !freebsd && !js
|
|
|
|
// Package updater holds the auto-update domain: the typed State, the
|
|
// daemon-SystemEvent metadata schema, and the Holder that caches the latest
|
|
// state and broadcasts changes. No Wails dependency.
|
|
package updater
|
|
|
|
import (
|
|
"sync"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
"github.com/netbirdio/netbird/client/proto"
|
|
)
|
|
|
|
// EventStateChanged carries the full State snapshot as payload.
|
|
const EventStateChanged = "netbird:update:state"
|
|
|
|
// State is the typed snapshot of the daemon's update situation. Installing is
|
|
// driven only by the daemon's progress_window:show event; a UI-side
|
|
// Update.Trigger() does not flip it.
|
|
type State struct {
|
|
Available bool `json:"available"`
|
|
Version string `json:"version"`
|
|
Enforced bool `json:"enforced"`
|
|
Installing bool `json:"installing"`
|
|
}
|
|
|
|
// Emitter is the broadcast dependency Holder needs; the Wails app.Event
|
|
// processor satisfies it.
|
|
type Emitter interface {
|
|
Emit(name string, data ...any) bool
|
|
}
|
|
|
|
// Holder caches the latest update State and broadcasts changes.
|
|
type Holder struct {
|
|
emitter Emitter
|
|
|
|
mu sync.Mutex
|
|
state State
|
|
}
|
|
|
|
// NewHolder constructs an empty-state Holder. A nil emitter skips the broadcast.
|
|
func NewHolder(emitter Emitter) *Holder {
|
|
return &Holder{emitter: emitter}
|
|
}
|
|
|
|
// Get returns a copy of the cached State.
|
|
func (h *Holder) Get() State {
|
|
h.mu.Lock()
|
|
defer h.mu.Unlock()
|
|
return h.state
|
|
}
|
|
|
|
// OnSystemEvent folds update-related metadata into the cached state, emitting
|
|
// EventStateChanged only on an actual change so repeated daemon snapshots
|
|
// don't produce redundant pushes.
|
|
func (h *Holder) OnSystemEvent(ev *proto.SystemEvent) {
|
|
md := ev.GetMetadata()
|
|
if len(md) == 0 {
|
|
return
|
|
}
|
|
|
|
h.mu.Lock()
|
|
changed := false
|
|
if v, ok := md["new_version_available"]; ok {
|
|
_, enforced := md["enforced"]
|
|
if !h.state.Available || h.state.Version != v || h.state.Enforced != enforced {
|
|
h.state.Available = true
|
|
h.state.Version = v
|
|
h.state.Enforced = enforced
|
|
changed = true
|
|
}
|
|
}
|
|
if md["progress_window"] == "show" {
|
|
if !h.state.Installing {
|
|
h.state.Installing = true
|
|
changed = true
|
|
}
|
|
if v, ok := md["version"]; ok && v != "" && h.state.Version != v {
|
|
h.state.Version = v
|
|
h.state.Available = true
|
|
changed = true
|
|
}
|
|
}
|
|
snap := h.state
|
|
h.mu.Unlock()
|
|
|
|
if !changed {
|
|
return
|
|
}
|
|
log.Infof("update state: available=%v version=%q enforced=%v installing=%v",
|
|
snap.Available, snap.Version, snap.Enforced, snap.Installing)
|
|
if h.emitter != nil {
|
|
h.emitter.Emit(EventStateChanged, snap)
|
|
}
|
|
}
|