agave-event-system 0.3.1

A local pub-sub system used by agave validators to publish events to outside processes.
Documentation
use {
    crate::{
        Event, PublisherFactory,
        backend::{self},
        stream_name::StreamName,
        stream_policy::StreamPolicy,
    },
    std::path::Path,
    thiserror::Error,
};

/// Owns an event-system directory and creates typed event streams within it.
#[derive(Clone)]
pub struct EventSystem {
    backend: Backend,
}

#[derive(Clone)]
enum Backend {
    Platform(backend::EventSystem),
    Stub(backend::stub::EventSystem),
}

impl EventSystem {
    /// Creates an event system directory in the given path, `event_system_directory`.
    ///
    /// ### Note:
    /// - If the directory path already exists, it must be empty.
    /// - This functions creates the given directory and any missing parents.
    /// - The given path is canonicalized.
    /// - The directory is emptied once this [`EventSystem`], its clones, and
    ///   all of its streams (including their [`PublisherFactory`]s and
    ///   publishers) are dropped. The directory itself is left in place, and
    ///   can be reused by a later call to [`EventSystem::new`].
    pub fn new(event_system_directory: impl AsRef<Path>) -> Result<Self, CreateEventSystemError> {
        Ok(Self {
            backend: Backend::Platform(backend::EventSystem::new(event_system_directory)?),
        })
    }

    /// Creates a no-op event system on any platform, including Linux.
    ///
    /// No filesystem access is performed. Streams ignore their configuration
    /// and policy, and their factories always return publishers that discard
    /// events without serializing them.
    pub fn stub() -> Self {
        Self {
            backend: Backend::Stub(backend::stub::EventSystem),
        }
    }

    /// Creates a stream named `stream_name` for event type `E`
    /// and returns its [`PublisherFactory`].
    pub fn create_stream<E: Event>(
        &self,
        stream_name: StreamName,
        stream_config: StreamConfig,
    ) -> Result<PublisherFactory<E>, CreateStreamError> {
        match &self.backend {
            Backend::Platform(backend) => backend
                .create_stream::<E>(stream_name, stream_config)
                .map(PublisherFactory::new),
            Backend::Stub(backend) => backend
                .create_stream::<E>(stream_name, stream_config)
                .map(PublisherFactory::stub),
        }
    }

    /// Applies the given [`StreamPolicy`] on the streams created by this
    /// [`EventSystem`].
    ///
    /// The applied stream policy will also be applied to future stream creations
    /// of this event system.
    pub fn set_stream_policy(&self, stream_policy: StreamPolicy) {
        match &self.backend {
            Backend::Platform(backend) => backend.set_stream_policy(stream_policy),
            Backend::Stub(backend) => backend.set_stream_policy(stream_policy),
        }
    }
}

impl std::fmt::Debug for EventSystem {
    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match &self.backend {
            Backend::Platform(backend) => backend.fmt(formatter),
            Backend::Stub(backend) => backend.fmt(formatter),
        }
    }
}

/// Capacity and participant limits for an event stream.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct StreamConfig {
    /// Number of events retained in each lane.
    pub capacity: usize,
    /// Maximum number of concurrent publishers that can be created for the stream.
    pub publisher_slots: usize,
    /// Maximum number of concurrent subscribers.
    pub subscriber_slots: usize,
}

#[derive(Debug, Error)]
#[error("failed to create the event-system directory")]
pub struct CreateEventSystemError(#[from] std::io::Error);

/// An error reported by the platform event-queue implementation.
#[derive(Debug, Error)]
#[error("{0}")]
pub struct EventQueueError(#[source] pub(crate) backend::EventQueueError);

#[derive(Debug, Error)]
pub enum CreateStreamError {
    #[error("failed to serialize the event-stream schema")]
    FailedToSerializeSchema(#[source] wincode::WriteError),
    #[error("failed to create the event-stream files")]
    FileSystem(#[from] std::io::Error),
    #[error("the stream name is already in use")]
    StreamNameAlreadyInUse,
    #[error("failed to create the event-stream queue")]
    Queue(#[source] EventQueueError),
    #[error("failed to produce a random number for the queue identifier")]
    OsRngFailure(std::io::Error),
}