initial commit

This commit is contained in:
2026-06-09 10:47:39 -04:00
commit 2cedcf448c
10 changed files with 670 additions and 0 deletions

102
opener.go Normal file
View File

@@ -0,0 +1,102 @@
package main
import (
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"runtime"
)
// hostOpen launches the platform's "open" handler for target (a URL, file path,
// or opaque string) without blocking. Errors after launch are logged, not
// returned, since the GUI handler is fire-and-forget.
//
// It resolves the opener via realOpenerPath so a host that also shadows
// `xdg-open`/`open` with this binary doesn't recurse back into client mode.
func hostOpen(target string) error {
name, args := openCommand(target)
bin, err := realOpenerPath(name)
if err != nil {
return err
}
cmd := exec.Command(bin, args...)
if err := cmd.Start(); err != nil {
return fmt.Errorf("start %s: %w", bin, err)
}
go func() {
if err := cmd.Wait(); err != nil {
log.Printf("open %q exited: %v", target, err)
}
}()
return nil
}
func openCommand(target string) (string, []string) {
switch runtime.GOOS {
case "darwin":
return "open", []string{target}
case "windows":
return "rundll32", []string{"url.dll,FileProtocolHandler", target}
default:
return "xdg-open", []string{target}
}
}
// defaultOpenerName is the platform's native opener, used as the fallback target
// when we were invoked as `open-proxy open` rather than under a shadowed name.
func defaultOpenerName() string {
if runtime.GOOS == "darwin" {
return "open"
}
return "xdg-open"
}
// localOpen runs the real opener (the next `name` on $PATH that isn't us) for
// arg. Used as the client-side fallback when the host is unreachable.
func localOpen(name, arg string) error {
bin, err := realOpenerPath(name)
if err != nil {
return err
}
cmd := exec.Command(bin, arg)
cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
return cmd.Run()
}
// realOpenerPath finds an executable named `name` on $PATH that is not this
// binary (so a symlink shadowing `xdg-open`/`open` doesn't recurse into us).
func realOpenerPath(name string) (string, error) {
self := selfFileInfo()
for _, dir := range filepath.SplitList(os.Getenv("PATH")) {
if dir == "" {
continue
}
cand := filepath.Join(dir, name)
info, err := os.Stat(cand) // follows symlinks
if err != nil || info.IsDir() || info.Mode()&0o111 == 0 {
continue
}
// Compare by file identity (device+inode), not path string: a symlink or
// hardlink pointing back at this binary is recognized as us regardless of
// how its path is spelled or whether $PATH entries are relative.
if self != nil && os.SameFile(self, info) {
continue
}
return cand, nil
}
return "", fmt.Errorf("no real %q found on PATH", name)
}
func selfFileInfo() os.FileInfo {
exe, err := os.Executable()
if err != nil {
return nil
}
info, err := os.Stat(exe)
if err != nil {
return nil
}
return info
}