85 lines
2.4 KiB
Go
85 lines
2.4 KiB
Go
// Package moonlight handles launching the Moonlight client.
|
|
// It locates the Moonlight executable and launches a stream session
|
|
// to a specific host and app.
|
|
package moonlight
|
|
|
|
import (
|
|
"fmt"
|
|
"os/exec"
|
|
"runtime"
|
|
)
|
|
|
|
// DefaultPaths are the well-known install locations per platform.
|
|
var DefaultPaths = map[string][]string{
|
|
"windows": {
|
|
`C:\Program Files\Moonlight Game Streaming\Moonlight.exe`,
|
|
`C:\Program Files (x86)\Moonlight Game Streaming\Moonlight.exe`,
|
|
},
|
|
"darwin": {
|
|
"/Applications/Moonlight.app/Contents/MacOS/Moonlight",
|
|
},
|
|
"linux": {
|
|
"/usr/bin/moonlight",
|
|
"/usr/local/bin/moonlight",
|
|
},
|
|
}
|
|
|
|
// Launcher knows how to start Moonlight.
|
|
type Launcher struct {
|
|
execPath string
|
|
}
|
|
|
|
// New creates a Launcher, auto-detecting the Moonlight binary.
|
|
// Pass an empty string to use auto-detection.
|
|
func New(overridePath string) (*Launcher, error) {
|
|
if overridePath != "" {
|
|
if path, err := exec.LookPath(overridePath); err == nil {
|
|
return &Launcher{execPath: path}, nil
|
|
}
|
|
return nil, fmt.Errorf("moonlight not found at %q", overridePath)
|
|
}
|
|
|
|
// Try PATH first
|
|
if path, err := exec.LookPath("moonlight"); err == nil {
|
|
return &Launcher{execPath: path}, nil
|
|
}
|
|
|
|
// Try well-known locations
|
|
for _, candidate := range DefaultPaths[runtime.GOOS] {
|
|
if path, err := exec.LookPath(candidate); err == nil {
|
|
return &Launcher{execPath: path}, nil
|
|
}
|
|
}
|
|
|
|
// Return a launcher even if not found — we'll surface the error at connect time
|
|
return &Launcher{}, nil
|
|
}
|
|
|
|
// ExecPath returns the resolved path to the Moonlight binary.
|
|
func (l *Launcher) ExecPath() string {
|
|
return l.execPath
|
|
}
|
|
|
|
// Stream launches a Moonlight stream to the given host + app.
|
|
// app is typically "Desktop" for a full desktop stream.
|
|
func (l *Launcher) Stream(hostIP, app string) error {
|
|
if l.execPath == "" {
|
|
return fmt.Errorf("Moonlight executable not found — please install Moonlight or set MOONLIGHT_PATH")
|
|
}
|
|
// moonlight stream <host> <app>
|
|
cmd := exec.Command(l.execPath, "stream", hostIP, app)
|
|
cmd.Stdout = nil
|
|
cmd.Stderr = nil
|
|
return cmd.Start() // non-blocking — let Moonlight own its window
|
|
}
|
|
|
|
// Pair runs the Moonlight pairing flow for a host.
|
|
func (l *Launcher) Pair(hostIP string) error {
|
|
if l.execPath == "" {
|
|
return fmt.Errorf("Moonlight executable not found")
|
|
}
|
|
cmd := exec.Command(l.execPath, "pair", hostIP)
|
|
cmd.Stdout = nil
|
|
cmd.Stderr = nil
|
|
return cmd.Start()
|
|
}
|