rns_embedded_runtime/node_parts/
eventsubscription.rs1pub struct EventSubscription {
2 inner: SharedNode,
3 subscription_id: u64,
4}
5
6impl Clone for EventSubscription {
7 fn clone(&self) -> Self {
8 Self { inner: clone_inner(&self.inner), subscription_id: self.subscription_id }
9 }
10}
11
12impl EmbeddedNode {
13 pub fn new() -> Self {
14 #[cfg(feature = "std")]
15 let inner = Arc::new(StdNodeInner {
16 state: Mutex::new(NodeState::default()),
17 condvar: Condvar::new(),
18 });
19
20 #[cfg(not(feature = "std"))]
21 let inner = Rc::new(RefCell::new(NodeState::default()));
22
23 Self { inner }
24 }
25
26 pub fn start(&self, config: NodeConfig) -> Result<(), NodeError> {
27 let next_epoch = self.with_state(|state| {
28 if state.session.is_some() {
29 return Err(NodeError::AlreadyRunning);
30 }
31 let epoch = state.epoch.saturating_add(1);
32 let session = RuntimeSession::new(epoch, &config)?;
33 state.epoch = epoch;
34 state.session = Some(session);
35 state.event_capacity = config.runtime.max_events;
36 state.last_now_ms = 0;
37 signal_generation_change(state, epoch);
38 push_event_locked(
39 state,
40 NodeEventKind::StatusChanged {
41 run_state: NodeRunState::Running,
42 lifecycle_state: Some(NodeLifecycleState::Boot),
43 },
44 None,
45 0,
46 );
47 Ok(epoch)
48 })?;
49 self.notify_waiters();
50 #[cfg(feature = "std")]
51 self.start_driver(next_epoch)?;
52 #[cfg(not(feature = "std"))]
53 let _ = next_epoch;
54 Ok(())
55 }
56
57 pub fn stop(&self) -> Result<(), NodeError> {
58 #[cfg(feature = "std")]
59 let handle = self.with_state(|state| {
60 let handle = stop_driver_locked(state);
61 if state.session.is_some() {
62 state.session = None;
63 signal_stopped(state);
64 push_event_locked(
65 state,
66 NodeEventKind::StatusChanged {
67 run_state: NodeRunState::Stopped,
68 lifecycle_state: None,
69 },
70 None,
71 state.last_now_ms,
72 );
73 }
74 Ok(handle)
75 })?;
76
77 #[cfg(not(feature = "std"))]
78 self.with_state(|state| {
79 if state.session.is_some() {
80 state.session = None;
81 signal_stopped(state);
82 push_event_locked(
83 state,
84 NodeEventKind::StatusChanged {
85 run_state: NodeRunState::Stopped,
86 lifecycle_state: None,
87 },
88 None,
89 state.last_now_ms,
90 );
91 }
92 Ok(())
93 })?;
94
95 self.notify_waiters();
96
97 #[cfg(feature = "std")]
98 join_driver(handle)?;
99
100 Ok(())
101 }
102
103 pub fn restart(&self, config: NodeConfig) -> Result<(), NodeError> {
104 self.stop()?;
105 self.start(config)
106 }
107
108 pub fn get_status(&self) -> NodeStatus {
109 self.with_state_read(|state| {
110 state.session.as_ref().map_or(
111 NodeStatus {
112 run_state: NodeRunState::Stopped,
113 epoch: state.epoch,
114 lifecycle_state: None,
115 pending_outbound: 0,
116 stats: RuntimeStats::default(),
117 log_level: state.log_level,
118 },
119 |session| session.status(state.log_level),
120 )
121 })
122 }
123
124 pub fn send(
125 &self,
126 destination: [u8; 16],
127 data: &[u8],
128 _options: SendOptions,
129 ) -> Result<NodeOperationReceipt, NodeError> {
130 let receipt = self.with_state(|state| {
131 let session = state.session.as_mut().ok_or(NodeError::NotRunning)?;
132 if !session.has_outbound_capacity(1) {
133 return Err(NodeError::QueuePressure);
134 }
135 let sequence = session.queue_message(destination, data)?;
136 Ok(NodeOperationReceipt {
137 operation: NodeOperationKind::Send,
138 operation_id: u64::from(sequence),
139 epoch: session.epoch,
140 accepted_bytes: data.len(),
141 queued: true,
142 target_count: 1,
143 })
144 })?;
145 self.notify_waiters();
146 Ok(receipt)
147 }
148
149 pub fn broadcast(
150 &self,
151 data: &[u8],
152 options: BroadcastOptions,
153 ) -> Result<NodeOperationReceipt, NodeError> {
154 if options.destinations.is_empty() {
155 return Err(NodeError::InvalidConfig);
156 }
157 let receipt = self.with_state(|state| {
158 let session = state.session.as_mut().ok_or(NodeError::NotRunning)?;
159 if !session.has_outbound_capacity(options.destinations.len()) {
160 return Err(NodeError::QueuePressure);
161 }
162 let mut last_sequence = 0_u64;
163 for destination in &options.destinations {
164 last_sequence = u64::from(session.queue_message(*destination, data)?);
165 }
166 Ok(NodeOperationReceipt {
167 operation: NodeOperationKind::Broadcast,
168 operation_id: last_sequence,
169 epoch: session.epoch,
170 accepted_bytes: data.len(),
171 queued: true,
172 target_count: u32::try_from(options.destinations.len()).unwrap_or(u32::MAX),
173 })
174 })?;
175 self.notify_waiters();
176 Ok(receipt)
177 }
178
179 pub fn set_log_level(&self, level: NodeLogLevel) -> Result<(), NodeError> {
180 self.with_state(|state| {
181 state.log_level = level;
182 push_event_locked(
183 state,
184 NodeEventKind::Log { level, code: 0 },
185 None,
186 state.last_now_ms,
187 );
188 Ok(())
189 })?;
190 self.notify_waiters();
191 Ok(())
192 }
193
194 pub fn subscribe_events(&self) -> Result<EventSubscription, NodeError> {
195 let subscription_id = self.with_state(|state| {
196 let id = state.next_subscription_id;
197 state.next_subscription_id = state.next_subscription_id.saturating_add(1);
198 state.subscriptions.insert(
199 id,
200 SubscriptionState {
201 next_event_id: state.next_event_id,
202 pending_signals: VecDeque::new(),
203 },
204 );
205 Ok(id)
206 })?;
207
208 Ok(EventSubscription { inner: clone_inner(&self.inner), subscription_id })
209 }
210
211 pub fn tick(&self, now_ms: u64) -> Result<(), NodeError> {
212 self.with_state(|state| {
213 ensure_manual_progression_allowed(state)?;
214 let events = {
215 let session = state.session.as_mut().ok_or(NodeError::NotRunning)?;
216 session.tick(now_ms)?
217 };
218 state.last_now_ms = now_ms;
219 append_runtime_events_locked(state, events);
220 Ok(())
221 })?;
222 self.notify_waiters();
223 Ok(())
224 }
225
226 pub fn set_link_state(&self, state_value: LinkState) -> Result<(), NodeError> {
227 self.with_state(|state| {
228 let session = state.session.as_mut().ok_or(NodeError::NotRunning)?;
229 session.backend.set_link_state(state_value);
230 Ok(())
231 })
232 }
233
234 pub fn set_network_provisioned(&self, provisioned: bool) -> Result<(), NodeError> {
235 self.with_state(|state| {
236 let session = state.session.as_mut().ok_or(NodeError::NotRunning)?;
237 session.runtime.set_network_provisioned(provisioned);
238 Ok(())
239 })
240 }
241
242 pub fn set_ble_recovery_active(&self, active: bool) -> Result<(), NodeError> {
243 self.with_state(|state| {
244 let session = state.session.as_mut().ok_or(NodeError::NotRunning)?;
245 session.runtime.set_ble_recovery_active(active);
246 Ok(())
247 })
248 }
249
250 pub fn push_inbound_wire(&self, bytes: &[u8]) -> Result<(), NodeError> {
251 self.with_state(|state| {
252 let session = state.session.as_mut().ok_or(NodeError::NotRunning)?;
253 session.backend.push_inbound_wire(bytes)
254 })
255 }
256
257 pub fn take_outbound_wire(&self) -> Result<Option<Vec<u8>>, NodeError> {
258 self.with_state(|state| {
259 let session = state.session.as_mut().ok_or(NodeError::NotRunning)?;
260 Ok(session.backend.take_outbound_wire())
261 })
262 }
263
264 pub fn link_state(&self) -> Result<LinkState, NodeError> {
265 self.with_state_read_result(|state| {
266 let session = state.session.as_ref().ok_or(NodeError::NotRunning)?;
267 Ok(session.backend.link_state())
268 })
269 }
270
271 pub fn capability_supports_blocking_next(&self) -> bool {
272 cfg!(feature = "std")
273 }
274
275 pub fn capability_supports_managed_runtime(&self) -> bool {
276 cfg!(feature = "std")
277 }
278
279 pub fn capability_supports_event_gap_signaling(&self) -> bool {
280 true
281 }
282
283 #[cfg(feature = "std")]
284 fn start_driver(&self, epoch: u64) -> Result<(), NodeError> {
285 let start_instant = Instant::now();
286 self.with_state(|state| {
287 state.driver =
288 Some(DriverState { epoch, stop_requested: false, start_instant, handle: None });
289 Ok(())
290 })?;
291
292 let inner = Arc::clone(&self.inner);
293 let handle = thread::spawn(move || loop {
294 let continue_running = driver_tick(&inner, epoch);
295 if !continue_running {
296 break;
297 }
298 thread::sleep(DRIVER_TICK_SLEEP);
299 });
300
301 let mut state = match self.inner.state.lock() {
302 Ok(state) => state,
303 Err(_) => {
304 handle.join().map_err(|_| NodeError::InternalError)?;
305 return Err(NodeError::InternalError);
306 }
307 };
308 if let Some(driver) = state.driver.as_mut() {
309 if driver.epoch == epoch {
310 driver.handle = Some(handle);
311 return Ok(());
312 }
313 }
314 drop(state);
315
316 handle.join().map_err(|_| NodeError::InternalError)?;
317 Ok(())
318 }
319
320 #[cfg(feature = "std")]
321 fn notify_waiters(&self) {
322 self.inner.condvar.notify_all();
323 }
324
325 #[cfg(not(feature = "std"))]
326 fn notify_waiters(&self) {}
327
328 #[cfg(feature = "std")]
329 fn with_state<R>(
330 &self,
331 f: impl FnOnce(&mut NodeState) -> Result<R, NodeError>,
332 ) -> Result<R, NodeError> {
333 let mut state = self.inner.state.lock().map_err(|_| NodeError::InternalError)?;
334 f(&mut state)
335 }
336
337 #[cfg(not(feature = "std"))]
338 fn with_state<R>(
339 &self,
340 f: impl FnOnce(&mut NodeState) -> Result<R, NodeError>,
341 ) -> Result<R, NodeError> {
342 let mut state = self.inner.try_borrow_mut().map_err(|_| NodeError::InternalError)?;
343 f(&mut state)
344 }
345
346 #[cfg(feature = "std")]
347 fn with_state_read<R>(&self, f: impl FnOnce(&NodeState) -> R) -> R {
348 let state = self.inner.state.lock().expect("node state poisoned");
349 f(&state)
350 }
351
352 #[cfg(not(feature = "std"))]
353 fn with_state_read<R>(&self, f: impl FnOnce(&NodeState) -> R) -> R {
354 let state = self.inner.borrow();
355 f(&state)
356 }
357
358 #[cfg(feature = "std")]
359 fn with_state_read_result<R>(
360 &self,
361 f: impl FnOnce(&NodeState) -> Result<R, NodeError>,
362 ) -> Result<R, NodeError> {
363 let state = self.inner.state.lock().map_err(|_| NodeError::InternalError)?;
364 f(&state)
365 }
366
367 #[cfg(not(feature = "std"))]
368 fn with_state_read_result<R>(
369 &self,
370 f: impl FnOnce(&NodeState) -> Result<R, NodeError>,
371 ) -> Result<R, NodeError> {
372 let state = self.inner.try_borrow().map_err(|_| NodeError::InternalError)?;
373 f(&state)
374 }
375}
376
377impl EventSubscription {
378 pub fn next(&self, timeout_ms: u64) -> Result<PollResult, NodeError> {
379 #[cfg(feature = "std")]
380 {
381 if timeout_ms > MAX_BLOCKING_TIMEOUT_MS {
382 return Ok(PollResult::Timeout);
383 }
384
385 let Some(deadline) = Instant::now().checked_add(Duration::from_millis(timeout_ms))
386 else {
387 return Ok(PollResult::Timeout);
388 };
389 let mut state = self.inner.state.lock().map_err(|_| NodeError::InternalError)?;
390 loop {
391 let result = next_poll_result_locked(&mut state, self.subscription_id);
392 if !matches!(result, PollResult::Timeout) || timeout_ms == 0 {
393 return Ok(result);
394 }
395 let now = Instant::now();
396 if now >= deadline {
397 return Ok(PollResult::Timeout);
398 }
399 let wait = deadline.saturating_duration_since(now);
400 let (next_state, _) = self
401 .inner
402 .condvar
403 .wait_timeout(state, wait)
404 .map_err(|_| NodeError::InternalError)?;
405 state = next_state;
406 }
407 }
408
409 #[cfg(not(feature = "std"))]
410 {
411 let mut state = self.inner.try_borrow_mut().map_err(|_| NodeError::InternalError)?;
412 let _ = timeout_ms;
413 Ok(next_poll_result_locked(&mut state, self.subscription_id))
414 }
415 }
416
417 pub fn close(&self) -> Result<(), NodeError> {
418 #[cfg(feature = "std")]
419 {
420 let mut state = self.inner.state.lock().map_err(|_| NodeError::InternalError)?;
421 state.subscriptions.remove(&self.subscription_id);
422 self.inner.condvar.notify_all();
423 Ok(())
424 }
425
426 #[cfg(not(feature = "std"))]
427 {
428 let mut state = self.inner.try_borrow_mut().map_err(|_| NodeError::InternalError)?;
429 state.subscriptions.remove(&self.subscription_id);
430 Ok(())
431 }
432 }
433}