macula_rust/pool/
serve.rs1use std::collections::HashMap;
7use std::sync::atomic::{AtomicU64, Ordering};
8use std::sync::{Arc, Mutex, MutexGuard, Weak};
9use std::time::Duration;
10
11use crate::frame::StreamMode;
12use crate::station_link::{
13 self, Handler, Link, LinkError, StreamHandler, StreamOffer, DEFAULT_CALL_TIMEOUT,
14};
15
16use super::{Pool, PoolError, PoolInner};
17
18static NEXT_SERVED: AtomicU64 = AtomicU64::new(1);
19
20#[derive(Clone)]
24pub struct Offer {
25 pub realm: [u8; 32],
26 pub procedure: String,
27 pub handler: Option<Handler>,
28 pub stream: Option<StreamOffer>,
29}
30
31impl Offer {
32 pub fn unary(realm: [u8; 32], procedure: &str, handler: Handler) -> Offer {
34 Offer {
35 realm,
36 procedure: procedure.to_string(),
37 handler: Some(handler),
38 stream: None,
39 }
40 }
41
42 pub fn stream(
44 realm: [u8; 32],
45 procedure: &str,
46 mode: StreamMode,
47 handler: StreamHandler,
48 ) -> Offer {
49 Offer {
50 realm,
51 procedure: procedure.to_string(),
52 handler: None,
53 stream: Some(StreamOffer { mode, handler }),
54 }
55 }
56}
57
58pub struct Served {
61 inner: Arc<ServedInner>,
62}
63
64pub(super) struct ServedInner {
65 id: u64,
66 pool: Weak<PoolInner>,
67 offer: station_link::Offer,
68 held: Mutex<Held>,
69}
70
71struct Held {
72 stopped: bool,
73 on_links: HashMap<u64, station_link::Served>,
74}
75
76impl Pool {
77 pub async fn serve(&self, o: Offer) -> Result<Served, PoolError> {
82 let realm_key = self.inner.realm_key_for(&o.realm, &o.procedure)?;
83 let served = Arc::new(ServedInner {
84 id: NEXT_SERVED.fetch_add(1, Ordering::Relaxed),
85 pool: Arc::downgrade(&self.inner),
86 offer: station_link::Offer {
87 realm: o.realm,
88 procedure: o.procedure,
89 handler: o.handler,
90 stream: o.stream,
91 realm_key,
92 },
93 held: Mutex::new(Held {
94 stopped: false,
95 on_links: HashMap::new(),
96 }),
97 });
98 let links = self.inner.links();
99 if links.is_empty() {
100 return Err(PoolError::NoLink(Vec::new()));
101 }
102 let mut errors = Vec::new();
103 for link in &links {
104 if let Err(e) = served.serve_on(link).await {
105 errors.push(e);
106 }
107 }
108 if errors.len() == links.len() {
109 return Err(PoolError::NotServed(errors));
110 }
111 {
112 let mut state = self.inner.lock();
113 if state.closed {
114 return Err(PoolError::Closed);
115 }
116 state.served.insert(served.id, served.clone());
117 }
118 for link in self.inner.links() {
119 served.attach(link);
120 }
121 Ok(Served { inner: served })
122 }
123}
124
125impl PoolInner {
126 pub(super) async fn replay(&self, link: &Link) {
129 let (subs, served) = {
130 let state = self.lock();
131 (
132 state.subs.values().cloned().collect::<Vec<_>>(),
133 state.served.values().cloned().collect::<Vec<_>>(),
134 )
135 };
136 for sub in subs {
137 sub.attach(link).await;
138 }
139 for s in served {
140 s.attach(link.clone());
141 }
142 }
143}
144
145impl Served {
146 pub async fn stop(&self) -> Result<(), LinkError> {
148 if let Some(pool) = self.inner.pool.upgrade() {
149 pool.lock().served.remove(&self.inner.id);
150 }
151 let on_links = {
152 let mut held = self.inner.lock();
153 if held.stopped {
154 return Ok(());
155 }
156 held.stopped = true;
157 std::mem::take(&mut held.on_links)
158 };
159 let mut result = Ok(());
160 for on_link in on_links.into_values() {
161 if let Err(e) = on_link.stop().await {
162 result = Err(e);
163 }
164 }
165 result
166 }
167}
168
169impl ServedInner {
170 fn lock(&self) -> MutexGuard<'_, Held> {
171 self.held.lock().unwrap_or_else(|p| p.into_inner())
172 }
173
174 fn respawn_delay(&self) -> Option<Duration> {
175 self.pool.upgrade().map(|p| p.opts.respawn_delay)
176 }
177
178 async fn serve_on(self: &Arc<Self>, link: &Link) -> Result<(), LinkError> {
180 {
181 let held = self.lock();
182 if held.stopped || held.on_links.contains_key(&link.serial()) {
183 return Ok(());
184 }
185 }
186 let on_link = match link.serve(self.offer.clone()).await {
187 Err(LinkError::AlreadyServed) => return Ok(()),
188 other => other?,
189 };
190 {
191 let mut held = self.lock();
192 if !held.stopped {
193 held.on_links.insert(link.serial(), on_link.clone());
194 drop(held);
195 tokio::spawn(watch(self.clone(), link.clone(), on_link));
196 return Ok(());
197 }
198 }
199 on_link.stop().await
200 }
201
202 pub(super) fn attach(self: &Arc<Self>, link: Link) {
205 let served = self.clone();
206 tokio::spawn(async move {
207 loop {
208 let outcome =
209 tokio::time::timeout(DEFAULT_CALL_TIMEOUT, served.serve_on(&link)).await;
210 if matches!(outcome, Ok(Ok(()))) {
211 return;
212 }
213 let Some(delay) = served.respawn_delay() else {
214 return;
215 };
216 tokio::select! {
217 _ = link.done() => return,
218 _ = tokio::time::sleep(delay) => {}
219 }
220 }
221 });
222 }
223}
224
225async fn watch(served: Arc<ServedInner>, link: Link, on_link: station_link::Served) {
228 let why = on_link.done().await;
229 let stopped = {
230 let mut held = served.lock();
231 held.on_links.remove(&link.serial());
232 held.stopped
233 };
234 if stopped || why == LinkError::Stopped || link.error().is_some() {
235 return;
236 }
237 let Some(delay) = served.respawn_delay() else {
238 return;
239 };
240 tokio::select! {
241 _ = link.done() => {}
242 _ = tokio::time::sleep(delay) => served.attach(link.clone()),
243 }
244}