Which board to build for an incoming request – and how a board is carried
across the session$reload() that a preserve_board restore triggers – is
the job of an app-level board loader, passed to serve() as its
loader argument. A board_loader() pairs a resolve(request, session, default) – returning the board to build for an incoming request, or
NULL for the serve() default – with an optional stage(board, session), which persists a board and returns the URL query parameters that
reference it (a resolve-only loader, e.g. one not backing a restore, leaves
stage NULL). serve() uses that one loader for both the request-phase
resolution (at the GET, where session is NULL, and at the WS connect)
and the in-session staging when a restore fires; core writes those
parameters into the URL and drives the reload, so the reload stays a
guaranteed core mechanism that no loader can opt out of.
Arguments
- resolve, stage
Paired functions backing a
board_loader:resolveisfunction(request, session, default)returning theboardto build orNULL;stageisfunction(board, session)(orNULLfor a loader that does not stage, e.g. resolve-only) which persistsboardand returns the URL query parameters referencing it (core writes them and reloads). They share private state, so aboard_loaderis built as a unit, not supplied as two loose functions.- x
Object to test for
board_loader-ness
Value
board_loader() and local_loader() return a board_loader object
and is_board_loader() a scalar logical.
Details
resolve receives the raw HTTP request at both phases (the UI request at
the GET, session$request at the WS), the session (NULL at the GET),
and default – the board passed to serve() (the serve() default,
built when resolve returns NULL), which a loader can also derive its own
result from (e.g. clear_board(default)). A loader that keys off URL query
parameters reads them itself, minding the phase split: the query is on
request$QUERY_STRING at the GET but session$clientData$url_search at the
WS (the websocket request carries neither).
The default local_loader() keeps its handoff in a per-loader store (no
process global) and is therefore single-process; multi-user deployments pass
a loader resolving from a shared backend (as blockr.session does).