use crate::config::PresenceConfig as PresenceFabricConfig;
use crate::types::*;
use dashmap::DashMap;
use std::time::{Duration, Instant};
pub struct PresenceFabric {
states: DashMap<ResonatorId, PresenceStateWithMetadata>,
config: PresenceFabricConfig,
}
struct PresenceStateWithMetadata {
state: PresenceState,
last_update: Instant,
}
impl PresenceFabric {
fn initial_last_update(min_signal_interval_ms: u64) -> Instant {
Instant::now()
.checked_sub(Duration::from_millis(min_signal_interval_ms))
.unwrap_or_else(Instant::now)
}
pub fn new(config: &PresenceFabricConfig) -> Self {
Self {
states: DashMap::new(),
config: config.clone(),
}
}
pub async fn initialize_presence(
&self,
resonator: &ResonatorId,
config: &PresenceConfig,
) -> Result<(), String> {
let mut state = PresenceState::new();
state.discoverability = config.initial_discoverability;
state.responsiveness = config.initial_responsiveness;
state.silent_mode = config.start_silent;
let metadata = PresenceStateWithMetadata {
state,
last_update: Self::initial_last_update(self.config.min_signal_interval_ms),
};
self.states.insert(*resonator, metadata);
tracing::debug!("Initialized presence for {}", resonator);
Ok(())
}
pub async fn signal_presence(
&self,
resonator: ResonatorId,
state: PresenceState,
) -> Result<(), PresenceError> {
if let Some(existing) = self.states.get(&resonator) {
let elapsed = existing.last_update.elapsed();
let min_interval = std::time::Duration::from_millis(self.config.min_signal_interval_ms);
if elapsed < min_interval {
return Err(PresenceError::RateLimitExceeded);
}
}
let metadata = PresenceStateWithMetadata {
state,
last_update: Instant::now(),
};
self.states.insert(resonator, metadata);
Ok(())
}
pub async fn enable_silent_presence(&self, resonator: ResonatorId) {
if let Some(mut entry) = self.states.get_mut(&resonator) {
entry.state.silent_mode = true;
entry.state.discoverability = 0.1; }
}
pub async fn disable_silent_presence(&self, resonator: ResonatorId) {
if let Some(mut entry) = self.states.get_mut(&resonator) {
entry.state.silent_mode = false;
entry.state.discoverability = 0.5; }
}
pub fn get_presence(&self, resonator: &ResonatorId) -> Option<PresenceState> {
self.states.get(resonator).map(|r| r.state.clone())
}
pub fn is_present(&self, resonator: &ResonatorId) -> bool {
self.states.contains_key(resonator)
}
pub async fn update_presence_gradient(
&self,
resonator: &ResonatorId,
adjustment: PresenceAdjustment,
) {
if let Some(mut entry) = self.states.get_mut(resonator) {
match adjustment {
PresenceAdjustment::IncreaseResponsiveness(delta) => {
entry.state.responsiveness = (entry.state.responsiveness + delta).min(1.0);
}
PresenceAdjustment::DecreaseResponsiveness(delta) => {
entry.state.responsiveness = (entry.state.responsiveness - delta).max(0.0);
}
PresenceAdjustment::IncreaseStability(delta) => {
entry.state.stability = (entry.state.stability + delta).min(1.0);
}
PresenceAdjustment::DecreaseStability(delta) => {
entry.state.stability = (entry.state.stability - delta).max(0.0);
}
PresenceAdjustment::SetCouplingReadiness(value) => {
entry.state.coupling_readiness = value.clamp(0.0, 1.0);
}
}
}
}
pub async fn restore_presence(
&self,
resonator: &ResonatorId,
state: &PresenceState,
) -> Result<(), String> {
let metadata = PresenceStateWithMetadata {
state: state.clone(),
last_update: Self::initial_last_update(self.config.min_signal_interval_ms),
};
self.states.insert(*resonator, metadata);
tracing::debug!("Restored presence for {}", resonator);
Ok(())
}
pub fn remove_presence(&self, resonator: &ResonatorId) {
self.states.remove(resonator);
}
pub fn get_all_present(&self) -> Vec<ResonatorId> {
self.states.iter().map(|entry| *entry.key()).collect()
}
pub fn count(&self) -> usize {
self.states.len()
}
}
pub enum PresenceAdjustment {
IncreaseResponsiveness(f64),
DecreaseResponsiveness(f64),
IncreaseStability(f64),
DecreaseStability(f64),
SetCouplingReadiness(f64),
}