use liminal::channel::ChannelMode;
use liminal::protocol::SchemaId as ProtocolSchemaId;
use liminal_protocol::reason_code::{CHANNEL_NOT_REGISTERED_CODE, CHANNEL_QUIESCED_CODE};
#[cfg(test)]
#[path = "channel_registry_tests.rs"]
mod channel_registry_tests;
const SERVER_ERROR_CODE: u16 = 0xFFFF;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ChannelRegistration {
pub name: String,
pub schema_bytes: Option<Vec<u8>>,
pub durable: bool,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Registered {
Created,
AlreadyIdentical,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ChannelOrigin {
BootConfigured,
RuntimeRegistered,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ChannelState {
Active,
Quiesced {
reason: String,
},
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ChannelStatus {
NotRegistered,
Active {
origin: ChannelOrigin,
mode: ChannelMode,
schema: ProtocolSchemaId,
},
Quiesced {
reason: String,
origin: ChannelOrigin,
mode: ChannelMode,
},
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ChannelDescriptor {
pub name: String,
pub origin: ChannelOrigin,
pub state: ChannelState,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ChannelConfigField {
Mode,
SchemaId,
SchemaDocument,
}
impl std::fmt::Display for ChannelConfigField {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Mode => formatter.write_str("mode"),
Self::SchemaId => formatter.write_str("schema id"),
Self::SchemaDocument => formatter.write_str("schema document"),
}
}
}
pub const MAX_CHANNELS_KEY: &str = "limits.max_channels";
#[derive(Debug, thiserror::Error)]
pub enum ChannelRegistryError {
#[error("channel '{name}' is already registered with a different {field}")]
AlreadyRegistered {
name: String,
field: ChannelConfigField,
},
#[error("channel '{name}' is not registered")]
NotRegistered {
name: String,
},
#[error("channel '{name}' is already quiesced: {reason}")]
AlreadyQuiesced {
name: String,
reason: String,
},
#[error("channel '{name}' schema rejected: {message}")]
SchemaRejected {
name: String,
message: String,
},
#[error("durable channel '{name}' could not be initialized: {message}")]
DurableInitFailed {
name: String,
message: String,
},
#[error(
"runtime channel registration refused: no {cap} is configured; \
a deployment that registers channels at runtime must declare its bound"
)]
CapNotConfigured {
cap: &'static str,
},
#[error("channel registration refused: the {cap} limit of {limit} is reached")]
CapReached {
cap: &'static str,
limit: usize,
},
#[error("channel roster unavailable: {message}")]
RosterUnavailable {
message: String,
},
}
#[derive(Debug, thiserror::Error)]
pub enum ChannelAccessError {
#[error("channel '{name}' is not registered")]
NotRegistered {
name: String,
},
#[error("channel '{name}' is quiesced: {reason}")]
Quiesced {
name: String,
reason: String,
},
#[error("channel roster unavailable: {message}")]
RosterUnavailable {
message: String,
},
}
impl ChannelAccessError {
#[must_use]
pub const fn reason_code(&self) -> u16 {
match self {
Self::NotRegistered { .. } => CHANNEL_NOT_REGISTERED_CODE,
Self::Quiesced { .. } => CHANNEL_QUIESCED_CODE,
Self::RosterUnavailable { .. } => SERVER_ERROR_CODE,
}
}
}
#[derive(Debug)]
pub(super) enum ChannelBuildError {
SchemaRejected {
message: String,
},
DurableInitFailed {
message: String,
},
}
impl ChannelBuildError {
pub(super) fn boot_message(&self, name: &str) -> String {
match self {
Self::SchemaRejected { message } => {
format!("failed to initialize channel '{name}': {message}")
}
Self::DurableInitFailed { message } => {
format!("failed to initialize durable channel '{name}': {message}")
}
}
}
pub(super) fn into_registry_error(self, name: &str) -> ChannelRegistryError {
match self {
Self::SchemaRejected { message } => ChannelRegistryError::SchemaRejected {
name: name.to_owned(),
message,
},
Self::DurableInitFailed { message } => ChannelRegistryError::DurableInitFailed {
name: name.to_owned(),
message,
},
}
}
}
pub(super) const STATE_ACTIVE: u8 = 0;
pub(super) const STATE_QUIESCED: u8 = 1;
pub(super) const UNRECORDED_QUIESCE_REASON: &str = "quiesce reason unrecorded (ordering violated)";