Skip to main content

featherbit/plugins/
resources.rs

1//! Process-wide services shared by every plugin instance.
2//!
3//! `SharedState` owns one [`PluginResources`] for the process lifetime and
4//! threads it through `compile_policy` → `create_plugin` → each plugin's
5//! `from_config`, so plugins can hold handles to shared infrastructure
6//! (metrics registry, outbound HTTP client, consumer store, rate-limit
7//! counter backends) instead of constructing their own per node or — worse —
8//! per request.
9
10use std::sync::Arc;
11
12use arc_swap::ArcSwap;
13
14use crate::consumers::ConsumerStore;
15use crate::metrics::GatewayMetrics;
16use crate::outbound::OutboundClient;
17use crate::ratelimit::CounterStoreRegistry;
18use crate::traffic::TrafficRegistries;
19
20/// Handle to process-wide services, injected into plugins at construction.
21///
22/// Grows as shared infrastructure lands (counter backends); every field must
23/// be cheap to clone or shared behind its own `Arc`.
24pub struct PluginResources {
25    /// Shared Prometheus registry; `None` disables recording (unit tests).
26    pub metrics: Option<Arc<GatewayMetrics>>,
27    /// Pooled outbound HTTP client for upstream proxying and plugin callouts.
28    pub outbound: Arc<OutboundClient>,
29    /// Consumer store, swapped atomically on config reload so lookups on the
30    /// request path are lock-free. Plugins should `load()` per request, not
31    /// cache the inner Arc across requests.
32    pub consumers: ArcSwap<ConsumerStore>,
33    /// Rate-limit counter backends, resolved by `policy` name at config load.
34    pub counters: CounterStoreRegistry,
35    /// Shared state for traffic-control node pairs (concurrency, breakers, cache).
36    pub traffic: TrafficRegistries,
37}
38
39impl PluginResources {
40    /// Creates the process-wide resources handle with an empty consumer
41    /// store; callers swap in the real store via [`PluginResources::consumers`].
42    pub fn new(metrics: Option<Arc<GatewayMetrics>>) -> Arc<Self> {
43        Arc::new(Self {
44            metrics,
45            outbound: Arc::new(OutboundClient::new()),
46            consumers: ArcSwap::from_pointee(ConsumerStore::default()),
47            counters: CounterStoreRegistry::default(),
48            traffic: TrafficRegistries::default(),
49        })
50    }
51
52    /// Resources with optional services disabled — for unit tests.
53    #[cfg(test)]
54    pub fn empty() -> Arc<Self> {
55        Self::new(None)
56    }
57}