SealSkin

collaboration

Collaboration rooms: the room page, its WebSocket, and token fan-out.

A collaboration session is a normal session whose container also runs a control plane that accepts a table of tokens (controller, viewers, gamepad slots, mouse/keyboard owner). This module serves the room page, relays chat and control messages between participants over a WebSocket, and pushes token changes down to every container of the session.

attributelogger
= logging.getLogger(__name__)
attributerouter
= APIRouter()
attributeROOM_CONNECTIONSdict[str, dict[str, Any]]
= {}
attributeROOM_ALIAS_KEYSdict[str, bytes]
= {}
attributeTOKEN_ENDPOINT_CACHEdict[str, str]
= {}
attributeGAMEPAD_SLOTS
= 4
func_alias(session_id, token) -> str

Another participant's token as a viewer is told it.

Stable for the room, so the room page keys that participant's streams and slots by it, and no use for joining.

paramsession_idstr
paramtokenstr

Returns

str
func_as_viewer_sees(session_id, payload, own) -> dict[str, Any]

payload as viewer own receives it.

A room token, the controller's above all, lets whoever holds it take that participant's part, so only own stays itself.

paramsession_idstr
parampayloaddict[str, Any]
paramownstr

Returns

dict[str, typing.Any]
func_absolutize_room_assets(html) -> str

Rewrite relative asset references in the room template to /companion/ui/room/.

The page is served at /room/<session_id> while its hashed assets live under the static /ui/room/ mount, so relative references would 404. They are addressed through the companion lane, which a reverse proxy that signs users in passes raw, so a guest with an invite link, who has no account at the proxy's provider, gets the page whole.

paramhtmlstr

Raw room template.

Returns

str

The template with relative src/href values made absolute.

func_join_url(session_id, token) -> str

Return the relative invite URL of a room for token.

paramsession_idstr
paramtokenstr

Returns

str
funccollaborative_room(request, session_id, collab_token=Query(None, alias='token')) -> Response

Serve the collaboration room page.

Authenticates the visitor as controller (session access token or controller token), existing viewer, or new participant/read-only viewer via an invite token. New viewers get a personal token and are redirected.

paramrequestRequest

Incoming request.

paramsession_idUUID

Collaboration session id.

paramcollab_tokenstr | None
= Query(None, alias='token')

Controller, viewer, or invite token.

Returns

fastapi.responses.Response

The room HTML, or a redirect for newly registered viewers.

funcbroadcast_token_state(session_id, session_data) -> None

Push the current token table to every container of a session.

paramsession_idstr

Session id.

paramsession_datadict[str, Any]

Session record.

Returns

None
func_owner_group(username) -> list[str]

Return the groups of a user.

paramusernamestr

Returns

list[str]
funcbroadcast_to_room(session_id, payload) -> None

Send a JSON payload to every participant of a room.

paramsession_idstr
parampayloaddict[str, Any]

Returns

None
funcbroadcast_binary_to_room(session_id, payload, sender_ws) -> None

Relay a binary (audio/video) packet to every participant except the sender.

paramsession_idstr
parampayloadbytes
paramsender_wsWebSocket

Returns

None
funcroom_websocket(websocket, session_id) -> None

Handle a participant's WebSocket for the lifetime of the connection.

paramwebsocketWebSocket

The accepted socket.

paramsession_idUUID

Collaboration session id.

Returns

None
funcbroadcast_state(session_id) -> None

Send the participant list and designated speaker to the room.

paramsession_idstr

Returns

None
funcvalid_slot(slot) -> bool

Whether slot names one of the container's gamepad slots.

paramslotAny

Returns

bool
funcgamepads_text(slots) -> str

Name slots for a room notice: "Gamepad 3", "Gamepads 3 and 4".

paramslotslist[int]

Returns

str
func_slot_holders(session_data) -> list[tuple[dict[str, Any], str, str, Any]]

Every participant that can hold gamepad slots.

paramsession_datadict[str, Any]

Returns

list

(record, key, name, token) for each: the controller's slots live under

func_take_slot(session_data, slot, keep=None) -> list[str]

Take slot from whoever holds it other than token keep.

paramsession_datadict[str, Any]
paramslotint
paramkeepAny
= None

Returns

list

The room notices saying so.

func_push_slots(session_id, session_data, notices) -> None

Push a slot change to the session's containers, keep it, and tell the room.

paramsession_idstr
paramsession_datadict[str, Any]
paramnoticeslist[str]

Returns

None
funchandle_assign_slot(session_id, viewer_token, slot) -> None

Give a participant a gamepad slot beside those it holds.

The slot is taken from whoever held it, and None clears every slot the participant holds. A participant holding several drives one with each of its local controllers, in slot order: Selkies hands a token's list to the page's pads in turn.

paramsession_idstr
paramviewer_tokenstr
paramslotint | None

Returns

None
funchandle_release_slot(session_id, slot) -> None

Return a gamepad slot to the pool from whoever holds it.

paramsession_idstr
paramslotAny

Returns

None
funchandle_assign_mk(session_id, target_token) -> None

Give mouse and keyboard control to a participant (None = controller).

paramsession_idstr
paramtarget_tokenstr | None

Returns

None
funcnotify_session_ended(session_id) -> None

Tell every participant that the session ended and drop the room.

paramsession_idstr

Returns

None