use crate::ids::{ActorId, DepartmentId, TenantId};
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ActorCapabilities {
capabilities: Vec<String>,
}
impl ActorCapabilities {
pub fn new(capabilities: Vec<String>) -> Result<Self, String> {
if capabilities.is_empty() {
return Err("actor must declare at least one capability".to_string());
}
for cap in &capabilities {
if cap.is_empty() {
return Err("capability string must be non-empty".to_string());
}
}
Ok(ActorCapabilities { capabilities })
}
pub fn as_slice(&self) -> &[String] {
&self.capabilities
}
pub fn satisfies(&self, required: &[String]) -> bool {
required.iter().all(|r| self.capabilities.iter().any(|c| c == r))
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ActorRegistration {
actor_id: ActorId,
identity: String,
capabilities: ActorCapabilities,
department: Option<DepartmentId>,
heartbeat_interval_secs: u64,
tenant_id: Option<TenantId>,
}
impl ActorRegistration {
pub fn new(
actor_id: ActorId,
identity: impl Into<String>,
capabilities: ActorCapabilities,
heartbeat_interval_secs: u64,
) -> Self {
let identity = identity.into();
assert!(!identity.is_empty(), "actor identity must be non-empty");
assert!(heartbeat_interval_secs > 0, "heartbeat_interval_secs must be > 0");
ActorRegistration {
actor_id,
identity,
capabilities,
department: None,
heartbeat_interval_secs,
tenant_id: None,
}
}
pub fn with_department(mut self, department: DepartmentId) -> Self {
self.department = Some(department);
self
}
pub fn with_tenant(mut self, tenant_id: TenantId) -> Self {
self.tenant_id = Some(tenant_id);
self
}
pub fn actor_id(&self) -> ActorId {
self.actor_id
}
pub fn identity(&self) -> &str {
&self.identity
}
pub fn capabilities(&self) -> &ActorCapabilities {
&self.capabilities
}
pub fn department(&self) -> Option<&DepartmentId> {
self.department.as_ref()
}
pub fn heartbeat_interval_secs(&self) -> u64 {
self.heartbeat_interval_secs
}
pub fn tenant_id(&self) -> Option<TenantId> {
self.tenant_id
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct HeartbeatPolicy {
interval_secs: u64,
timeout_multiplier: u32,
}
impl HeartbeatPolicy {
pub const DEFAULT_MULTIPLIER: u32 = 3;
pub fn new(interval_secs: u64, timeout_multiplier: u32) -> Self {
assert!(interval_secs > 0, "heartbeat interval_secs must be > 0");
assert!(timeout_multiplier > 0, "timeout_multiplier must be > 0");
HeartbeatPolicy { interval_secs, timeout_multiplier }
}
pub fn with_default_multiplier(interval_secs: u64) -> Self {
Self::new(interval_secs, Self::DEFAULT_MULTIPLIER)
}
pub fn interval_secs(&self) -> u64 {
self.interval_secs
}
pub fn timeout_multiplier(&self) -> u32 {
self.timeout_multiplier
}
pub fn timeout_secs(&self) -> u64 {
self.interval_secs.saturating_mul(self.timeout_multiplier as u64)
}
}
impl Default for HeartbeatPolicy {
fn default() -> Self {
Self::new(30, Self::DEFAULT_MULTIPLIER)
}
}