//go:build !(linux && 386) package main import ( "context" "errors" "fmt" "os" "os/exec" "fyne.io/fyne/v2" "fyne.io/systray" log "github.com/sirupsen/logrus" ) type eventHandler struct { client *serviceClient } func newEventHandler(client *serviceClient) *eventHandler { return &eventHandler{ client: client, } } func (h *eventHandler) listen(ctx context.Context) { for { select { case <-ctx.Done(): return case <-h.client.mUp.ClickedCh: h.handleConnectClick() case <-h.client.mDown.ClickedCh: h.handleDisconnectClick() case <-h.client.mAllowSSH.ClickedCh: h.handleAllowSSHClick() case <-h.client.mAutoConnect.ClickedCh: h.handleAutoConnectClick() case <-h.client.mEnableRosenpass.ClickedCh: h.handleRosenpassClick() case <-h.client.mLazyConnEnabled.ClickedCh: h.handleLazyConnectionClick() case <-h.client.mBlockInbound.ClickedCh: h.handleBlockInboundClick() case <-h.client.mAdvancedSettings.ClickedCh: h.handleAdvancedSettingsClick() case <-h.client.mCreateDebugBundle.ClickedCh: h.handleCreateDebugBundleClick() case <-h.client.mQuit.ClickedCh: h.handleQuitClick() return case <-h.client.mGitHub.ClickedCh: h.handleGitHubClick() case <-h.client.mUpdate.ClickedCh: h.handleUpdateClick() case <-h.client.mNetworks.ClickedCh: h.handleNetworksClick() case <-h.client.mNotifications.ClickedCh: h.handleNotificationsClick() } } } func (h *eventHandler) handleConnectClick() { h.client.mUp.Disable() go func() { defer h.client.mUp.Enable() if err := h.client.menuUpClick(); err != nil { h.client.app.SendNotification(fyne.NewNotification("Error", "Failed to connect to NetBird service")) } }() } func (h *eventHandler) handleDisconnectClick() { h.client.mDown.Disable() go func() { defer h.client.mDown.Enable() if err := h.client.menuDownClick(); err != nil { h.client.app.SendNotification(fyne.NewNotification("Error", "Failed to connect to NetBird daemon")) } }() } func (h *eventHandler) handleAllowSSHClick() { h.toggleCheckbox(h.client.mAllowSSH) h.updateConfigWithErr() } func (h *eventHandler) handleAutoConnectClick() { h.toggleCheckbox(h.client.mAutoConnect) h.updateConfigWithErr() } func (h *eventHandler) handleRosenpassClick() { h.toggleCheckbox(h.client.mEnableRosenpass) h.updateConfigWithErr() } func (h *eventHandler) handleLazyConnectionClick() { h.toggleCheckbox(h.client.mLazyConnEnabled) h.updateConfigWithErr() } func (h *eventHandler) handleBlockInboundClick() { h.toggleCheckbox(h.client.mBlockInbound) h.updateConfigWithErr() } func (h *eventHandler) handleNotificationsClick() { h.toggleCheckbox(h.client.mNotifications) if h.client.eventManager != nil { h.client.eventManager.SetNotificationsEnabled(h.client.mNotifications.Checked()) } h.updateConfigWithErr() } func (h *eventHandler) handleAdvancedSettingsClick() { h.client.mAdvancedSettings.Disable() go func() { defer h.client.mAdvancedSettings.Enable() defer h.client.getSrvConfig() h.runSelfCommand("settings", "true") }() } func (h *eventHandler) handleCreateDebugBundleClick() { h.client.mCreateDebugBundle.Disable() go func() { defer h.client.mCreateDebugBundle.Enable() h.runSelfCommand("debug", "true") }() } func (h *eventHandler) handleQuitClick() { systray.Quit() } func (h *eventHandler) handleGitHubClick() { if err := openURL("https://github.com/netbirdio/netbird"); err != nil { log.Errorf("failed to open GitHub URL: %v", err) } } func (h *eventHandler) handleUpdateClick() { if err := openURL("https://netbird.io/download"); err != nil { log.Errorf("failed to open download URL: %v", err) } } func (h *eventHandler) handleNetworksClick() { h.client.mNetworks.Disable() go func() { defer h.client.mNetworks.Enable() h.runSelfCommand("networks", "true") }() } func (h *eventHandler) toggleCheckbox(item *systray.MenuItem) { if item.Checked() { item.Uncheck() } else { item.Check() } } func (h *eventHandler) updateConfigWithErr() { if err := h.client.updateConfig(); err != nil { log.Errorf("failed to update config: %v", err) } } func (h *eventHandler) runSelfCommand(command, arg string) { proc, err := os.Executable() if err != nil { log.Errorf("error getting executable path: %v", err) return } cmd := exec.Command(proc, fmt.Sprintf("--%s=%s", command, arg), fmt.Sprintf("--daemon-addr=%s", h.client.addr), ) if out := h.client.attachOutput(cmd); out != nil { defer func() { if err := out.Close(); err != nil { log.Errorf("error closing log file %s: %v", h.client.logFile, err) } }() } log.Printf("running command: %s --%s=%s --daemon-addr=%s", proc, command, arg, h.client.addr) if err := cmd.Run(); err != nil { var exitErr *exec.ExitError if errors.As(err, &exitErr) { log.Printf("command '%s %s' failed with exit code %d", command, arg, exitErr.ExitCode()) } return } log.Printf("command '%s %s' completed successfully", command, arg) }