Skip to main content

ServeConfig

Struct ServeConfig 

Source
pub struct ServeConfig {
Show 35 fields pub relay_addr: SocketAddr, pub rtmp_addr: SocketAddr, pub admin_addr: SocketAddr, pub hls_addr: Option<SocketAddr>, pub hls_dvr_window_secs: u32, pub hls_target_duration_secs: u32, pub hls_part_target_ms: u32, pub whep_addr: Option<SocketAddr>, pub whip_addr: Option<SocketAddr>, pub dash_addr: Option<SocketAddr>, pub rtsp_addr: Option<SocketAddr>, pub srt_addr: Option<SocketAddr>, pub mesh_enabled: bool, pub max_peers: usize, pub auth: Option<SharedAuth>, pub record_dir: Option<PathBuf>, pub archive_dir: Option<PathBuf>, pub hmac_playback_secret: Option<String>, pub wasm_filter: Vec<PathBuf>, pub install_prometheus: bool, pub otel_metrics_recorder: Option<OtelMetricsRecorder>, pub tls_cert: Option<PathBuf>, pub tls_key: Option<PathBuf>, pub cluster_listen: Option<SocketAddr>, pub cluster_seeds: Vec<String>, pub cluster_node_id: Option<String>, pub cluster_id: Option<String>, pub cluster_advertise_hls: Option<String>, pub cluster_advertise_dash: Option<String>, pub cluster_advertise_rtsp: Option<String>, pub federation_links: Vec<FederationLink>, pub no_auth_live_playback: bool, pub no_auth_signal: bool, pub mesh_root_peer_count: Option<usize>, pub mesh_ice_servers: Vec<IceServer>,
}
Expand description

Configuration passed to [start] to bring up a full-stack LVQR server.

Every *_addr field accepts port 0 for ephemeral port binding; the real bound address is reported back through [ServerHandle].

Fields§

§relay_addr: SocketAddr

QUIC/MoQ relay bind address.

§rtmp_addr: SocketAddr

RTMP ingest bind address.

§admin_addr: SocketAddr

Admin HTTP (and WS relay/ingest) bind address.

§hls_addr: Option<SocketAddr>

Optional LL-HLS HTTP bind address. When Some, start() spins up a dedicated HlsServer axum router on this address that observes the RTMP bridge’s fragment output and serves /playlist.m3u8, /init.mp4, and the per-chunk media URIs the playlist references. When None, no HLS surface is exposed.

§hls_dvr_window_secs: u32

DVR window depth in seconds for the LL-HLS sliding-window eviction. Translated to max_segments = dvr_secs / target_duration_secs at server construction. 0 means unbounded (no eviction). Default: 120 (60 segments at 2 s).

§hls_target_duration_secs: u32

LL-HLS target segment duration in seconds. Controls both the EXT-X-TARGETDURATION declaration and the CMAF segmenter’s segment-close policy. Default: 2.

§hls_part_target_ms: u32

LL-HLS target partial (chunk) duration in milliseconds. Controls both EXT-X-PART-INF:PART-TARGET and the CMAF segmenter’s partial-close policy. Default: 200.

§whep_addr: Option<SocketAddr>

Optional WHEP (WebRTC HTTP Egress Protocol) HTTP bind address. When Some, start() constructs a Str0mAnswerer and a WhepServer, attaches the server as a RawSampleObserver on the RTMP bridge, and spins up an axum router on this address that accepts POST /whep/{broadcast} SDP offers, answers them via str0m, and fans each ingest sample into every subscribed session. When None, no WHEP surface is exposed and no str0m state is constructed.

§whip_addr: Option<SocketAddr>

Optional WHIP (WebRTC HTTP Ingest Protocol) HTTP bind address. When Some, start() constructs a Str0mIngestAnswerer and a WhipMoqBridge, attaches it as an ingest sink, and spins up an axum router on this address that accepts POST /whip/{broadcast} SDP offers. When None, no WHIP surface is exposed.

§dash_addr: Option<SocketAddr>

Optional MPEG-DASH HTTP bind address. When Some, start() spins up a MultiDashServer axum router on this address that observes the same fragment stream the LL-HLS bridge observes and serves /dash/{broadcast}/manifest.mpd plus numbered segment URIs. RTMP and WHIP publishers both feed the DASH egress without any per-protocol wiring.

