tstest/natlab/vmtest: add macOS VM screenshot streaming to web UI
When --vmtest-web is set, Host.app is launched with --screenshot-port 0
to start a localhost HTTP server that captures the VZVirtualMachineView
display. The Go test harness parses the SCREENSHOT_PORT=<port> line from
stdout, then polls every 2 seconds for JPEG thumbnails and pushes them
over WebSocket to the web dashboard.
Clicking a screenshot thumbnail opens a full-resolution image proxied
through the web UI's /screenshot/{node} endpoint.
Screenshot events are excluded from the EventBus history (they're large
and only the latest matters, stored in NodeStatus.Screenshot).
Updates #13038
Change-Id: I9bc67ddd1cc72948b33c555d4be3d8db06a41f6d
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
committed by
Brad Fitzpatrick
parent
78627c132f
commit
4cec06b8f2
@@ -108,6 +108,7 @@ func (e *Env) maybeStartWebServer() {
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("GET /", e.serveIndex)
|
||||
mux.HandleFunc("GET /ws", e.serveWebSocket)
|
||||
mux.HandleFunc("GET /screenshot/{node}", e.serveScreenshot)
|
||||
mux.HandleFunc("GET /style.css", serveStaticAsset("style.css"))
|
||||
|
||||
srv := &http.Server{Handler: mux}
|
||||
@@ -155,6 +156,25 @@ func (e *Env) serveIndex(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// serveScreenshot proxies a full-resolution screenshot from the Host.app
|
||||
// screenshot server. Returns raw JPEG with no HTML wrapper.
|
||||
func (e *Env) serveScreenshot(w http.ResponseWriter, r *http.Request) {
|
||||
name := r.PathValue("node")
|
||||
port := e.nodeScreenshotPort(name)
|
||||
if port == 0 {
|
||||
http.Error(w, "no screenshot server for node", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
resp, err := http.Get(fmt.Sprintf("http://127.0.0.1:%d/screenshot?full=1", port))
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadGateway)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
w.Header().Set("Content-Type", "image/jpeg")
|
||||
io.Copy(w, resp.Body)
|
||||
}
|
||||
|
||||
func (e *Env) serveWebSocket(w http.ResponseWriter, r *http.Request) {
|
||||
conn, err := websocket.Accept(w, r, nil)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user