1use std::collections::VecDeque;
10use std::sync::{Arc, Mutex, MutexGuard};
11
12use oxrdf::{Literal, Quad, Term};
13use serde::{Deserialize, Serialize};
14use vertep_core::datamodel::Event;
15use vertep_core::kernel::descriptor_matches;
16
17use crate::address::Address;
18use crate::storage::{Storage, select, text};
19use crate::vocab::{self as vt, node};
20
21#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
23pub struct Envelope {
24 pub message_id: String,
26 pub to: String,
28 pub event: Event,
30 pub correlation: Option<String>,
32 pub timer: Option<String>,
34}
35
36impl Envelope {
37 pub fn new(message_id: impl Into<String>, to: &Address, event: Event) -> Self {
39 Envelope {
40 message_id: message_id.into(),
41 to: to.as_str().to_owned(),
42 event,
43 correlation: None,
44 timer: None,
45 }
46 }
47}
48
49#[derive(Clone, Debug, PartialEq, Eq)]
51pub struct MailboxError(pub String);
52
53impl core::fmt::Display for MailboxError {
54 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
55 write!(f, "mailbox error: {}", self.0)
56 }
57}
58
59impl std::error::Error for MailboxError {}
60
61pub fn is_deferred(deferred: &[String], name: &str) -> bool {
63 deferred.iter().any(|d| descriptor_matches(d, name))
64}
65
66pub trait Mailbox: Send + Sync {
70 fn enqueue(&self, env: Envelope) -> Result<(), MailboxError>;
76
77 fn receive(&self, deferred: &[String]) -> Option<Envelope>;
80
81 fn ack(&self, message_id: &str) -> Result<(), MailboxError>;
87
88 fn release(&self, message_id: &str);
90
91 fn release_all(&self);
93
94 fn pending(&self) -> Vec<Envelope>;
96
97 fn has_deliverable(&self, deferred: &[String]) -> bool {
99 self.pending_deliverable(deferred) > 0
100 }
101
102 fn pending_deliverable(&self, deferred: &[String]) -> usize;
104
105 fn len(&self) -> usize {
107 self.pending().len()
108 }
109
110 fn is_empty(&self) -> bool {
112 self.len() == 0
113 }
114}
115
116struct Row {
117 env: Envelope,
118 seq: u64,
119 in_flight: bool,
120}
121
122#[derive(Default)]
123struct Rows {
124 rows: VecDeque<Row>,
125 next: u64,
126}
127
128impl Rows {
129 fn receive(&mut self, deferred: &[String]) -> Option<Envelope> {
130 let r = self
131 .rows
132 .iter_mut()
133 .find(|r| !r.in_flight && !is_deferred(deferred, &r.env.event.name))?;
134 r.in_flight = true;
135 Some(r.env.clone())
136 }
137
138 fn remove(&mut self, id: &str) -> Option<Row> {
139 let i = self
140 .rows
141 .iter()
142 .position(|r| r.in_flight && r.env.message_id == id)
143 .or_else(|| self.rows.iter().position(|r| r.env.message_id == id))?;
144 self.rows.remove(i)
145 }
146
147 fn release(&mut self, id: &str) {
148 for r in &mut self.rows {
149 if r.env.message_id == id {
150 r.in_flight = false;
151 }
152 }
153 }
154
155 fn deliverable(&self, deferred: &[String]) -> usize {
156 self.rows
157 .iter()
158 .filter(|r| !r.in_flight && !is_deferred(deferred, &r.env.event.name))
159 .count()
160 }
161}
162
163fn lock(m: &Mutex<Rows>) -> MutexGuard<'_, Rows> {
164 m.lock().unwrap_or_else(std::sync::PoisonError::into_inner)
165}
166
167#[derive(Default)]
169pub struct MemoryMailbox {
170 rows: Mutex<Rows>,
171}
172
173impl std::fmt::Debug for MemoryMailbox {
174 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
175 f.debug_struct("MemoryMailbox")
176 .field("len", &self.len())
177 .finish()
178 }
179}
180
181impl Mailbox for MemoryMailbox {
182 fn enqueue(&self, env: Envelope) -> Result<(), MailboxError> {
183 let mut g = lock(&self.rows);
184 let seq = g.next;
185 g.next += 1;
186 g.rows.push_back(Row {
187 env,
188 seq,
189 in_flight: false,
190 });
191 Ok(())
192 }
193
194 fn receive(&self, deferred: &[String]) -> Option<Envelope> {
195 lock(&self.rows).receive(deferred)
196 }
197
198 fn ack(&self, message_id: &str) -> Result<(), MailboxError> {
199 lock(&self.rows).remove(message_id);
200 Ok(())
201 }
202
203 fn release(&self, message_id: &str) {
204 lock(&self.rows).release(message_id);
205 }
206
207 fn release_all(&self) {
208 for r in &mut lock(&self.rows).rows {
209 r.in_flight = false;
210 }
211 }
212
213 fn pending(&self) -> Vec<Envelope> {
214 lock(&self.rows)
215 .rows
216 .iter()
217 .map(|r| r.env.clone())
218 .collect()
219 }
220
221 fn pending_deliverable(&self, deferred: &[String]) -> usize {
222 lock(&self.rows).deliverable(deferred)
223 }
224}
225
226pub struct StoreMailbox {
230 address: Address,
231 storage: Arc<dyn Storage>,
232 rows: Mutex<Rows>,
233}
234
235impl std::fmt::Debug for StoreMailbox {
236 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
237 f.debug_struct("StoreMailbox")
238 .field("address", &self.address)
239 .field("len", &self.len())
240 .finish()
241 }
242}
243
244impl StoreMailbox {
245 pub fn open(address: Address, storage: Arc<dyn Storage>) -> Self {
247 let mut rows = Rows::default();
248 let g = address.mailbox_graph();
249 let q = format!(
250 "SELECT ?seq ?env WHERE {{ GRAPH {g} {{ ?m <{seq}> ?seq ; <{env}> ?env }} }}",
251 seq = vt::SEQUENCE,
252 env = vt::ENVELOPE
253 );
254 if let Ok(sol) = select(storage.graph(address.node()), &q) {
255 let mut found: Vec<(u64, Envelope)> = Vec::new();
256 for i in 0..sol.len() {
257 let seq = sol
258 .get(i, "seq")
259 .and_then(text)
260 .and_then(|s| s.parse::<u64>().ok());
261 let env = sol
262 .get(i, "env")
263 .and_then(text)
264 .and_then(|s| serde_json::from_str::<Envelope>(&s).ok());
265 if let (Some(seq), Some(env)) = (seq, env) {
266 found.push((seq, env));
267 }
268 }
269 found.sort_by(|(s, a), (t, b)| s.cmp(t).then_with(|| a.message_id.cmp(&b.message_id)));
272 for (seq, env) in found {
273 rows.next = rows.next.max(seq + 1);
274 rows.rows.push_back(Row {
275 env,
276 seq,
277 in_flight: false,
278 });
279 }
280 }
281 StoreMailbox {
282 address,
283 storage,
284 rows: Mutex::new(rows),
285 }
286 }
287
288 fn quads(&self, seq: u64, env: &Envelope) -> Vec<Quad> {
289 let g = self.address.mailbox_graph();
290 let json = serde_json::to_string(env).unwrap_or_default();
291 let m = self.address.mailbox_row_iri(seq, &json);
292 let q = |p: &str, o: Term| Quad::new(m.clone(), node(p), o, g.clone());
293 vec![
294 q(vt::RDF_TYPE, node(vt::MESSAGE).into()),
295 q(vt::RECIPIENT, self.address.node().clone().into()),
296 q(
297 vt::SEQUENCE,
298 Literal::new_typed_literal(seq.to_string(), oxrdf::vocab::xsd::INTEGER).into(),
299 ),
300 q(
301 vt::MESSAGE_ID,
302 Literal::new_simple_literal(&env.message_id).into(),
303 ),
304 q(vt::ENVELOPE, Literal::new_simple_literal(json).into()),
305 ]
306 }
307}
308
309impl Mailbox for StoreMailbox {
310 fn enqueue(&self, env: Envelope) -> Result<(), MailboxError> {
311 let mut g = lock(&self.rows);
312 let seq = g.next;
313 self.storage
314 .graph(self.address.node())
315 .insert_quads(&self.quads(seq, &env))
316 .map_err(|e| MailboxError(e.to_string()))?;
317 g.next += 1;
318 g.rows.push_back(Row {
319 env,
320 seq,
321 in_flight: false,
322 });
323 Ok(())
324 }
325
326 fn receive(&self, deferred: &[String]) -> Option<Envelope> {
327 lock(&self.rows).receive(deferred)
328 }
329
330 fn ack(&self, message_id: &str) -> Result<(), MailboxError> {
331 let mut g = lock(&self.rows);
332 if let Some(r) = g.remove(message_id) {
333 self.storage
334 .graph(self.address.node())
335 .remove_quads(&self.quads(r.seq, &r.env))
336 .map_err(|e| MailboxError(e.to_string()))?;
337 }
338 Ok(())
339 }
340
341 fn release(&self, message_id: &str) {
342 lock(&self.rows).release(message_id);
343 }
344
345 fn release_all(&self) {
346 for r in &mut lock(&self.rows).rows {
347 r.in_flight = false;
348 }
349 }
350
351 fn pending(&self) -> Vec<Envelope> {
352 lock(&self.rows)
353 .rows
354 .iter()
355 .map(|r| r.env.clone())
356 .collect()
357 }
358
359 fn pending_deliverable(&self, deferred: &[String]) -> usize {
360 lock(&self.rows).deliverable(deferred)
361 }
362}
363
364pub trait MailboxFactory: Send + Sync {
366 fn create(&self, address: &Address) -> Arc<dyn Mailbox>;
368 fn recover(&self) -> Vec<Address> {
370 Vec::new()
371 }
372}
373
374#[derive(Clone, Copy, Debug, Default)]
376pub struct MemoryMailboxes;
377
378impl MailboxFactory for MemoryMailboxes {
379 fn create(&self, _address: &Address) -> Arc<dyn Mailbox> {
380 Arc::new(MemoryMailbox::default())
381 }
382}
383
384#[derive(Clone)]
386pub struct StoreMailboxes {
387 storage: Arc<dyn Storage>,
388}
389
390impl std::fmt::Debug for StoreMailboxes {
391 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
392 f.debug_struct("StoreMailboxes").finish_non_exhaustive()
393 }
394}
395
396impl StoreMailboxes {
397 pub fn new(storage: Arc<dyn Storage>) -> Self {
399 StoreMailboxes { storage }
400 }
401}
402
403impl MailboxFactory for StoreMailboxes {
404 fn create(&self, address: &Address) -> Arc<dyn Mailbox> {
405 Arc::new(StoreMailbox::open(address.clone(), self.storage.clone()))
406 }
407
408 fn recover(&self) -> Vec<Address> {
409 let q = format!(
410 "SELECT DISTINCT ?a WHERE {{ GRAPH ?g {{ ?m a <{msg}> ; <{rcpt}> ?a }} }}",
411 msg = vt::MESSAGE,
412 rcpt = vt::RECIPIENT
413 );
414 let mut out = Vec::new();
415 for g in self.storage.graphs() {
416 if let Ok(sol) = select(g, &q) {
417 for t in sol.values("a") {
418 if let Some(a) = text(&t).and_then(|s| Address::parse(&s).ok()) {
419 out.push(a);
420 }
421 }
422 }
423 }
424 out.sort();
425 out.dedup();
426 out
427 }
428}
429
430#[cfg(test)]
431mod tests {
432 use super::*;
433 use vertep_core::datamodel::EventType;
434
435 fn env(id: &str, name: &str) -> Envelope {
436 Envelope::new(
437 id,
438 &Address::parse("urn:t:a").unwrap(),
439 Event::named(name, EventType::External),
440 )
441 }
442
443 #[test]
444 fn receive_skips_deferred_and_in_flight_and_keeps_order() {
445 let m = MemoryMailbox::default();
446 m.enqueue(env("1", "order.cancel")).unwrap();
447 m.enqueue(env("2", "ping")).unwrap();
448 m.enqueue(env("3", "pong")).unwrap();
449 let d = vec!["order.*".to_owned()];
450 assert_eq!(m.receive(&d).unwrap().message_id, "2");
451 assert_eq!(m.receive(&d).unwrap().message_id, "3");
452 assert!(m.receive(&d).is_none());
453 m.release("2");
454 assert_eq!(m.receive(&[]).unwrap().message_id, "1");
455 m.ack("1").unwrap();
456 assert_eq!(m.receive(&[]).unwrap().message_id, "2");
457 assert_eq!(m.len(), 2);
458 }
459}