desktop

package
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 9, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

Documentation

Overview

Package desktop streams a running task's desktop to a person's browser.

A desktop playbook's task runs voxl on an exposed port named "desktop": a virtual display streamed as H.264 over one WebSocket. This package is the only way a browser reaches it. It is served on an origin of its own (PODIUM_DESKTOP_URL), never the UI's: voxl's web client is someone else's JavaScript, and on the UI's origin it could call Podium's API as the person watching. The UI's session cookie is host-only, so the desktop origin never sees it.

The same task's terminal — ttyd on the exposed port "terminal", a shell in the workspace — is served the same way, with a link of its own.

A person gets in with a link, not a cookie: TaskService.CreateDesktopTicket mints /t/<task>/<token>/ for a member who may see the task, one per port, and everything voxl or ttyd loads is relative to that path, so every request carries the token. A cookie would have to cross from the UI's site into an iframe on another, which third-party cookie blocking refuses. The token is signed by this process, names the task, the port and the login, and expires; the task must still be running for any request it makes to be answered.

Index

Constants

View Source
const PortName = "desktop"

PortName is the exposed port a desktop playbook's task names voxl's port by.

View Source
const TerminalPortName = "terminal"

TerminalPortName is the exposed port a desktop playbook's task names ttyd's port by: a terminal in the turn's workspace, beside its desktop.

View Source
const TokenTTL = 12 * time.Hour

TokenTTL is how long a desktop link works. A viewer that outlives it is closed when it next connects and the panel asks for a new one; a turn's desktop rarely lives longer.

Variables

View Source
var ErrNoDesktop = errors.New("desktop: no desktop to show")

ErrNoDesktop is a task that has no desktop this server can reach right now: not running, not a desktop playbook's, or exposed somewhere this server cannot route to.

Functions

This section is empty.

Types

type Resolver

type Resolver interface {
	Resolve(ctx context.Context, taskID, port string) (Upstream, error)
}

Resolver finds a running task's desktop, or its terminal: the exposed port named port.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service mints desktop links and serves the desktop origin.

func New

func New(base *url.URL, uiOrigin string, resolver Resolver, logger *slog.Logger) (*Service, error)

New serves desktops on base (PODIUM_DESKTOP_URL), framed only by uiOrigin when it is known (PODIUM_PUBLIC_URL; empty allows any framer, which is the local, single-origin dev case).

func (*Service) Handles

func (s *Service) Handles(r *http.Request) bool

Handles reports whether r is addressed to the desktop origin. Everything that is, and only that, is the desktop's: the UI and the API are not served there.

func (*Service) Mint

func (s *Service) Mint(taskID, port, login string) (string, time.Time, error)

Mint is a link to a task's desktop (PortName) or terminal (TerminalPortName) for login. The caller has already decided login may see the task and that it is a running desktop; the link is refused again at use if it is not.

func (*Service) Origin

func (s *Service) Origin() string

Origin is the desktop origin, scheme://host[:port], which the UI's CSP must let it frame.

func (*Service) Ready

func (s *Service) Ready(ctx context.Context, taskID string) bool

Ready reports whether a task's desktop answers yet: voxl's health check, through the same route and with the same credentials a viewer's requests take. podium-desktop starts the terminal before it waits for voxl, so a desktop that answers has its terminal too. A task is running before its desktop is up — the display, XFCE, Chromium and the stream take seconds, and the first run on a machine pulls the image — and a frame loaded in that window shows an error page it never recovers from: the panel waits on this instead.

func (*Service) ServeHTTP

func (s *Service) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP serves /t/<task>/<token>/<rest>: <rest> is voxl's, or ttyd's, own path.

type Upstream

type Upstream struct {
	URL   *url.URL
	Apply func(*http.Request)
}

Upstream is where a desktop answers, and what each request to it has to carry for the provider in front of it to let it through (Modal's connect token, for one).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL