use std::net::SocketAddr;
use std::path::PathBuf;
use std::time::Duration;
use crate::ServerError;
#[derive(Debug, Clone, serde::Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ServerConfig {
pub listen_address: SocketAddr,
#[serde(default)]
pub extra_listen_addresses: Vec<SocketAddr>,
pub health_listen_address: SocketAddr,
pub drain_timeout_ms: u64,
pub channels: Vec<ChannelDef>,
pub routing_rules: Vec<RoutingRuleDef>,
pub persistence_path: Option<PathBuf>,
pub cluster: Option<ClusterConfig>,
#[serde(default)]
pub auth: Option<AuthConfig>,
#[serde(default)]
pub services: ServicesConfig,
#[serde(default)]
pub limits: LimitsConfig,
#[serde(default)]
pub websocket: Option<WebSocketConfig>,
#[serde(default)]
pub participant: Option<ParticipantConfig>,
}
impl ServerConfig {
#[must_use]
pub const fn drain_timeout(&self) -> Duration {
Duration::from_millis(self.drain_timeout_ms)
}
}
#[derive(Debug, Clone, serde::Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ChannelDef {
pub name: String,
#[serde(default)]
pub schema_ref: Option<PathBuf>,
pub durable: bool,
#[serde(skip)]
pub loaded_schema: Option<LoadedSchema>,
}
#[derive(Debug, Clone)]
pub struct LoadedSchema {
pub bytes: Vec<u8>,
pub document: serde_json::Value,
}
#[derive(Debug, Clone, serde::Deserialize)]
#[serde(deny_unknown_fields)]
pub struct RoutingRuleDef {
pub source_channel: String,
pub target_channel: String,
pub predicate: Option<String>,
}
pub const DEFAULT_COOKIE: &str = "beamr-cookie";
#[derive(Debug, Clone, serde::Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ClusterConfig {
pub node_name: String,
pub listen_address: SocketAddr,
pub seed_nodes: Vec<SocketAddr>,
pub cookie: String,
}
#[derive(Clone, serde::Deserialize)]
#[serde(deny_unknown_fields)]
pub struct AuthConfig {
pub token: String,
#[serde(default)]
pub pass: Option<PassConfig>,
#[serde(default)]
pub lys: Option<LysConfig>,
#[serde(default)]
pub require_verified_worker: bool,
}
impl std::fmt::Debug for AuthConfig {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter
.debug_struct("AuthConfig")
.field("token", &crate::auth_pass::ByteLength(self.token.len()))
.field("pass", &self.pass)
.field("lys", &self.lys)
.field("require_verified_worker", &self.require_verified_worker)
.finish()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum AccessMode {
Open,
Gated,
}
impl std::fmt::Display for AccessMode {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter.write_str(match self {
Self::Open => "open",
Self::Gated => "gated",
})
}
}
impl ServerConfig {
#[must_use]
pub const fn access_mode(&self) -> AccessMode {
if self.auth.is_some() {
AccessMode::Gated
} else {
AccessMode::Open
}
}
}
#[derive(Debug, Clone, serde::Deserialize)]
#[serde(deny_unknown_fields)]
pub struct PassConfig {
pub registry_verifying_key: String,
pub maximum_clock_skew_seconds: u64,
}
#[derive(Debug, Clone, serde::Deserialize)]
#[serde(deny_unknown_fields)]
pub struct WebSocketConfig {
pub listen_address: SocketAddr,
pub path: String,
#[serde(default)]
pub allowed_origins: Vec<String>,
#[serde(default)]
pub allowed_origin_ports: Vec<u16>,
#[serde(default)]
pub ping_interval_ms: Option<u64>,
}
#[derive(Debug, Clone, serde::Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ServicesConfig {
#[serde(default = "default_service_profile")]
pub profile: String,
#[serde(default)]
pub self_streams: SelfStreamsConfig,
}
#[derive(Debug, Clone, Copy, serde::Deserialize)]
#[serde(deny_unknown_fields)]
pub struct SelfStreamsConfig {
#[serde(default = "default_cost_rows")]
pub cost_rows: u64,
#[serde(default = "default_events_rows")]
pub events_rows: u64,
}
impl Default for SelfStreamsConfig {
fn default() -> Self {
Self {
cost_rows: default_cost_rows(),
events_rows: default_events_rows(),
}
}
}
const fn default_cost_rows() -> u64 {
10_000
}
const fn default_events_rows() -> u64 {
100_000
}
impl Default for ServicesConfig {
fn default() -> Self {
Self {
profile: default_service_profile(),
self_streams: SelfStreamsConfig::default(),
}
}
}
impl ServicesConfig {
pub fn profile(&self) -> Result<ServiceProfile, ServerError> {
ServiceProfile::parse(&self.profile)
}
}
fn default_service_profile() -> String {
ServiceProfile::FULL.to_owned()
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ServiceProfile {
Full,
WorkerFrontDoor,
}
impl ServiceProfile {
pub const FULL: &'static str = "full";
pub const WORKER_FRONT_DOOR: &'static str = "worker-front-door";
pub fn parse(value: &str) -> Result<Self, ServerError> {
match value {
Self::FULL => Ok(Self::Full),
Self::WORKER_FRONT_DOOR => Ok(Self::WorkerFrontDoor),
other => Err(ServerError::ConfigValidation {
message: format!(
"services.profile: unknown profile '{other}'; expected \"{}\" or \"{}\"",
Self::FULL,
Self::WORKER_FRONT_DOOR
),
}),
}
}
}
mod limits;
mod lys;
mod participant;
pub use crate::auth_membership::grant_stream::GrantStreamConfig;
pub use limits::LimitsConfig;
pub use lys::*;
pub use participant::{ParticipantConfig, PruningConfig};