Files
netbird/client/uiwails/main.go
Zoltán Papp 04a982263d Wails UI
2026-03-02 15:59:09 +01:00

130 lines
3.6 KiB
Go

//go:build !(linux && 386)
package main
import (
"context"
"embed"
"flag"
"os"
"runtime"
log "github.com/sirupsen/logrus"
"github.com/wailsapp/wails/v3/pkg/application"
"github.com/wailsapp/wails/v3/pkg/events"
"github.com/wailsapp/wails/v3/pkg/services/notifications"
"github.com/netbirdio/netbird/client/uiwails/event"
"github.com/netbirdio/netbird/client/uiwails/process"
"github.com/netbirdio/netbird/client/uiwails/services"
)
//go:embed frontend/dist
var frontendFS embed.FS
var (
daemonAddr = flag.String("daemon-addr", defaultDaemonAddr(), "NetBird daemon gRPC address")
)
func defaultDaemonAddr() string {
if runtime.GOOS == "windows" {
return "tcp://127.0.0.1:41731"
}
return "unix:///var/run/netbird.sock"
}
func main() {
flag.Parse()
// Single-instance guard — if another instance is running, show its window and exit.
if pid, running, err := process.IsAnotherProcessRunning(); err == nil && running {
log.Infof("another instance is running (pid %d), signalling it to show window", pid)
if err := sendShowWindowSignal(pid); err != nil {
log.Warnf("send show window signal: %v", err)
}
os.Exit(0)
}
grpcClient := NewGRPCClient(*daemonAddr)
connSvc := services.NewConnectionService(grpcClient)
settingsSvc := services.NewSettingsService(grpcClient)
networkSvc := services.NewNetworkService(grpcClient)
profileSvc := services.NewProfileService(grpcClient)
peersSvc := services.NewPeersService(grpcClient)
debugSvc := services.NewDebugService(grpcClient)
updateSvc := services.NewUpdateService(grpcClient)
notifSvc := notifications.New()
app := application.New(application.Options{
Name: "NetBird",
Description: "NetBird VPN client",
Services: []application.Service{
application.NewService(connSvc),
application.NewService(settingsSvc),
application.NewService(networkSvc),
application.NewService(profileSvc),
application.NewService(peersSvc),
application.NewService(debugSvc),
application.NewService(updateSvc),
application.NewService(notifSvc),
},
Assets: application.AssetOptions{
Handler: application.BundledAssetFileServer(frontendFS),
},
Mac: application.MacOptions{
ActivationPolicy: application.ActivationPolicyAccessory,
},
})
window := app.Window.NewWithOptions(application.WebviewWindowOptions{
Title: "NetBird",
Width: 900,
Height: 650,
Hidden: true, // start hidden — tray is the primary interface
URL: "/",
AlwaysOnTop: false,
DisableResize: false,
Windows: application.WindowsWindow{
HiddenOnTaskbar: true,
},
})
// Hide instead of quit when user closes the window.
window.RegisterHook(events.Common.WindowClosing, func(e *application.WindowEvent) {
e.Cancel()
window.Hide()
})
// Register an in-process StatusNotifierWatcher so the tray works on
// minimal WMs (Fluxbox, OpenBox, i3…) that don't ship one themselves.
startStatusNotifierWatcher()
tray := newTrayManager(app, window, connSvc, settingsSvc, networkSvc, profileSvc)
tray.Setup(iconDisconnected)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Signal handler: SIGUSR1 on Unix, Windows Event on Windows.
setupSignalHandler(ctx, window)
// Daemon event stream → desktop notifications.
notify := func(title, body string) {
if err := notifSvc.SendNotification(notifications.NotificationOptions{
ID: "netbird-event",
Title: title,
Body: body,
}); err != nil {
log.Warnf("send notification: %v", err)
}
}
evtManager := event.NewManager(*daemonAddr, notify)
go evtManager.Start(ctx)
if err := app.Run(); err != nil {
log.Fatalf("app run: %v", err)
}
}