mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-20 01:06:45 +00:00
Compare commits
1 Commits
fix/androi
...
quick-seti
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5fadbeb769 |
@@ -85,21 +85,22 @@ func main() {
|
|||||||
|
|
||||||
// Create the service client (this also builds the settings or networks UI if requested).
|
// Create the service client (this also builds the settings or networks UI if requested).
|
||||||
client := newServiceClient(&newServiceClientArgs{
|
client := newServiceClient(&newServiceClientArgs{
|
||||||
addr: flags.daemonAddr,
|
addr: flags.daemonAddr,
|
||||||
logFile: logFile,
|
logFile: logFile,
|
||||||
app: a,
|
app: a,
|
||||||
showSettings: flags.showSettings,
|
showSettings: flags.showSettings,
|
||||||
showNetworks: flags.showNetworks,
|
showNetworks: flags.showNetworks,
|
||||||
showLoginURL: flags.showLoginURL,
|
showLoginURL: flags.showLoginURL,
|
||||||
showDebug: flags.showDebug,
|
showDebug: flags.showDebug,
|
||||||
showProfiles: flags.showProfiles,
|
showProfiles: flags.showProfiles,
|
||||||
|
showQuickActions: flags.showQuickActions,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Watch for theme/settings changes to update the icon.
|
// Watch for theme/settings changes to update the icon.
|
||||||
go watchSettingsChanges(a, client)
|
go watchSettingsChanges(a, client)
|
||||||
|
|
||||||
// Run in window mode if any UI flag was set.
|
// Run in window mode if any UI flag was set.
|
||||||
if flags.showSettings || flags.showNetworks || flags.showDebug || flags.showLoginURL || flags.showProfiles {
|
if flags.showSettings || flags.showNetworks || flags.showDebug || flags.showLoginURL || flags.showProfiles || flags.showQuickActions {
|
||||||
a.Run()
|
a.Run()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -111,23 +112,29 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if running {
|
if running {
|
||||||
log.Warnf("another process is running with pid %d, exiting", pid)
|
log.Infof("another process is running with pid %d, sending signal to show window", pid)
|
||||||
|
if err := sendShowWindowSignal(pid); err != nil {
|
||||||
|
log.Errorf("send signal to running instance: %v", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client.setupSignalHandler(client.ctx)
|
||||||
|
|
||||||
client.setDefaultFonts()
|
client.setDefaultFonts()
|
||||||
systray.Run(client.onTrayReady, client.onTrayExit)
|
systray.Run(client.onTrayReady, client.onTrayExit)
|
||||||
}
|
}
|
||||||
|
|
||||||
type cliFlags struct {
|
type cliFlags struct {
|
||||||
daemonAddr string
|
daemonAddr string
|
||||||
showSettings bool
|
showSettings bool
|
||||||
showNetworks bool
|
showNetworks bool
|
||||||
showProfiles bool
|
showProfiles bool
|
||||||
showDebug bool
|
showDebug bool
|
||||||
showLoginURL bool
|
showLoginURL bool
|
||||||
errorMsg string
|
showQuickActions bool
|
||||||
saveLogsInFile bool
|
errorMsg string
|
||||||
|
saveLogsInFile bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseFlags reads and returns all needed command-line flags.
|
// parseFlags reads and returns all needed command-line flags.
|
||||||
@@ -143,6 +150,7 @@ func parseFlags() *cliFlags {
|
|||||||
flag.BoolVar(&flags.showNetworks, "networks", false, "run networks window")
|
flag.BoolVar(&flags.showNetworks, "networks", false, "run networks window")
|
||||||
flag.BoolVar(&flags.showProfiles, "profiles", false, "run profiles window")
|
flag.BoolVar(&flags.showProfiles, "profiles", false, "run profiles window")
|
||||||
flag.BoolVar(&flags.showDebug, "debug", false, "run debug window")
|
flag.BoolVar(&flags.showDebug, "debug", false, "run debug window")
|
||||||
|
flag.BoolVar(&flags.showQuickActions, "quick-actions", false, "run quick actions window")
|
||||||
flag.StringVar(&flags.errorMsg, "error-msg", "", "displays an error message window")
|
flag.StringVar(&flags.errorMsg, "error-msg", "", "displays an error message window")
|
||||||
flag.BoolVar(&flags.saveLogsInFile, "use-log-file", false, fmt.Sprintf("save logs in a file: %s/netbird-ui-PID.log", os.TempDir()))
|
flag.BoolVar(&flags.saveLogsInFile, "use-log-file", false, fmt.Sprintf("save logs in a file: %s/netbird-ui-PID.log", os.TempDir()))
|
||||||
flag.BoolVar(&flags.showLoginURL, "login-url", false, "show login URL in a popup window")
|
flag.BoolVar(&flags.showLoginURL, "login-url", false, "show login URL in a popup window")
|
||||||
@@ -287,6 +295,7 @@ type serviceClient struct {
|
|||||||
showNetworks bool
|
showNetworks bool
|
||||||
wNetworks fyne.Window
|
wNetworks fyne.Window
|
||||||
wProfiles fyne.Window
|
wProfiles fyne.Window
|
||||||
|
wQuickActions fyne.Window
|
||||||
|
|
||||||
eventManager *event.Manager
|
eventManager *event.Manager
|
||||||
|
|
||||||
@@ -304,14 +313,15 @@ type menuHandler struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type newServiceClientArgs struct {
|
type newServiceClientArgs struct {
|
||||||
addr string
|
addr string
|
||||||
logFile string
|
logFile string
|
||||||
app fyne.App
|
app fyne.App
|
||||||
showSettings bool
|
showSettings bool
|
||||||
showNetworks bool
|
showNetworks bool
|
||||||
showDebug bool
|
showDebug bool
|
||||||
showLoginURL bool
|
showLoginURL bool
|
||||||
showProfiles bool
|
showProfiles bool
|
||||||
|
showQuickActions bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// newServiceClient instance constructor
|
// newServiceClient instance constructor
|
||||||
@@ -347,6 +357,8 @@ func newServiceClient(args *newServiceClientArgs) *serviceClient {
|
|||||||
s.showDebugUI()
|
s.showDebugUI()
|
||||||
case args.showProfiles:
|
case args.showProfiles:
|
||||||
s.showProfilesUI()
|
s.showProfilesUI()
|
||||||
|
case args.showQuickActions:
|
||||||
|
s.showQuickActionsUI()
|
||||||
}
|
}
|
||||||
|
|
||||||
return s
|
return s
|
||||||
|
|||||||
101
client/ui/quickactions.go
Normal file
101
client/ui/quickactions.go
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
//go:build !(linux && 386)
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/container"
|
||||||
|
"fyne.io/fyne/v2/layout"
|
||||||
|
"fyne.io/fyne/v2/widget"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/client/internal/peer"
|
||||||
|
"github.com/netbirdio/netbird/client/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
// showQuickActionsUI displays a simple window with connect/disconnect controls.
|
||||||
|
func (s *serviceClient) showQuickActionsUI() {
|
||||||
|
s.wQuickActions = s.app.NewWindow("NetBird")
|
||||||
|
s.wQuickActions.SetOnClosed(s.cancel)
|
||||||
|
|
||||||
|
statusLabel := widget.NewLabel("Status: Checking...")
|
||||||
|
connectBtn := widget.NewButton("Connect", nil)
|
||||||
|
disconnectBtn := widget.NewButton("Disconnect", nil)
|
||||||
|
|
||||||
|
updateUI := func() {
|
||||||
|
client, err := s.getSrvClient(defaultFailTimeout)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("get service client: %v", err)
|
||||||
|
statusLabel.SetText("Status: Error connecting to daemon")
|
||||||
|
connectBtn.Disable()
|
||||||
|
disconnectBtn.Disable()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
status, err := client.Status(context.Background(), &proto.StatusRequest{})
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("get status: %v", err)
|
||||||
|
statusLabel.SetText("Status: Error")
|
||||||
|
connectBtn.Disable()
|
||||||
|
disconnectBtn.Disable()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status.Status == string(peer.StatusConnected) {
|
||||||
|
statusLabel.SetText("Status: Connected")
|
||||||
|
connectBtn.Disable()
|
||||||
|
disconnectBtn.Enable()
|
||||||
|
} else {
|
||||||
|
statusLabel.SetText("Status: Disconnected")
|
||||||
|
connectBtn.Enable()
|
||||||
|
disconnectBtn.Disable()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
connectBtn.OnTapped = func() {
|
||||||
|
connectBtn.Disable()
|
||||||
|
statusLabel.SetText("Status: Connecting...")
|
||||||
|
go func() {
|
||||||
|
if err := s.menuUpClick(); err != nil {
|
||||||
|
log.Errorf("connect failed: %v", err)
|
||||||
|
statusLabel.SetText(fmt.Sprintf("Status: Error - %v", err))
|
||||||
|
}
|
||||||
|
updateUI()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnectBtn.OnTapped = func() {
|
||||||
|
disconnectBtn.Disable()
|
||||||
|
statusLabel.SetText("Status: Disconnecting...")
|
||||||
|
go func() {
|
||||||
|
if err := s.menuDownClick(); err != nil {
|
||||||
|
log.Errorf("disconnect failed: %v", err)
|
||||||
|
statusLabel.SetText(fmt.Sprintf("Status: Error - %v", err))
|
||||||
|
}
|
||||||
|
updateUI()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
content := container.NewVBox(
|
||||||
|
layout.NewSpacer(),
|
||||||
|
statusLabel,
|
||||||
|
layout.NewSpacer(),
|
||||||
|
container.NewHBox(
|
||||||
|
layout.NewSpacer(),
|
||||||
|
connectBtn,
|
||||||
|
disconnectBtn,
|
||||||
|
layout.NewSpacer(),
|
||||||
|
),
|
||||||
|
layout.NewSpacer(),
|
||||||
|
)
|
||||||
|
|
||||||
|
s.wQuickActions.SetContent(content)
|
||||||
|
s.wQuickActions.Resize(fyne.NewSize(300, 150))
|
||||||
|
s.wQuickActions.SetFixedSize(true)
|
||||||
|
s.wQuickActions.Show()
|
||||||
|
|
||||||
|
updateUI()
|
||||||
|
}
|
||||||
76
client/ui/signal_unix.go
Normal file
76
client/ui/signal_unix.go
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
//go:build !windows && !(linux && 386)
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// setupSignalHandler sets up a signal handler to listen for SIGUSR1.
|
||||||
|
// When received, it opens the quick actions window.
|
||||||
|
func (s *serviceClient) setupSignalHandler(ctx context.Context) {
|
||||||
|
sigChan := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(sigChan, syscall.SIGUSR1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case <-sigChan:
|
||||||
|
log.Info("received SIGUSR1 signal, opening quick actions window")
|
||||||
|
s.openQuickActions()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// openQuickActions opens the quick actions window by spawning a new process.
|
||||||
|
func (s *serviceClient) openQuickActions() {
|
||||||
|
proc, err := os.Executable()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("get executable path: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.CommandContext(s.ctx, proc,
|
||||||
|
"--quick-actions=true",
|
||||||
|
"--daemon-addr="+s.addr,
|
||||||
|
)
|
||||||
|
|
||||||
|
if out := s.attachOutput(cmd); out != nil {
|
||||||
|
defer func() {
|
||||||
|
if err := out.Close(); err != nil {
|
||||||
|
log.Errorf("close log file %s: %v", s.logFile, err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("running command: %s --quick-actions=true --daemon-addr=%s", proc, s.addr)
|
||||||
|
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
log.Errorf("start quick actions window: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if err := cmd.Wait(); err != nil {
|
||||||
|
log.Debugf("quick actions window exited: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendShowWindowSignal sends SIGUSR1 to the specified PID.
|
||||||
|
func sendShowWindowSignal(pid int32) error {
|
||||||
|
process, err := os.FindProcess(int(pid))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return process.Signal(syscall.SIGUSR1)
|
||||||
|
}
|
||||||
57
client/ui/signal_windows.go
Normal file
57
client/ui/signal_windows.go
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// setupSignalHandler sets up signal handling for Windows.
|
||||||
|
// Windows doesn't support SIGUSR1, so this is currently a no-op.
|
||||||
|
// Future enhancement: implement Windows-specific IPC (named events, named pipes, etc.)
|
||||||
|
func (s *serviceClient) setupSignalHandler(ctx context.Context) {
|
||||||
|
// TODO: see how debug bundle is generated on signal in windows
|
||||||
|
log.Debug("signal handler not yet implemented for Windows")
|
||||||
|
}
|
||||||
|
|
||||||
|
// openQuickActions opens the quick actions window by spawning a new process.
|
||||||
|
func (s *serviceClient) openQuickActions() {
|
||||||
|
proc, err := os.Executable()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("get executable path: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.CommandContext(s.ctx, proc,
|
||||||
|
"--quick-actions=true",
|
||||||
|
"--daemon-addr="+s.addr,
|
||||||
|
)
|
||||||
|
|
||||||
|
if out := s.attachOutput(cmd); out != nil {
|
||||||
|
defer func() {
|
||||||
|
if err := out.Close(); err != nil {
|
||||||
|
log.Errorf("close log file %s: %v", s.logFile, err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("running command: %s --quick-actions=true --daemon-addr=%s", proc, s.addr)
|
||||||
|
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
log.Errorf("start quick actions window: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if err := cmd.Wait(); err != nil {
|
||||||
|
log.Debugf("quick actions window exited: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendShowWindowSignal(pid int32) error {
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user