net_lattice_platform/event_provider.rs
1use std::sync::{Arc, Mutex, mpsc};
2use std::time::Duration;
3
4use net_lattice_core::{Error, Result};
5
6/// Default number of ordinary events buffered for one synchronous watcher.
7pub const DEFAULT_EVENT_QUEUE_CAPACITY: usize = 256;
8
9/// Non-blocking backend producer for a bounded event receiver.
10#[derive(Clone)]
11pub struct EventSender<E> {
12 sender: mpsc::SyncSender<Result<E>>,
13 pending_resync: Arc<Mutex<Option<E>>>,
14}
15
16impl<E> EventSender<E> {
17 /// Never blocks a native callback. On overflow, records one resync event
18 /// that is delivered before a later ordinary event.
19 pub fn send(&self, event: E, resync: E) -> bool {
20 let mut pending = self.pending_resync.lock().expect("event sender poisoned");
21 if let Some(resync) = pending.take() {
22 match self.sender.try_send(Ok(resync)) {
23 Ok(()) => {}
24 Err(mpsc::TrySendError::Full(Ok(resync))) => {
25 *pending = Some(resync);
26 return true;
27 }
28 Err(mpsc::TrySendError::Disconnected(_)) => return false,
29 Err(mpsc::TrySendError::Full(Err(_))) => unreachable!(),
30 }
31 }
32 match self.sender.try_send(Ok(event)) {
33 Ok(()) => true,
34 Err(mpsc::TrySendError::Full(Ok(_))) => {
35 *pending = Some(resync);
36 true
37 }
38 Err(mpsc::TrySendError::Disconnected(_)) => false,
39 Err(mpsc::TrySendError::Full(Err(_))) => unreachable!(),
40 }
41 }
42 pub fn send_error(&self, error: Error) -> bool {
43 self.sender.send(Err(error)).is_ok()
44 }
45}
46
47/// A bounded synchronous receiver of network change events.
48///
49/// Receivers are normally created through the facade's `Lattice::watch` or
50/// `Lattice::watch_filtered` methods.
51///
52/// [`Self::recv`] blocks, while [`Self::try_recv`] and
53/// [`Self::recv_timeout`] do not wait indefinitely. Dropping the receiver
54/// also drops any backend-owned subscription guard, allowing its native
55/// watcher to stop. If its producer shuts down, receive methods return
56/// [`Error::Disconnected`]. When a slow consumer fills the bounded queue,
57/// multiple dropped events are coalesced into one resynchronization event
58/// delivered before a later ordinary event.
59///
60/// `EventReceiver<E>` is `Send` when `E` is `Send`; it is not cloneable, so a
61/// watcher has one consuming receiver. It is not guaranteed to be [`Sync`].
62///
63/// Also implements [`Iterator`], yielding the same [`Result`] values as
64/// [`Self::recv`]. Iteration ends only after the watcher disconnects.
65pub struct EventReceiver<E> {
66 receiver: mpsc::Receiver<Result<E>>,
67 // Owns backend-specific cancellation state (for example, a Windows IP
68 // Helper registration or a route-socket reader). It is intentionally
69 // opaque: consumers only receive events, while dropping the receiver
70 // reliably tears down the native subscription.
71 _subscription: Option<Box<dyn Send>>,
72}
73
74impl<E> EventReceiver<E> {
75 /// Creates a bounded event channel using the default capacity.
76 ///
77 /// This constructor is intended for backend implementations. Applications
78 /// normally obtain an `EventReceiver` through `Lattice::watch` or
79 /// `Lattice::watch_filtered`. The returned sender applies Net Lattice's
80 /// bounded-delivery and overflow semantics.
81 pub fn bounded() -> (EventSender<E>, Self) {
82 Self::bounded_with_capacity(DEFAULT_EVENT_QUEUE_CAPACITY)
83 }
84
85 /// Creates a bounded event channel with the requested capacity.
86 ///
87 /// This constructor is intended for backend implementations. Applications
88 /// normally obtain an `EventReceiver` through `Lattice::watch` or
89 /// `Lattice::watch_filtered`.
90 ///
91 /// # Panics
92 ///
93 /// Panics if `capacity` is zero.
94 pub fn bounded_with_capacity(capacity: usize) -> (EventSender<E>, Self) {
95 assert!(capacity > 0, "event queue capacity must be non-zero");
96 let (sender, receiver) = mpsc::sync_channel(capacity);
97 (
98 EventSender {
99 sender,
100 pending_resync: Arc::new(Mutex::new(None)),
101 },
102 Self {
103 receiver,
104 _subscription: None,
105 },
106 )
107 }
108 /// Wraps a channel receiver that a backend watcher thread or task sends
109 /// events into.
110 ///
111 /// This constructor is intended for backend implementations. Applications
112 /// normally obtain an `EventReceiver` through `Lattice::watch` or
113 /// `Lattice::watch_filtered`.
114 pub fn from_channel_receiver(receiver: mpsc::Receiver<Result<E>>) -> Self {
115 Self {
116 receiver,
117 _subscription: None,
118 }
119 }
120
121 /// Wraps a channel receiver and attaches a backend-owned subscription
122 /// guard.
123 ///
124 /// The guard is retained for the lifetime of the returned receiver.
125 /// Dropping the receiver drops the guard, allowing the associated native
126 /// subscription to stop.
127 ///
128 /// This constructor is intended for backend implementations. Applications
129 /// normally obtain an `EventReceiver` through `Lattice::watch` or
130 /// `Lattice::watch_filtered`.
131 pub fn from_receiver_with_subscription<S>(
132 receiver: mpsc::Receiver<Result<E>>,
133 subscription: S,
134 ) -> Self
135 where
136 S: Send + 'static,
137 {
138 Self {
139 receiver,
140 _subscription: Some(Box::new(subscription)),
141 }
142 }
143
144 /// Attaches a backend-owned subscription guard to this receiver.
145 ///
146 /// The guard is retained for the lifetime of the receiver and dropped
147 /// when the receiver is dropped. If a guard is already attached, it is
148 /// dropped and replaced by the new guard.
149 ///
150 /// This method is intended for backend implementations.
151 pub fn with_subscription<S>(mut self, subscription: S) -> Self
152 where
153 S: Send + 'static,
154 {
155 self._subscription = Some(Box::new(subscription));
156 self
157 }
158
159 /// Blocks until the next event is available.
160 ///
161 /// A temporarily empty queue does not cause this method to return. The
162 /// receiver retains any attached subscription guard throughout the wait.
163 /// Returns [`Error::Disconnected`] after the backend watcher has stopped
164 /// and no further events can arrive. Other producer errors are propagated
165 /// unchanged.
166 pub fn recv(&self) -> Result<E> {
167 self.receiver.recv().map_err(|_| Error::Disconnected)?
168 }
169
170 /// Attempts to receive an event without blocking.
171 ///
172 /// Returns `Ok(Some(event))` when an event is already queued, `Ok(None)`
173 /// when no event is currently available, or [`Error::Disconnected`] when
174 /// the watcher has stopped and no further events can arrive. A temporarily
175 /// empty queue is not an error. Other producer errors are propagated
176 /// unchanged.
177 pub fn try_recv(&self) -> Result<Option<E>> {
178 match self.receiver.try_recv() {
179 Ok(Ok(event)) => Ok(Some(event)),
180 Ok(Err(error)) => Err(error),
181 Err(mpsc::TryRecvError::Empty) => Ok(None),
182 Err(mpsc::TryRecvError::Disconnected) => Err(Error::Disconnected),
183 }
184 }
185
186 /// Waits for an event for at most `timeout`.
187 ///
188 /// Returns `Ok(Some(event))` when an event arrives before the timeout,
189 /// `Ok(None)` when the timeout expires, or [`Error::Disconnected`] when
190 /// the watcher has stopped and no further events can arrive. A timeout is
191 /// not an error. Other producer errors are propagated unchanged.
192 pub fn recv_timeout(&self, timeout: Duration) -> Result<Option<E>> {
193 match self.receiver.recv_timeout(timeout) {
194 Ok(Ok(event)) => Ok(Some(event)),
195 Ok(Err(error)) => Err(error),
196 Err(mpsc::RecvTimeoutError::Timeout) => Ok(None),
197 Err(mpsc::RecvTimeoutError::Disconnected) => Err(Error::Disconnected),
198 }
199 }
200}
201
202/// Iterates over events until the backend watcher disconnects.
203///
204/// Calling [`Iterator::next`] blocks in the same way as [`Self::recv`].
205/// Receiver errors are yielded to the caller as `Err` values.
206impl<E> Iterator for EventReceiver<E> {
207 type Item = Result<E>;
208
209 fn next(&mut self) -> Option<Result<E>> {
210 match self.recv() {
211 Ok(event) => Some(Ok(event)),
212 Err(Error::Disconnected) => None,
213 Err(error) => Some(Err(error)),
214 }
215 }
216}
217
218/// Subscribes to filtered change notifications for the domains and objects a
219/// backend supports.
220///
221/// Generic over an associated `Event` type rather than naming
222/// `net_lattice_model::event::Event` directly — `net-lattice-platform` does
223/// not depend on `net-lattice-model` (see ARCHITECTURE.md). The facade
224/// crate (`net-lattice`) is what constrains `Event` to the concrete model
225/// type.
226///
227/// Unlike the other provider traits, this one is inherently push-based:
228/// `watch` starts a backend-owned background watcher (a Netlink multicast
229/// subscription, a BSD routing-socket reader, a Windows
230/// `NotifyRouteChange2`-style callback, ...) and returns an
231/// [`EventReceiver`] fed by it. The watcher runs for as long as the
232/// returned `EventReceiver` (and whatever the backend keeps alive to feed
233/// it) is alive.
234pub trait EventProvider {
235 type Event;
236 type EventFilter;
237
238 fn watch(&self) -> Result<EventReceiver<Self::Event>>;
239 fn watch_filtered(&self, filter: Self::EventFilter) -> Result<EventReceiver<Self::Event>>;
240}
241
242#[cfg(test)]
243mod tests {
244 use super::*;
245 use std::sync::atomic::{AtomicUsize, Ordering};
246 use std::thread;
247
248 struct DropGuard(Arc<AtomicUsize>);
249
250 impl Drop for DropGuard {
251 fn drop(&mut self) {
252 self.0.fetch_add(1, Ordering::SeqCst);
253 }
254 }
255
256 #[test]
257 fn recv_returns_disconnected_once_the_sender_is_dropped() {
258 let (sender, receiver) = EventReceiver::<u32>::bounded();
259 drop(sender);
260 assert!(matches!(receiver.recv(), Err(Error::Disconnected)));
261 }
262
263 #[test]
264 fn try_recv_returns_none_when_empty_but_still_connected() {
265 let (_sender, receiver) = EventReceiver::<u32>::bounded();
266 assert!(matches!(receiver.try_recv(), Ok(None)));
267 }
268
269 #[test]
270 fn iterator_ends_when_the_sender_is_dropped() {
271 let (sender, receiver) = EventReceiver::<u32>::bounded();
272 thread::spawn(move || {
273 assert!(sender.send(1, 0));
274 assert!(sender.send(2, 0));
275 });
276 let received: Vec<Result<u32>> = receiver.collect();
277 assert!(matches!(received.as_slice(), [Ok(1), Ok(2)]));
278 }
279
280 #[test]
281 fn iterator_yields_a_producer_error() {
282 let (sender, mut receiver) = EventReceiver::<u32>::bounded();
283 assert!(sender.send_error(Error::InvalidState));
284 assert!(matches!(receiver.next(), Some(Err(Error::InvalidState))));
285 }
286
287 #[test]
288 fn dropping_receiver_drops_subscription_guard() {
289 let drops = Arc::new(AtomicUsize::new(0));
290 let (_sender, receiver) = EventReceiver::<u32>::bounded();
291 drop(receiver.with_subscription(DropGuard(Arc::clone(&drops))));
292 assert_eq!(drops.load(Ordering::SeqCst), 1);
293 }
294
295 #[test]
296 fn replacing_subscription_drops_the_previous_guard() {
297 let first = Arc::new(AtomicUsize::new(0));
298 let second = Arc::new(AtomicUsize::new(0));
299 let (_sender, receiver) = EventReceiver::<u32>::bounded();
300 let receiver = receiver.with_subscription(DropGuard(Arc::clone(&first)));
301 let receiver = receiver.with_subscription(DropGuard(Arc::clone(&second)));
302 assert_eq!(first.load(Ordering::SeqCst), 1);
303 assert_eq!(second.load(Ordering::SeqCst), 0);
304 drop(receiver);
305 assert_eq!(second.load(Ordering::SeqCst), 1);
306 }
307
308 #[test]
309 #[should_panic(expected = "event queue capacity must be non-zero")]
310 fn zero_capacity_is_rejected() {
311 let _ = EventReceiver::<u32>::bounded_with_capacity(0);
312 }
313
314 #[test]
315 fn recv_timeout_returns_none_on_timeout_without_disconnecting() {
316 let (sender, receiver) = EventReceiver::<u32>::bounded();
317 assert!(matches!(
318 receiver.recv_timeout(Duration::from_millis(10)),
319 Ok(None)
320 ));
321 assert!(sender.send(7, 0));
322 assert_eq!(
323 receiver.recv_timeout(Duration::from_secs(1)).unwrap(),
324 Some(7)
325 );
326 }
327
328 #[test]
329 fn overflow_delivers_resync_before_a_later_event() {
330 let (sender, receiver) = EventReceiver::bounded_with_capacity(1);
331 assert!(sender.send(1, 99));
332 assert!(sender.send(2, 99));
333 assert_eq!(receiver.recv().unwrap(), 1);
334 assert!(sender.send(3, 99));
335 assert_eq!(receiver.recv().unwrap(), 99);
336 }
337
338 #[test]
339 fn background_error_is_returned() {
340 let (sender, receiver) = EventReceiver::<u32>::bounded();
341 assert!(sender.send_error(Error::InvalidState));
342 assert!(matches!(receiver.recv(), Err(Error::InvalidState)));
343 }
344}