Skip to main content

simple_someip/server/
subscription_manager.rs

1//! Manages event group subscriptions
2
3use super::service_info::Subscriber;
4use std::collections::HashMap;
5use std::net::SocketAddrV4;
6
7/// Manages subscriptions to event groups
8#[derive(Debug)]
9pub struct SubscriptionManager {
10    /// Map of (`service_id`, `instance_id`, `event_group_id`) -> list of subscribers
11    subscriptions: HashMap<(u16, u16, u16), Vec<Subscriber>>,
12}
13
14impl SubscriptionManager {
15    /// Create a new subscription manager
16    #[must_use]
17    pub fn new() -> Self {
18        Self {
19            subscriptions: HashMap::new(),
20        }
21    }
22
23    /// Add a subscriber to an event group
24    pub fn subscribe(
25        &mut self,
26        service_id: u16,
27        instance_id: u16,
28        event_group_id: u16,
29        subscriber_addr: SocketAddrV4,
30    ) {
31        let key = (service_id, instance_id, event_group_id);
32        let subscribers = self.subscriptions.entry(key).or_default();
33
34        // Deduplicate: if this address is already subscribed, just refresh (don't add again)
35        if subscribers.iter().any(|s| s.address == subscriber_addr) {
36            tracing::debug!(
37                "Refreshed existing subscriber {} for service 0x{:04X}, instance {}, event group 0x{:04X}",
38                subscriber_addr,
39                service_id,
40                instance_id,
41                event_group_id
42            );
43            return;
44        }
45
46        let subscriber = Subscriber::new(subscriber_addr, service_id, instance_id, event_group_id);
47        subscribers.push(subscriber);
48
49        tracing::info!(
50            "Subscriber {} added for service 0x{:04X}, instance {}, event group 0x{:04X}",
51            subscriber_addr,
52            service_id,
53            instance_id,
54            event_group_id
55        );
56    }
57
58    /// Remove a subscriber from an event group
59    pub fn unsubscribe(
60        &mut self,
61        service_id: u16,
62        instance_id: u16,
63        event_group_id: u16,
64        subscriber_addr: SocketAddrV4,
65    ) {
66        let key = (service_id, instance_id, event_group_id);
67
68        if let Some(subscribers) = self.subscriptions.get_mut(&key) {
69            subscribers.retain(|s| s.address != subscriber_addr);
70
71            if subscribers.is_empty() {
72                self.subscriptions.remove(&key);
73            }
74
75            tracing::info!(
76                "Removed subscriber {} from service 0x{:04X}, instance {}, event group 0x{:04X}",
77                subscriber_addr,
78                service_id,
79                instance_id,
80                event_group_id
81            );
82        }
83    }
84
85    /// Get all subscribers for an event group
86    #[must_use]
87    pub fn get_subscribers(
88        &self,
89        service_id: u16,
90        instance_id: u16,
91        event_group_id: u16,
92    ) -> Vec<Subscriber> {
93        let key = (service_id, instance_id, event_group_id);
94        self.subscriptions.get(&key).cloned().unwrap_or_default()
95    }
96
97    /// Get total number of active subscriptions
98    #[must_use]
99    pub fn subscription_count(&self) -> usize {
100        self.subscriptions.values().map(std::vec::Vec::len).sum()
101    }
102}
103
104impl Default for SubscriptionManager {
105    fn default() -> Self {
106        Self::new()
107    }
108}
109
110#[cfg(test)]
111mod tests {
112    use super::*;
113    use std::net::Ipv4Addr;
114
115    #[test]
116    fn test_subscription_management() {
117        let mut manager = SubscriptionManager::new();
118        let addr = SocketAddrV4::new(Ipv4Addr::new(192, 168, 1, 1), 8080);
119
120        // Subscribe
121        manager.subscribe(0x5B, 1, 0x01, addr);
122        assert_eq!(manager.subscription_count(), 1);
123
124        // Get subscribers
125        let subscribers = manager.get_subscribers(0x5B, 1, 0x01);
126        assert_eq!(subscribers.len(), 1);
127        assert_eq!(subscribers[0].address, addr);
128
129        // Unsubscribe
130        manager.unsubscribe(0x5B, 1, 0x01, addr);
131        assert_eq!(manager.subscription_count(), 0);
132    }
133}