// ollie-httpgw - HTTP gateway for ollie session management. // // Translates HTTP requests to D-Bus calls against org.ollie.SessionManager. // // Usage: // // ollie-httpgw [start|fgstart|stop|status] package main import ( _ "embed" "encoding/json" "flag" "fmt" "log" "net" "net/http" "os" "os/exec" "path/filepath" "syscall" ) //go:embed openapi.json var openapiSpec []byte var listen = flag.String("listen", ":8011", "HTTP listen address") const pidFile = "ollie-httpgw.pid" func main() { args := os.Args[1:] if len(args) >= 1 { subcmd := args[0] switch subcmd { case "start", "fgstart", "stop", "status": flag.CommandLine.Parse(args[1:]) //nolint:errcheck ns := os.Getenv("NAMESPACE") if ns == "" { ns = fmt.Sprintf("/tmp/ns.%s.:0", os.Getenv("USER")) } pidPath := filepath.Join(ns, pidFile) switch subcmd { case "start": if gwRunning() { fmt.Println("ollie-httpgw already running") os.Exit(0) } daemonize() case "fgstart": if gwRunning() { fmt.Println("ollie-httpgw already running") os.Exit(0) } runGateway(pidPath) case "stop": stopGateway(pidPath) case "status": if gwRunning() { fmt.Println("ollie-httpgw running") } else { fmt.Println("ollie-httpgw not running") os.Exit(1) } } return } } // No subcommand — run in foreground directly (no pid file). flag.CommandLine.Parse(args) //nolint:errcheck serve() } func gwRunning() bool { conn, err := net.Dial("tcp", *listen) if err == nil { conn.Close() return true } return false } func daemonize() { exe, _ := os.Executable() args := []string{"fgstart", "-listen", *listen} cmd := exec.Command(exe, args...) cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true} if err := cmd.Start(); err != nil { fmt.Fprintf(os.Stderr, "failed to start: %v\n", err) os.Exit(1) } fmt.Printf("ollie-httpgw started (pid %d)\n", cmd.Process.Pid) } func stopGateway(pidPath string) { data, err := os.ReadFile(pidPath) if err != nil { fmt.Println("ollie-httpgw not running") return } var pid int fmt.Sscanf(string(data), "%d", &pid) if pid > 0 { syscall.Kill(pid, syscall.SIGTERM) //nolint:errcheck } os.Remove(pidPath) //nolint:errcheck fmt.Println("ollie-httpgw stopped") } func runGateway(pidPath string) { os.WriteFile(pidPath, fmt.Appendf(nil, "%d", os.Getpid()), 0644) //nolint:errcheck serve() os.Remove(pidPath) //nolint:errcheck } func serve() { http.HandleFunc("/openapi.json", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write(openapiSpec) }) http.HandleFunc("/", dbusHandler) log.Printf("ollie-httpgw listening on %s", *listen) log.Fatal(http.ListenAndServe(*listen, nil)) } func writeJSON(w http.ResponseWriter, status int, v any) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) json.NewEncoder(w).Encode(v) }