package browser import ( "fmt" "os/exec" "runtime" log "github.com/sirupsen/logrus" "github.com/skratchdot/open-golang/open" ) // OpenURL opens a URL in the default browser func OpenURL(url string) error { log.Debugf("Attempting to open URL in browser: %s", url) // Try using the open-golang library first err := open.Run(url) if err == nil { log.Debug("Successfully opened URL using open-golang library") return nil } log.Debugf("open-golang failed: %v, trying platform-specific commands", err) // Fallback to platform-specific commands return openURLPlatformSpecific(url) } // openURLPlatformSpecific opens URL using platform-specific commands func openURLPlatformSpecific(url string) error { var cmd *exec.Cmd switch runtime.GOOS { case "darwin": // macOS cmd = exec.Command("open", url) case "windows": cmd = exec.Command("rundll32", "url.dll,FileProtocolHandler", url) case "linux": // Try common Linux browsers in order of preference browsers := []string{"xdg-open", "x-www-browser", "www-browser", "firefox", "chromium", "google-chrome"} for _, browser := range browsers { if _, err := exec.LookPath(browser); err == nil { cmd = exec.Command(browser, url) break } } if cmd == nil { return fmt.Errorf("no suitable browser found on Linux system") } default: return fmt.Errorf("unsupported operating system: %s", runtime.GOOS) } log.Debugf("Running command: %s %v", cmd.Path, cmd.Args[1:]) err := cmd.Start() if err != nil { return fmt.Errorf("failed to start browser command: %w", err) } log.Debug("Successfully opened URL using platform-specific command") return nil } // IsAvailable checks if browser opening functionality is available func IsAvailable() bool { // First check if open-golang can work testErr := open.Run("about:blank") if testErr == nil { return true } // Check platform-specific commands switch runtime.GOOS { case "darwin": _, err := exec.LookPath("open") return err == nil case "windows": _, err := exec.LookPath("rundll32") return err == nil case "linux": browsers := []string{"xdg-open", "x-www-browser", "www-browser", "firefox", "chromium", "google-chrome"} for _, browser := range browsers { if _, err := exec.LookPath(browser); err == nil { return true } } return false default: return false } } // GetPlatformInfo returns information about the current platform's browser support func GetPlatformInfo() map[string]interface{} { info := map[string]interface{}{ "os": runtime.GOOS, "arch": runtime.GOARCH, "available": IsAvailable(), } switch runtime.GOOS { case "darwin": info["default_command"] = "open" case "windows": info["default_command"] = "rundll32" case "linux": browsers := []string{"xdg-open", "x-www-browser", "www-browser", "firefox", "chromium", "google-chrome"} var availableBrowsers []string for _, browser := range browsers { if _, err := exec.LookPath(browser); err == nil { availableBrowsers = append(availableBrowsers, browser) } } info["available_browsers"] = availableBrowsers if len(availableBrowsers) > 0 { info["default_command"] = availableBrowsers[0] } } return info }