Methods
(static) closeSocket() → {void}
Best-effort teardown of the socket child + its observers.
- Type:
- void
(static) connectAndPump(url) → {boolean}
Open the socket and pump events until it closes or errors. Sends a KeepAlive whenever the wait times out at the interval Jellyfin's ForceKeepAlive requested (0 = block until an event, before any ForceKeepAlive arrives). Marshals each dispatchable command to the main thread. Returns on close. Returns TRUE when the connection was ESTABLISHED and STABLE — it opened AND stayed up at least STABLE_SESSION_MS — so runReceiver can reset its reconnect backoff. A never-opened socket, or one that opened but dropped sooner than that (a flap), returns FALSE so the backoff keeps climbing. Threshold = the backoff cap (30s): a session that outlived the max backoff interval was clearly real.
| Name | Type | Description |
|---|---|---|
url | string |
- Type:
- boolean
(static) dispatchBatch(body) → {integer}
Parse a long-poll 200 body (a JSON array of { MessageType, Data, MessageId } envelopes) and marshal each dispatchable command to the main thread, in array order. Returns how many commands were actually dispatched (0 for an empty array, a garbled body, or an all-ignore batch) so the caller can floor a pointless fast 200 against a hot-loop.
| Name | Type | Description |
|---|---|---|
body | string |
- Type:
- integer
(static) dispatchEnvelope(envelope) → {boolean}
Normalize one long-poll envelope and marshal it if dispatchable; returns true iff it was dispatched. The long-poll contract never carries KeepAlive/ForceKeepAlive (the poll request is the keepalive), so keepalive is treated like ignore here — there's no socket to answer on. Reuses the same pure parseMessage as the ws path.
| Name | Type | Description |
|---|---|---|
envelope | object |
- Type:
- boolean
(static) handleFrame(data) → {void}
Parse one inbound frame and either answer a keepalive or marshal a dispatchable command.
| Name | Type | Description |
|---|---|---|
data | object |
- Type:
- void
(static) httpGet(url, timeoutMs) → {object}
Authenticated async GET on this Task thread. Blocks up to timeoutMs for the response. Returns { code, body }; code = 0 on a failed initiation or a timeout. A fresh roUrlTransfer + roMessagePort per call avoids cross-call event bleed. NEVER logs the url — the Authorization header carries the token. Mirrors the raw-transfer pattern in captionTask.bs / ServerReachableTask.bs.
| Name | Type | Description |
|---|---|---|
url | string | |
timeoutMs | integer |
- Type:
- object
(static) init() → {void}
Remote-control receiver (#666) — the ws:// "Cast to JellyRock" listener. See RemoteControlTask.xml for the lifecycle/threading overview. This task owns the vendored WebSocketClient node and runs the Jellyfin session socket off the render thread: open -> parse frames -> answer keepalive -> marshal commands to the main thread -> reconnect with backoff. It NEVER dispatches (that's remoteDispatch on the main thread) and NEVER logs the socket url (it carries the auth token).
- Type:
- void
(static) marshalCommand(command) → {void}
Marshal a normalized command to the main thread. Drops the bulky original 'raw' Data first (a whole ItemIds list for a series/album can be large) — the normalized fields carry everything the main thread needs. Shared by both transports; callers gate out keepalive/ignore before calling.
| Name | Type | Description |
|---|---|---|
command | object |
- Type:
- void
(static) runLongPollReceiver(serverUrl) → {void}
HTTPS long-poll transport (#667). Roku can't ws:// a secure server, so on https we consume the companion plugin's authenticated long-poll command channel over TLS (roUrlTransfer). The poll request ITSELF is the keepalive (it refreshes server-side session activity), so — unlike the ws path — there's no client KeepAlive to send. See docs/architecture/remote-control-longpoll-contract.md.
| Name | Type | Description |
|---|---|---|
serverUrl | string |
- Type:
- void
(static) runReceiver() → {void}
Post-login entry point (control="RUN" from Home.isFirstRun, once the session token exists). Selects the transport by server scheme: an http:// server uses the ws:// session socket (#666); an https:// server can't ws:// (Roku has no socket TLS) so it probes for the companion plugin and, if present, runs the long-poll command channel (#667). SignOut sets control="STOP", terminating this thread.
- Type:
- void
(static) runWsReceiver(serverUrl) → {void}
ws:// transport (#666): build the session-socket url and run the connect/reconnect loop until the session ends (token rotated, or control="STOP" kills the thread).
| Name | Type | Description |
|---|---|---|
serverUrl | string |
- Type:
- void
(static) throttleEmptyPoll(pollTimer) → {void}
Hot-loop floor for an abnormally fast EMPTY poll. A compliant plugin holds an empty poll for ~POLL_WAIT_MS, so this never fires against it; a misbehaving plugin that returns an empty 200/204 near-instantly would otherwise spin the poll loop with no backoff. Sleep out the remainder of a minimum interval. Only ever called on the empty path, so it never delays a real command.
| Name | Type | Description |
|---|---|---|
pollTimer | object |
- Type:
- void