refactor(backend): add darwin no-cgo tray fallback (#1689)

This commit is contained in:
wenjie
2026-03-17 19:43:44 +08:00
committed by GitHub
parent afe22c5adf
commit 174fbba14c
4 changed files with 86 additions and 49 deletions
+46
View File
@@ -0,0 +1,46 @@
package main
import (
"context"
"fmt"
"time"
"github.com/sipeed/picoclaw/pkg/logger"
"github.com/sipeed/picoclaw/web/backend/utils"
)
const (
browserDelay = 500 * time.Millisecond
shutdownTimeout = 15 * time.Second
)
func shutdownApp() {
fmt.Println(T(Exiting))
if apiHandler != nil {
apiHandler.Shutdown()
}
if server != nil {
server.SetKeepAlivesEnabled(false)
ctx, cancel := context.WithTimeout(context.Background(), shutdownTimeout)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
if err == context.DeadlineExceeded {
logger.Infof("Server shutdown timeout after %v, forcing close", shutdownTimeout)
} else {
logger.Errorf("Server shutdown error: %v", err)
}
} else {
logger.Infof("Server shutdown completed successfully")
}
}
}
func openBrowser() error {
if serverAddr == "" {
return fmt.Errorf("server address not set")
}
return utils.OpenBrowser(serverAddr)
}
+3 -6
View File
@@ -22,8 +22,6 @@ import (
"strconv"
"time"
"fyne.io/systray"
"github.com/sipeed/picoclaw/pkg/config"
"github.com/sipeed/picoclaw/web/backend/api"
"github.com/sipeed/picoclaw/web/backend/launcherconfig"
@@ -168,10 +166,10 @@ func main() {
}
fmt.Println()
// Set server address for systray
// Share the local URL with the launcher runtime.
serverAddr = fmt.Sprintf("http://localhost:%s", effectivePort)
// Auto-open browser will be handled by systray onReady
// Auto-open browser will be handled by the launcher runtime.
// Auto-start gateway after backend starts listening.
go func() {
@@ -188,6 +186,5 @@ func main() {
}
}()
// Start system tray
systray.Run(onReady, onExit)
runTray()
}
+5 -43
View File
@@ -1,10 +1,10 @@
//go:build !darwin || cgo
package main
import (
"context"
_ "embed"
"fmt"
"time"
"fyne.io/systray"
@@ -12,10 +12,9 @@ import (
"github.com/sipeed/picoclaw/web/backend/utils"
)
const (
browserDelay = 500 * time.Millisecond
shutdownTimeout = 15 * time.Second
)
func runTray() {
systray.Run(onReady, shutdownApp)
}
// onReady is called when the system tray is ready
func onReady() {
@@ -90,43 +89,6 @@ func onReady() {
}
}
// onExit is called when the system tray is exiting
func onExit() {
fmt.Println(T(Exiting))
// First, shutdown API handler
if apiHandler != nil {
apiHandler.Shutdown()
}
if server != nil {
// Disable keep-alive to allow graceful shutdown
server.SetKeepAlivesEnabled(false)
ctx, cancel := context.WithTimeout(context.Background(), shutdownTimeout)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
// Context deadline exceeded is expected if there are active connections
// This is not necessarily an error, so log it at info level
if err == context.DeadlineExceeded {
logger.Infof("Server shutdown timeout after %v, forcing close", shutdownTimeout)
} else {
logger.Errorf("Server shutdown error: %v", err)
}
} else {
logger.Infof("Server shutdown completed successfully")
}
}
}
// openBrowser opens the PicoClaw web console in the default browser
func openBrowser() error {
if serverAddr == "" {
return fmt.Errorf("server address not set")
}
return utils.OpenBrowser(serverAddr)
}
// getIcon returns the system tray icon
func getIcon() []byte {
return iconData
+32
View File
@@ -0,0 +1,32 @@
//go:build darwin && !cgo
package main
import (
"context"
"os"
"os/signal"
"syscall"
"time"
"github.com/sipeed/picoclaw/pkg/logger"
)
func runTray() {
logger.Infof("System tray is unavailable in darwin builds without cgo; running without tray")
if !*noBrowser {
go func() {
time.Sleep(browserDelay)
if err := openBrowser(); err != nil {
logger.Errorf("Warning: Failed to auto-open browser: %v", err)
}
}()
}
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
<-ctx.Done()
shutdownApp()
}