§rtsp_addr: Option<SocketAddr>

Optional RTSP ingest bind address. When Some, start() spins up an RtspServer on this TCP address that accepts RTSP ANNOUNCE/RECORD sessions with interleaved RTP and fans depacketized H.264/HEVC through the fragment observer chain.

§srt_addr: Option<SocketAddr>

Optional SRT ingest bind address. When Some, start() spins up an SrtIngestServer on this UDP address that accepts MPEG-TS streams and fans them through the fragment observer chain.

§mesh_enabled: bool

Enable the peer mesh coordinator and /signal endpoint.

§max_peers: usize

Max children per mesh parent when mesh_enabled.

§auth: Option<SharedAuth>

Pre-built auth provider. None means open access (NoopAuthProvider).

§record_dir: Option<PathBuf>

Recording directory. None disables recording.

§archive_dir: Option<PathBuf>

DVR archive directory. When Some, start() opens a RedbSegmentIndex under <archive_dir>/archive.redb and attaches an archiving fragment observer to the RTMP bridge that writes every emitted fragment to <archive_dir>/<broadcast>/<track>/<seq>.m4s and records a SegmentRef against the index. The index + segment files back the DVR scrub / time-range playback surface (Tier 2.4).

§hmac_playback_secret: Option<String>

Optional HMAC signing secret for short-lived playback URLs (PLAN v1.1 row 121). When set, every /playback/* handler accepts an alternative auth path: a ?exp=<unix_ts>&sig= <base64url> pair where sig = HMAC-SHA256(secret, "<path> ?exp=<ts>"). A valid signature short-circuits the normal subscribe-token check so an operator can mint a one-off share link for a third party who cannot authenticate. An expired or tampered signature returns 403 (NOT 401) so the client can distinguish missing auth from wrong auth. When unset, all playback routes fall back to their existing SubscribeAuth gate.

§wasm_filter: Vec<PathBuf>

Ordered list of WASM fragment filter modules. When non-empty, start() loads + compiles each module via lvqr_wasm::WasmFilter::load and installs a single lvqr_wasm::ChainFilter tap on the shared FragmentBroadcasterRegistry before any ingest listener starts accepting traffic. Chain order is preserved; the first filter that drops a fragment short-circuits the rest of the chain for that fragment. Each path is watched independently via its own WasmFilterReloader so hot-swapping one slot does not disturb the others.

The tap observes every fragment flowing through every broadcaster and drives lvqr_wasm_fragments_total{outcome=keep|drop} counters; in v1 it does NOT modify what downstream subscribers receive (session-86 scope narrowing). Leave empty to disable.

§install_prometheus: bool

Install the global Prometheus recorder. Must be false in tests because metrics-exporter-prometheus panics on the second install in a process. main.rs sets this to true.

§otel_metrics_recorder: Option<OtelMetricsRecorder>

Pre-built OTLP metrics recorder handed off by lvqr_observability::init when LVQR_OTLP_ENDPOINT is set. When Some, start() installs it as the global metrics-crate recorder – either on its own or composed with the Prometheus recorder via metrics_util::layers::FanoutBuilder when install_prometheus is also true. When None, only the Prometheus path runs (legacy behavior).

§tls_cert: Option<PathBuf>

Path to TLS certificate (PEM). Reserved; not consumed yet. The relay auto-generates self-signed certs when unset.

§tls_key: Option<PathBuf>

Path to TLS private key (PEM). Reserved; not consumed yet.

§cluster_listen: Option<SocketAddr>

Optional cluster gossip bind address. When Some, start() bootstraps an lvqr_cluster::Cluster on this address, wires it into the admin router so /api/v1/cluster/* answers, and installs an OwnerResolver on the HLS server so subscribers hitting this node for a peer-owned broadcast receive a 302 pointing at the owner. None (default) disables clustering and the node behaves as a standalone single-process server.

Feature-gated on cluster; the field is present regardless so ServeConfig stays ABI-stable across feature flips.

§cluster_seeds: Vec<String>

Cluster peer seed addresses. Each entry is an ip:port string the new node gossips to on boot. Ignored when cluster_listen is None.

§cluster_node_id: Option<String>

Cluster-node identifier. None auto-generates a random lvqr-<16 alphanumeric> id at bootstrap.

§cluster_id: Option<String>

Cluster tag gossipped in every SYN. Chitchat rejects cross-cluster gossip so two LVQR deployments on the same subnet stay isolated. Empty string falls back to the crate-default ("lvqr").

§cluster_advertise_hls: Option<String>

Externally-reachable HLS base URL this node advertises (e.g. "http://a.local:8888"). When clustering is enabled, start() writes this URL into the per-node endpoints KV so peers redirecting subscribers know where to send them. None skips the publish; peers will then 404 rather than redirect for this node’s broadcasts.

§cluster_advertise_dash: Option<String>

Externally-reachable DASH base URL this node advertises (e.g. "http://a.local:8888"). Shape matches cluster_advertise_hls; peers use this when composing a 302 Location for /dash/... requests.

§cluster_advertise_rtsp: Option<String>

Externally-reachable RTSP base URL this node advertises (e.g. "rtsp://a.local:8554"). Used by the RTSP 302 redirect-to-owner path on DESCRIBE / PLAY for peer-owned broadcasts.

§federation_links: Vec<FederationLink>

Cross-cluster federation links. Each link opens a single outbound MoQ session to a peer cluster’s relay and re-publishes matching broadcasts into the local origin. Empty list disables federation. Feature-gated on cluster since FederationLink lives in lvqr-cluster. Tier 4 item 4.4.

§no_auth_live_playback: bool

Escape hatch for deployments that want open live HLS + DASH playback with auth scoped to ingest, admin, and DVR only. When false (default), the composition root wraps the HLS and DASH routers with the same SubscribeAuth gate that already protects /ws/*, /playback/*, and WHEP. When true, the live HLS and DASH routers are exposed without an auth layer – the pre-session-112 v0.4.0 behavior. Unauthed deployments (Noop provider) see no behavior change either way because the provider always allows. Session 112.

§no_auth_signal: bool

Escape hatch for deployments that want an unauthenticated mesh /signal WebSocket. When false (default), the composition root wraps /signal with the same SubscribeAuth gate pattern that protects other subscribe-side surfaces: Sec-WebSocket-Protocol: lvqr.bearer.<token> preferred, ?token=<token> query fallback. Noop provider deployments see no behavior change because the provider always allows. Configured deployments (static token, JWT) now require a bearer on every /signal upgrade. Only meaningful when mesh_enabled is true. Session 111-B1.

§mesh_root_peer_count: Option<usize>

Override the mesh root_peer_count (number of peers that connect directly to the origin before the tree starts assigning parents). None uses the lvqr_mesh::MeshConfig::default() value of 30. Tests that want to exercise the AssignParent path with a small number of peers set this to 1 so the second peer becomes a child of the first. Only meaningful when mesh_enabled is true. Session 111-B1.

§mesh_ice_servers: Vec<IceServer>

STUN/TURN servers to push to browser peers via the AssignParent server-push message. Empty vec (default) means “no opinion – client picks”: JS MeshPeer falls back to whatever was passed to its constructor (or its hardcoded Google STUN default). Non-empty vec is authoritative: clients rebuild their RTCPeerConnection iceServers list from this snapshot when AssignParent lands. Operator-facing CLI flag is --mesh-ice-servers <JSON> with LVQR_MESH_ICE_SERVERS env fallback. Only meaningful when mesh_enabled is true. Session 143 – TURN deployment recipe.

Implementations§

Source§

impl ServeConfig

Source

pub fn loopback_ephemeral() -> Self

Minimal loopback config for tests: every listener on 127.0.0.1:0, open access, no recording, no Prometheus install.

Trait Implementations§

Source§

impl Clone for ServeConfig

Source§

fn clone(&self) -> ServeConfig

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromRef<T> for T
where T: Clone,

Source§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
Source§

impl<T> FromRef<T> for T
where T: Clone,

Source§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
Source§

impl<T> FutureExt for T

Source§

fn with_context(self, otel_cx: Context) -> WithContext<Self>

Attaches the provided Context to this type, returning a WithContext wrapper. Read more
Source§

fn with_current_context(self) -> WithContext<Self>

Attaches the current Context to this type, returning a WithContext wrapper. Read more
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> IntoRequest<T> for T

Source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> MaybeSend for T
where T: Send,

Source§

impl<T> MaybeSync for T
where T: Sync,