Documentation
¶
Overview ¶
Package broker implements the read-only RFB multi-viewer feasibility spike. It is not wired into public routes. Callers must authenticate/authorize both transports before passing streams here; RFB security None is not platform auth.
Index ¶
Constants ¶
const ( MaxParticipants = 8 MaxPixels = 4096 * 2160 )
Variables ¶
var ( ErrClosed = errors.New("display broker closed") ErrCapacity = errors.New("display broker participant limit reached") )
Functions ¶
This section is empty.
Types ¶
type Broker ¶
type Broker struct {
// contains filtered or unexported fields
}
Broker owns a single upstream and up to MaxParticipants observers. Frames are immutable snapshots: each observer holds at most one in-flight snapshot, while intervening updates coalesce into the current snapshot. No socket I/O runs under mu. A controller participant forwards guest-mutating RFB messages upstream through an InputGate, serialized against capture's own write side. Create a new Broker for each upstream connection generation.
func (*Broker) Close ¶
func (b *Broker) Close()
Close is idempotent, including before Run. It wakes waiters and terminates blocked handshakes/readers/writers without holding the broker lock.
func (*Broker) Run ¶
Run owns capture until EOF, protocol failure or cancellation. It is single-use and always closes the upstream and all attached observers before returning.
func (*Broker) ServeObserver ¶
ServeObserver owns c until disconnect, cancellation or broker shutdown. It blocks; callers run separate observers in separate goroutines. All input mutations are discarded.
func (*Broker) ServeParticipant ¶
func (b *Broker) ServeParticipant(ctx context.Context, c Stream, controller bool, gate InputGate) error
ServeParticipant serves c like ServeObserver but, when controller and gate are set, forwards guest-mutating RFB messages (keys, pointer, clipboard, desktop resize, extended keys) upstream through gate. Dropped writes and the gate's fencing errors surface to the caller. Observer-local messages (framebuffer requests, pixel format, encodings for the participant's own view) never reach the upstream.
type InputGate ¶
type InputGate interface {
DispatchInput(fn func()) error
}
InputGate admits controller input writes. display.Fence satisfies it: writes only land while the caller still holds the registry controller role and the control lease is renewable, and stop at the fencing bound otherwise.
type Stream ¶
type Stream interface {
io.ReadWriteCloser
SetDeadline(time.Time) error
SetWriteDeadline(time.Time) error
}
Stream is a deadline-capable byte stream (net.Conn or a binary WebSocket adapter). Close must unblock concurrent reads/writes. A WebSocket message is not an RFB message; its adapter must flatten message boundaries. Streams must tolerate one concurrent reader and one concurrent writer.
type WebSocketStream ¶
type WebSocketStream struct {
// contains filtered or unexported fields
}
WebSocketStream flattens binary WebSocket messages into an RFB byte stream. A single goroutine reads and a single goroutine writes; Close may run from another goroutine. It does not dial, upgrade or authorize a connection.
func NewWebSocketStream ¶
func NewWebSocketStream(c *websocket.Conn) *WebSocketStream
func (*WebSocketStream) Close ¶
func (s *WebSocketStream) Close() error
func (*WebSocketStream) SetDeadline ¶
func (s *WebSocketStream) SetDeadline(t time.Time) error
func (*WebSocketStream) SetWriteDeadline ¶
func (s *WebSocketStream) SetWriteDeadline(t time.Time) error