use super::service_info::Subscriber;
use std::{collections::HashMap, net::SocketAddrV4, vec::Vec};
#[derive(Debug)]
pub struct SubscriptionManager {
subscriptions: HashMap<(u16, u16, u16), Vec<Subscriber>>,
}
impl SubscriptionManager {
#[must_use]
pub fn new() -> Self {
Self {
subscriptions: HashMap::new(),
}
}
pub fn subscribe(
&mut self,
service_id: u16,
instance_id: u16,
event_group_id: u16,
subscriber_addr: SocketAddrV4,
) {
let key = (service_id, instance_id, event_group_id);
let subscribers = self.subscriptions.entry(key).or_default();
if subscribers.iter().any(|s| s.address == subscriber_addr) {
tracing::debug!(
"Refreshed existing subscriber {} for service 0x{:04X}, instance {}, event group 0x{:04X}",
subscriber_addr,
service_id,
instance_id,
event_group_id
);
return;
}
let subscriber = Subscriber::new(subscriber_addr, service_id, instance_id, event_group_id);
subscribers.push(subscriber);
tracing::info!(
"Subscriber {} added for service 0x{:04X}, instance {}, event group 0x{:04X}",
subscriber_addr,
service_id,
instance_id,
event_group_id
);
}
pub fn unsubscribe(
&mut self,
service_id: u16,
instance_id: u16,
event_group_id: u16,
subscriber_addr: SocketAddrV4,
) {
let key = (service_id, instance_id, event_group_id);
if let Some(subscribers) = self.subscriptions.get_mut(&key) {
subscribers.retain(|s| s.address != subscriber_addr);
if subscribers.is_empty() {
self.subscriptions.remove(&key);
}
tracing::info!(
"Removed subscriber {} from service 0x{:04X}, instance {}, event group 0x{:04X}",
subscriber_addr,
service_id,
instance_id,
event_group_id
);
}
}
#[must_use]
pub fn get_subscribers(
&self,
service_id: u16,
instance_id: u16,
event_group_id: u16,
) -> Vec<Subscriber> {
let key = (service_id, instance_id, event_group_id);
self.subscriptions.get(&key).cloned().unwrap_or_default()
}
#[must_use]
pub fn subscription_count(&self) -> usize {
self.subscriptions.values().map(std::vec::Vec::len).sum()
}
}
impl Default for SubscriptionManager {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::net::Ipv4Addr;
#[test]
fn test_subscription_management() {
let mut manager = SubscriptionManager::new();
let addr = SocketAddrV4::new(Ipv4Addr::new(192, 168, 1, 1), 8080);
manager.subscribe(0x5B, 1, 0x01, addr);
assert_eq!(manager.subscription_count(), 1);
let subscribers = manager.get_subscribers(0x5B, 1, 0x01);
assert_eq!(subscribers.len(), 1);
assert_eq!(subscribers[0].address, addr);
manager.unsubscribe(0x5B, 1, 0x01, addr);
assert_eq!(manager.subscription_count(), 0);
}
#[test]
fn test_duplicate_subscriber_refresh() {
let mut manager = SubscriptionManager::new();
let addr = SocketAddrV4::new(Ipv4Addr::new(192, 168, 1, 1), 8080);
manager.subscribe(0x5B, 1, 0x01, addr);
assert_eq!(manager.subscription_count(), 1);
manager.subscribe(0x5B, 1, 0x01, addr);
assert_eq!(manager.subscription_count(), 1);
}
#[test]
fn test_unsubscribe_nonexistent_key() {
let mut manager = SubscriptionManager::new();
let addr = SocketAddrV4::new(Ipv4Addr::new(10, 0, 0, 1), 9000);
manager.unsubscribe(0x99, 1, 0x01, addr);
assert_eq!(manager.subscription_count(), 0);
}
#[test]
fn test_get_subscribers_empty() {
let manager = SubscriptionManager::new();
assert!(manager.get_subscribers(0x99, 1, 0x01).is_empty());
}
#[test]
fn test_default_impl() {
let manager = SubscriptionManager::default();
assert_eq!(manager.subscription_count(), 0);
}
}