Skip to contents

Start an annotatr-control-v1 service for a session so that a partner process (for example qupflowR) can read state and events and send typed commands. Nothing is started unless this function is called with control = "loopback". The service binds only to 127.0.0.1, requires a random 256-bit bearer token that expires after ttl_seconds, rejects browser-origin requests, enforces JSON size and path limits, and resolves file references only below root. There is no endpoint that evaluates code.

Usage

at_control_start(
  session,
  control = "loopback",
  host = "127.0.0.1",
  port = 0L,
  ttl_seconds = 900L,
  root = NULL,
  token_file = NULL,
  read_only = FALSE,
  max_body_bytes = 1048576L,
  serve = TRUE,
  call = rlang::caller_env()
)

Arguments

session

What to control: an annot_session (or anything at_annotate() accepts).

control

Must be "loopback".

host

Must be "127.0.0.1".

port

Port; 0 picks a random free port.

ttl_seconds

Token lifetime in seconds (1 to 86400).

root

Directory for payload references, exports, training exports and the lifecycle manifest; defaults to <session out_dir>/control.

token_file

Optional path of a new file to receive the token (for a client process). It must not exist yet.

The token needs a cryptographically secure random source (/dev/urandom, or the openssl package where there is none, as on Windows); without one the service is not started (CAPABILITY_UNAVAILABLE).

read_only

Logical; refuse annotation mutations.

max_body_bytes

Maximum request body size.

serve

Logical; start the HTTP listener. With FALSE only in-process calls through the handle are possible (useful in tests).

call

The calling environment, for error reporting.

Value

An at_control_handle (a list with kind = "local", instance_id, session_id, host, port, pid, manifest, expires_at); its print method never shows the token.

Details

The token is never written into URLs, logs, downloads, manifests or RDS files. In-process calls use the returned handle; a separate client process reads the token from token_file, which is created exclusively with owner-only permissions (on Windows, file modes are not enforced; keep the file in a directory only the user can read). A sanitised lifecycle manifest annotatr-control-<instance_id>.json is written to root at start and rewritten when the service stops.

The service stops itself when the token expires: either when the expiry timer runs or, if a request arrives first (for example after the computer slept), on that request. Error messages sent to clients never contain absolute local paths. Request bodies whose declared Content-Length exceeds max_body_bytes, and requests that fail the Host, Origin or token checks, are refused before the body is read (a chunked body without Content-Length is buffered by httpuv and then refused).

Two options bound work done for clients: hyperannotatR.control_mask_max_pixels (default 4096^2) is the largest mask mask.preview builds (without a level it picks the finest pyramid level within the budget), and hyperannotatR.control_hash_max_bytes (default 256 MiB) is the largest queue entry whose content id GET /v1/state computes before the entry is visited (larger entries report image_id: null until then).

Examples

h <- at_control_start(at_example_session(2), serve = FALSE)
at_control_state(h)$state_revision
#> [1] "0"
at_control_stop(h)