ServerConfigProvider

Struct ServerConfigProvider 

Source
pub struct ServerConfigProvider { /* private fields */ }
Expand description

Holds the current ServerConfig and refreshes it from an async stream.

Internally uses ArcSwap<ServerConfig> to provide lock-free, atomic swaps of the active TLS configuration. Call get_config to obtain an Arc<ServerConfig> for acceptors or handshakes.

Liveness of the underlying stream can be checked via stream_healthy.

§Concurrency

Reads get_config() are wait-free and do not block updates. Updates occur on a background task that listens to the user-provided stream.

§Backoff & Recovery

When the stream ends or errors, the provider:

  • Marks itself unhealthy,
  • Rebuilds the stream via the builder,
  • Retries with exponential backoff starting at 10ms and capping at 10s,
  • Resets backoff after a successful re-establishment.

§Examples

let config_stream_builder =
    SpiffeServerConfigStream::builder(vec!["example.org".try_into().unwrap()]);
let config_provider = ServerConfigProvider::start(config_stream_builder)
    .await
    .unwrap();
let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
    .await
    .unwrap();

loop {
    let (stream, _) = listener.accept().await.unwrap();

    let acceptor =
        tokio_rustls::LazyConfigAcceptor::new(rustls::server::Acceptor::default(), stream);
    tokio::pin!(acceptor);

    let config_provider = config_provider.clone();
    match acceptor.as_mut().await {
        Ok(start) => {
            tokio::spawn(async move {
                if !config_provider.stream_healthy() {
                    warn!(
                        "config provider does not have healthy stream; TLS config may be out of date"
                    );
                }
                let config = config_provider.get_config();
                match start.into_stream(config).await {
                    Ok(stream) => { /* serve some app (e.g. hyper, tower, axum) */ },
                    Err(err) => { /* handle error */ }
                }
            })
        }
        Err(_) => { /* handle error */ }
    }
}

Implementations§

Source§

impl ServerConfigProvider

Source

pub async fn start<B>(builder: B) -> Result<Arc<Self>, ServerConfigStreamError>
where B: ServerConfigStreamBuilder + Send + 'static,

Initializes the provider and spawn the background refresh task.

This awaits the first item from the builder’s stream to seed the internal configuration. It then spawns a task that continuously reads subsequent updates, atomically swapping them into place.

On stream failure or completion, the task attempts to rebuild the stream using exponential backoff (initial 10ms, max 10s, doubling).

Returns an Arc<ServerConfigProvider>

§Errors
Source

pub fn stream_healthy(&self) -> bool

Returns whether the stream is currently healthy.

This flag is set to false when the stream errors or ends, and set back to true after a successful rebuild.

Source

pub fn get_config(&self) -> Arc<ServerConfig>

Get the current ServerConfig.

This is a cheap, lock-free read that loads the internal ArcSwap<ServerConfig> into an Arc<ServerConfig> Callers can hold onto the returned Arc<ServerConfig> as long as needed; updates will affect future calls, not the already-held value.

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> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

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, 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<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