use std::collections::BTreeMap;
use super::messages::{
SbpRequest, SbpResponse, SbpStatus, SensingMeasurementSetupRequest,
SensingMeasurementSetupResponse,
};
use super::session::{Action, SensingSession, SessionConfig, SessionEvent, SessionState};
use super::types::{BfError, MeasurementSetupId, SetupStatus};
#[derive(Debug)]
pub struct SessionTable {
config: SessionConfig,
sessions: BTreeMap<u8, SensingSession>,
unknown_setup_drops: u64,
}
impl SessionTable {
pub fn new(config: SessionConfig) -> Self {
Self {
config,
sessions: BTreeMap::new(),
unknown_setup_drops: 0,
}
}
pub fn active_setups(&self) -> usize {
self.sessions
.values()
.filter(|s| s.state() != SessionState::Idle)
.count()
}
pub fn session(&self, setup_id: MeasurementSetupId) -> Option<&SensingSession> {
self.sessions.get(&setup_id.value())
}
pub fn unknown_setup_drops(&self) -> u64 {
self.unknown_setup_drops
}
pub fn handle_setup_request(
&mut self,
req: SensingMeasurementSetupRequest,
) -> Result<Vec<Action>, BfError> {
let reject = |setup_id, status| {
Ok(vec![Action::SendSetupResponse(
SensingMeasurementSetupResponse { setup_id, status },
)])
};
if self.is_collision(req.setup_id) {
return reject(req.setup_id, SetupStatus::RejectedSetupIdCollision);
}
if self.at_capacity() {
return reject(req.setup_id, SetupStatus::RejectedCapacity);
}
let key = req.setup_id.value();
let mut session = SensingSession::new_responder(self.config.clone());
let actions = session.handle(SessionEvent::SetupRequestReceived(req))?;
self.sessions.insert(key, session);
Ok(actions)
}
pub fn handle_sbp_request(&mut self, sbp: SbpRequest) -> Result<Vec<Action>, BfError> {
let reject = |proxy_setup_id, status| {
Ok(vec![Action::SendSbpResponse(SbpResponse {
proxy_setup_id,
status,
})])
};
if self.is_collision(sbp.proxy_setup_id) {
return reject(sbp.proxy_setup_id, SbpStatus::RejectedSetupIdCollision);
}
if self.at_capacity() {
return reject(sbp.proxy_setup_id, SbpStatus::RejectedCapacity);
}
let key = sbp.proxy_setup_id.value();
let mut session = SensingSession::new_responder(self.config.clone());
let actions = session.handle(SessionEvent::SbpRequestReceived(sbp))?;
self.sessions.insert(key, session);
Ok(actions)
}
pub fn handle_for(
&mut self,
setup_id: MeasurementSetupId,
event: SessionEvent,
) -> Result<Vec<Action>, BfError> {
match self.sessions.get_mut(&setup_id.value()) {
Some(session) => session.handle(event),
None => {
self.unknown_setup_drops = self.unknown_setup_drops.saturating_add(1);
Ok(vec![])
}
}
}
fn is_collision(&self, setup_id: MeasurementSetupId) -> bool {
self.sessions
.get(&setup_id.value())
.is_some_and(|existing| existing.state() != SessionState::Idle)
}
fn at_capacity(&self) -> bool {
self.active_setups() >= self.config.capabilities.max_active_setups as usize
}
}