Files
KoalaSync/docs/host-control-mode.md

3.8 KiB

Host Control Mode

This document describes the Host Control Mode implementation in the relay and extension. It only covers behavior implemented in the current codebase.

Modes

everyone

  • Default room mode.
  • Any peer may send room-moving playback events.

host-only

  • Only controllers may send room-moving playback events.
  • The host is always a controller.
  • The host can promote additional peers to controllers.
  • Guests can keep watching locally in solo/desynced mode, but their local actions still do not drive the shared room.

Room-moving events are:

  • play
  • pause
  • seek
  • force_sync_prepare
  • force_sync_execute
  • episode_lobby
  • episode_lobby_cancel

Heartbeats, force-sync ACKs, episode-ready events, ping/pong, and command ACKs remain allowed for guests.

Server State

Rooms store Host Control state in memory:

{
  hostPeerId,
  controlMode,
  controllers,
  lastControlModeChangeAt,
  lastRoleChangeAt,
  forceSyncInitiator
}

controllers is a Set on the server and is serialized as an array in room_data and control_mode.

State is not persisted across relay restarts.

Authority Rules

Changing mode

Only hostPeerId may send set_control_mode.

Valid values:

  • everyone
  • host-only

Invalid values are ignored. Non-host attempts are ignored and the sender receives the current control_mode snapshot so optimistic UI can revert.

Mode changes are debounced per room for 500 ms.

Promoting and demoting controllers

Only hostPeerId may send set_peer_role.

The host cannot demote themself. No-op role changes are ignored. Role changes are debounced per room for 500 ms.

Host leaving

When the host leaves and peers remain:

  • the next peer becomes hostPeerId;
  • controlMode falls back to everyone;
  • controllers is reset to the new host;
  • the relay broadcasts control_mode.

When a non-host controller leaves, the relay removes that peer from controllers and broadcasts control_mode.

Enforcement

The implementation has two enforcement points:

  • The extension background script blocks local guest attempts in host-only and sends HOST_BLOCKED to the content script for local UX.
  • The relay drops room-moving events from non-controllers in host-only, so old or modified clients cannot drive the room.

The relay is the authority for room-wide effects.

Guest UX

When a guest action is blocked locally, the content script classifies it:

  • deliberate user action: show the host-control dialog;
  • likely involuntary player action (buffering, tab refocus, no recent gesture): silently snap back when safe;
  • live/DVR stream: degrade without forcing snap-back.

The dialog offers:

  • stay in sync: resync to the host;
  • watch on my own: enter solo/desynced mode.

In solo/desynced mode:

  • the guest can control their local video;
  • host room commands are ignored locally, except force-sync preparation is ACKed so the host's flow can continue;
  • the guest can resync to the host.

The extension reports desynced in peer status so the host UI can show that a guest is watching solo.

Force Sync Edge Case

The relay tracks forceSyncInitiator after a controller sends force_sync_prepare.

This allows that same initiator's force_sync_execute through even if their controller role changes before execute arrives. Without this, a demotion in the middle of a force-sync flow could leave peers waiting after prepare.

The relay clears forceSyncInitiator after execute or when the initiator leaves.

Capabilities

The relay advertises Host Control support in room_data.capabilities:

  • host-control
  • co-host

The extension hides or disables matching UI when capabilities are missing.

See PROTOCOL.md for payloads and relay behavior for:

  • set_control_mode
  • control_mode
  • set_peer_role
  • host-only gated relay events