pub struct DataPlane { /* private fields */ }Expand description
The proxy dataplane: reads config generations from ConfigState and
keeps an UpstreamRegistry coupled to each generation.
Lifecycle: after every successful compile_and_publish, the operator
(dwara-bin’s reload path) calls DataPlane::refresh, which builds a
new generation pair and swaps it in atomically. In-flight requests hold
an Arc to the old pair, so old pools stay alive until the last request
using them completes — reloads drop nothing.
Implementations§
Source§impl DataPlane
impl DataPlane
Sourcepub fn new(state: Arc<ConfigState>) -> Arc<Self>
pub fn new(state: Arc<ConfigState>) -> Arc<Self>
Build from the state’s currently published snapshot.
Sourcepub fn set_state_store(&self, store: Arc<StateStore>)
pub fn set_state_store(&self, store: Arc<StateStore>)
Attach the DWARA_STATE_DB store (DWARA_STATE_DB deployments): credentials then come from the store’s hot-cached records instead of in-memory config hashes. Call once, before serving traffic; rebuilds the authenticator against it immediately.
Sourcepub fn set_license_status(&self, status: i64)
pub fn set_license_status(&self, status: i64)
Publish the license status gauge (DW-032): 0 = no license (OSS), 1 = valid, 2 = expired within grace, 3 = expired past grace. Set once at startup and on every reload.
Sourcepub fn set_locality_context(&self, ctx: LocalityContext)
pub fn set_locality_context(&self, ctx: LocalityContext)
DW-094 (Ent): set the edge’s locality context (region/zone).
Overrides the env-var-derived context set at construction. Applied
immediately to the current registry’s balancers and to every
future registry built by refresh. Used by the CP/DP edge
runtime to propagate the edge’s labels (set by the controller)
to the dataplane’s load balancers.
Sourcepub fn state_store(&self) -> Option<Arc<StateStore>>
pub fn state_store(&self) -> Option<Arc<StateStore>>
The DWARA_STATE_DB store when one is attached (None = pure-config
credentials). Admin surface seam (DW-022): /stats reports the
store’s schema version when present.
Sourcepub fn set_analytics(&self, store: Arc<EmbeddedAnalytics>)
pub fn set_analytics(&self, store: Arc<EmbeddedAnalytics>)
Attach the embedded analytics store (DW-043): dwara-bin opens the configured database, spawns the writer/rollup workers, and hands the store here ONCE, before serving traffic. There is no detach: analytics lifetime is the process lifetime (the database file outlives restarts; the runtime handle does not).
Sourcepub fn analytics(&self) -> Option<Arc<EmbeddedAnalytics>>
pub fn analytics(&self) -> Option<Arc<EmbeddedAnalytics>>
The embedded analytics store when one is attached (DW-043; None = the analytics endpoints 404 and recording is a no-op). Admin surface seam.
Sourcepub fn ai_runtime(&self) -> Option<Arc<AiRuntime>>
pub fn ai_runtime(&self) -> Option<Arc<AiRuntime>>
The compiled AI runtime for the current generation (DW-075;
None when no ai: block). Admin surface seam for DW-080
credential pool status introspection.
Sourcepub fn set_record_stream(&self, stream: Arc<AccessRecordStream>)
pub fn set_record_stream(&self, stream: Arc<AccessRecordStream>)
Attach the access-record stream (DW-121): dwara-bin constructs
it ALWAYS (capacity from the config when the block is present
at boot, the default otherwise) and hands it here once, before
serving traffic; the flusher is spawned separately
(DataPlane::spawn_record_stream_flusher). Arming is the
generation’s business: this immediately applies the CURRENT
compiled sink set’s enabled flag, so a stream attached after
construction with sinks configured does not wait for a reload
to start queuing.
Sourcepub fn record_stream(&self) -> Option<Arc<AccessRecordStream>>
pub fn record_stream(&self) -> Option<Arc<AccessRecordStream>>
The access-record stream when one is attached (DW-121; None = offers are no-ops — the direct-drive tests’ shape). Scrape and diagnostics seam.
Sourcepub fn stream_targets(&self) -> Receiver<StreamTargets>
pub fn stream_targets(&self) -> Receiver<StreamTargets>
A fresh receiver of the CURRENT record-stream target state
(DW-121); updates on every refresh. Tests driving the flusher
directly use this.
Sourcepub fn spawn_record_stream_flusher(
self: &Arc<Self>,
shutdown: Receiver<()>,
) -> JoinHandle<()>
pub fn spawn_record_stream_flusher( self: &Arc<Self>, shutdown: Receiver<()>, ) -> JoinHandle<()>
Spawn the record-stream flusher (DW-121): one background task
draining the stream’s bounded channel into ordered batches and
delivering each batch (one retry cycle per batch) to the
current generation’s sinks. Exactly one flusher per dataplane
(the channel’s single-consumer receiver is gone after the
first); a duplicate spawn logs and returns a finished handle.
The task stops on shutdown after one final drain-and-flush.
Sourcepub fn set_geoip(&self, db: Arc<GeoipDb>)
pub fn set_geoip(&self, db: Arc<GeoipDb>)
Attach/replace the GeoIP database (DW-050). dwara-bin opens it at startup and the hot-reload watcher swaps it; the swap is atomic and in-flight requests keep their loaded reader.
Sourcepub fn geoip(&self) -> Option<Arc<GeoipDb>>
pub fn geoip(&self) -> Option<Arc<GeoipDb>>
The current GeoIP database, if one is loaded (DW-050).
Sourcepub fn set_credential_pepper(&self, pepper: Option<Vec<u8>>)
pub fn set_credential_pepper(&self, pepper: Option<Vec<u8>>)
Attach the per-deployment credential pepper (#124). The bytes are resolved by the CALLER (dwara-bin, through the SecretSource extension seam — the security domain never touches extensions) and threaded down here; an empty slice is treated as “no pepper” (legacy-only mode). Call once, before serving traffic; rebuilds the authenticator against it immediately.
Sourcepub fn set_credential_pepper_previous(&self, pepper: Option<Vec<u8>>)
pub fn set_credential_pepper_previous(&self, pepper: Option<Vec<u8>>)
SEC-10: Set the PREVIOUS credential pepper (rotation window).
During a pepper rotation, the old pepper verifies existing
stored hashes while the new pepper (set via
set_credential_pepper) is used for new writes. Call once,
before serving traffic. An empty slice is treated as “no
previous pepper” (rotation window inactive).
Sourcepub fn hash_new_credential(&self, secret: &str) -> String
pub fn hash_new_credential(&self, secret: &str) -> String
Hash a NEW api-key secret exactly as the config seed path does
(DW-046, the admin credential-issue endpoint’s helper):
hmac-sha256:<hex> when a pepper is configured (#124),
legacy sha256:<hex> otherwise — the authenticator verifies
either shape with the SAME pepper state, so an issued key
authenticates immediately. The secret never leaves this call’s
stack in the clear (hashing is one-shot; no storage of raw
bytes anywhere).
Sourcepub fn refresh(&self)
pub fn refresh(&self)
Rebuild the (snapshot, registry) pair from the state’s current snapshot and swap it in. Call after every successful publish. Balancer state (in-flight counters, WRR phase, slow-start clocks for unchanged endpoint addresses) carries over from the previous generation, so weight/endpoint changes take effect without a restart and without resetting live counters (DW-011).
Contract (#46): the authenticator rebuild re-resolves ${...}
secret references from the CURRENT snapshot’s config, so a
refresh is only meaningful after the publish that validated
them. A bare refresh against a snapshot whose secret sources
have since broken loud-skips the affected credentials BY DESIGN
(the key stops authenticating; never stale plaintext). Both
call sites — the binary’s reload path and the admin publish
path — invoke it only on the success side of a publish.
DW-165 review: this inline variant resolves registry plugin
sources synchronously (bounded by the resolver’s per-publish
budget). Async callers that must not run blocking IO on a
worker thread use Self::refresh_with_sources with
resolutions produced on spawn_blocking.
Sourcepub fn refresh_with_sources(&self, sources: SourceResolutions)
pub fn refresh_with_sources(&self, sources: SourceResolutions)
DW-165 review: refresh with PRE-RESOLVED registry plugin
sources. The binary’s reload path runs
wasm::source::resolve_sources inside
tokio::task::spawn_blocking (DNS via getaddrinfo and the
sync TLS reads are blocking syscalls) and hands the result
here, so network IO never runs on an async worker thread. The
resolutions are keyed by plugin name; the lifecycle re-checks
each pinned digest against the loaded module’s checksum before
trusting a handed-in path, so a resolution that predates the
generation being built can only fail closed.
Sourcepub fn plugin_lifecycle(&self) -> &PluginLifecycle
pub fn plugin_lifecycle(&self) -> &PluginLifecycle
DW-158: read accessor for the plugin lifecycle (the /plugins
status surface and tests). Read-only by design — every mutation
flows through reload_plugins on generation swap, never through
an accessor handed to a presentation layer.
Sourcepub fn plugin_statuses(&self) -> Vec<PluginStatusEntry>
pub fn plugin_statuses(&self) -> Vec<PluginStatusEntry>
DW-158: the plugin status surface — one entry per plugin the
CURRENT generation declares (config order), with kind, source,
digest, lifecycle state, effective limits, declared phases, and
the routes referencing it. Backs the admin GET /plugins
endpoint and the CLI status section.
Sourcepub fn native_plugin_registry(&self) -> &NativeRegistry
pub fn native_plugin_registry(&self) -> &NativeRegistry
DW-157: the native filter registry. Compiled-in filters register
factories here at startup (config selects one with native: on
a plugin); the dataplane’s per-request chain resolves names
against it.
Sourcepub fn apply_service_split_weights(
&self,
service: &str,
new_canary_weight: u64,
) -> bool
pub fn apply_service_split_weights( &self, service: &str, new_canary_weight: u64, ) -> bool
DW-091: apply new service split weights atomically (transient,
reverts on config reload). Loads the current generation, clones
the registry, rebuilds the split for service with the new
canary weight (baseline = total - canary, keeping the total
constant), and stores a new Generation. Returns true on
success; false when the service has no split or the rebuild
failed. The canary is the SECOND target (index 1); the
baseline is the first (index 0).
Sourcepub fn apply_ai_canary_weights(
&self,
alias: &str,
new_canary_weight: u64,
) -> bool
pub fn apply_ai_canary_weights( &self, alias: &str, new_canary_weight: u64, ) -> bool
DW-091: apply new AI canary weights atomically (transient,
reverts on config reload). Loads the current generation, clones
the AI runtime, rebuilds the canary split for alias with the
new canary weight (baseline = total - canary, keeping the total
constant), and stores a new Generation. Returns true on
success; false when the alias has no canary or the rebuild
failed. The canary is the SECOND version (index 1); the
baseline is the first (index 0).
Sourcepub fn priority_counters(&self) -> &PriorityCounters
pub fn priority_counters(&self) -> &PriorityCounters
The per-priority admission/shed counters (DW-016). Metrics exposure (DW-021) reads these; tests read them directly.
Sourcepub fn observability(&self) -> &Observability
pub fn observability(&self) -> &Observability
This dataplane’s observability state (DW-021): metric recording, /metrics rendering, and the access-log sampling knob.
Sourcepub fn observability_arc(&self) -> Arc<Observability>
pub fn observability_arc(&self) -> Arc<Observability>
The shared handle behind Self::observability (DW-039: the
WebSocket tunnel task outlives the request and needs an owned
handle to record its policy outcome).
Sourcepub fn events(&self) -> &Arc<EventBus>
pub fn events(&self) -> &Arc<EventBus>
This dataplane’s event bus (DW-044): breaker/ejection/config
events emit onto it; spawn_webhook_deliverer drains it.
Sourcepub fn response_cache(&self) -> &Arc<ResponseCache>
pub fn response_cache(&self) -> &Arc<ResponseCache>
The local response cache (DW-037): lookup/store stages run from
handle, the admin purge endpoint and the metrics gauge walk
read from here. Shared as an Arc because stale-while-revalidate
spawns background revalidations that outlive the request.
Sourcepub fn webhook_targets(&self) -> Receiver<Arc<Vec<WebhookTarget>>>
pub fn webhook_targets(&self) -> Receiver<Arc<Vec<WebhookTarget>>>
A fresh receiver of the CURRENT webhook target set (DW-044);
updates on every refresh. Tests driving the deliverer directly
(without DataPlane::spawn_webhook_deliverer) use this.
Sourcepub fn spawn_webhook_deliverer(
self: &Arc<Self>,
shutdown: Receiver<()>,
) -> JoinHandle<()>
pub fn spawn_webhook_deliverer( self: &Arc<Self>, shutdown: Receiver<()>, ) -> JoinHandle<()>
Spawn the webhook deliverer (DW-044) against this dataplane’s bus,
target set, and metrics: one background task that drains the event
queue and POSTs matching events to the configured targets (see
events::webhook for the delivery contract). Exactly one
deliverer per dataplane: a second call logs and returns an
already-finished handle (the bus’s single-consumer receiver is
gone). The task stops on shutdown (or when the dataplane is
dropped and the bus closes).
Sourcepub fn quota_figures_at(
&self,
period_start_s: i64,
period_end_s: i64,
) -> HashMap<String, QuotaFigures>
pub fn quota_figures_at( &self, period_start_s: i64, period_end_s: i64, ) -> HashMap<String, QuotaFigures>
Per-consumer quota figures for one export window (DW-120): the
read side of the statement’s quota columns, assembled from the
CURRENT config generation’s quota blocks and the state store’s
quota_counters. A budget’s figures appear only when its UTC
quota window FULLY CONTAINS [period_start_s, period_end_s)
(see analytics::exports’ alignment rule): a daily export
carries the same-day daily counter and the month-to-date
monthly counter; a monthly export carries only the monthly
counter. Consumers without a quotas block, without a store, or
not yet synced into the store carry no figures — never
fabricated zeros.
Sourcepub fn spawn_export_worker(
self: &Arc<Self>,
shutdown: Receiver<()>,
) -> JoinHandle<()>
pub fn spawn_export_worker( self: &Arc<Self>, shutdown: Receiver<()>, ) -> JoinHandle<()>
Spawn the usage-report export worker (DW-120): one background
task on the same interval-plus-shutdown-watch machinery as the
analytics rollup cascade, reading the CURRENT config generation
each tick (a reload can add, change, or remove analytics. exports without a restart) and exporting every closed window
of the configured kind that has no successful run record —
oldest first, so a restart backfills missed windows. No-ops
without an analytics store or an exports block. Safe to abort:
each export is an atomic file write plus an idempotent record.
Sourcepub fn ai_budgets(&self) -> Arc<AiBudgetEngine>
pub fn ai_budgets(&self) -> Arc<AiBudgetEngine>
The AI budget engine (DW-078): current rules over the shared reload-surviving ledger.
Sourcepub fn ai_pricing(&self) -> Arc<PricingTable>
pub fn ai_pricing(&self) -> Arc<PricingTable>
The AI pricing table (DW-079): current per-model token rates.
Sourcepub fn ai_governance(&self) -> Arc<GovernanceEngine>
pub fn ai_governance(&self) -> Arc<GovernanceEngine>
The AI governance engine (DW-084): current per-team model allowlists and the audit switch.
Sourcepub fn ai_logging(&self) -> Option<Arc<AiLoggingEngine>>
pub fn ai_logging(&self) -> Option<Arc<AiLoggingEngine>>
The AI prompt/response logging engine (DW-081): current logging config (enabled, sampling, retention) and compiled redactor. None when logging is not configured (capture off, privacy-first).
Sourcepub fn ai_guardrails(&self) -> Arc<GuardrailEngine>
pub fn ai_guardrails(&self) -> Arc<GuardrailEngine>
The AI guardrail engine (DW-082): current compiled guardrail rules (prompt-injection, PII, banned-content, output schema enforcement). Empty when guardrails are not configured (every prompt and response passes through — fail-open).
Sourcepub fn ai_semantic_cache(&self) -> Option<Arc<SemanticCacheEngine>>
pub fn ai_semantic_cache(&self) -> Option<Arc<SemanticCacheEngine>>
The AI semantic cache engine (DW-083): the embedding-similarity cache. None when semantic caching is not configured or disabled. Persists across reloads (the HNSW index and cached entries survive config refreshes).
Sourcepub fn registry(&self) -> Arc<UpstreamRegistry>
pub fn registry(&self) -> Arc<UpstreamRegistry>
The current generation’s upstream registry. Used by the TLS-passthrough path (which picks endpoints through the same balancers) and by tests.
Sourcepub fn canary_controller(&self) -> Option<Arc<CanaryController>>
pub fn canary_controller(&self) -> Option<Arc<CanaryController>>
DW-091: the current generation’s auto-canary controller (None when no canary_analysis is configured). Used by the background runner and by tests.
Sourcepub fn ready(&self) -> bool
pub fn ready(&self) -> bool
Whether the gateway is READY to serve: at least one config
generation has been published successfully (generation >= 1). This
is the /readyz definition (DW-013). Upstream health deliberately
does NOT participate: a fully-ejected pool fail-opens rather than
blackholing (DW-012), so readiness tracks the gateway’s own state,
not its backends’.
Auto Trait Implementations§
impl !Freeze for DataPlane
impl !RefUnwindSafe for DataPlane
impl Send for DataPlane
impl Sync for DataPlane
impl Unpin for DataPlane
impl !UnwindSafe for DataPlane
Blanket Implementations§
§impl<T> AnyExt for T
impl<T> AnyExt for T
§fn downcast_ref<T>(this: &Self) -> Option<&T>where
T: Any,
fn downcast_ref<T>(this: &Self) -> Option<&T>where
T: Any,
T behind reference§fn downcast_mut<T>(this: &mut Self) -> Option<&mut T>where
T: Any,
fn downcast_mut<T>(this: &mut Self) -> Option<&mut T>where
T: Any,
T behind mutable reference§fn downcast_rc<T>(this: Rc<Self>) -> Result<Rc<T>, Rc<Self>>where
T: Any,
fn downcast_rc<T>(this: Rc<Self>) -> Result<Rc<T>, Rc<Self>>where
T: Any,
T behind Rc pointer§fn downcast_arc<T>(this: Arc<Self>) -> Result<Arc<T>, Arc<Self>>where
T: Any,
fn downcast_arc<T>(this: Arc<Self>) -> Result<Arc<T>, Arc<Self>>where
T: Any,
T behind Arc pointer§fn downcast_box<T>(this: Box<Self>) -> Result<Box<T>, Box<Self>>where
T: Any,
fn downcast_box<T>(this: Box<Self>) -> Result<Box<T>, Box<Self>>where
T: Any,
T behind Box pointer§fn downcast_move<T>(this: Self) -> Option<T>
fn downcast_move<T>(this: Self) -> Option<T>
Self to T,
useful only in generic context as a workaround for specializationSource§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T, X> CoerceTo<T> for Xwhere
T: CoerceFrom<X> + ?Sized,
impl<T, X> CoerceTo<T> for Xwhere
T: CoerceFrom<X> + ?Sized,
fn coerce_rc_to(self: Rc<X>) -> Rc<T>
fn coerce_box_to(self: Box<X>) -> Box<T>
fn coerce_ref_to(&self) -> &T
fn coerce_mut_to(&mut self) -> &mut T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
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