liminal_server/tap/subscription/
call.rs1use super::{Admitted, Hop, Tap, TapError, TapIdent, TapMessage, TapSource, lock};
4use crate::tap::message::{CallDetails, CallFact, Reached};
5use std::sync::{Arc, atomic::Ordering};
6use std::time::Instant;
7
8impl Tap {
9 pub fn source_station(&self, source: TapSource) -> Result<Option<Arc<str>>, TapError> {
14 self.station_of(source)
15 }
16
17 pub fn observe_call(&self, fact: &CallFact<'_>) -> Result<bool, TapError> {
23 if self.shared.active.load(Ordering::Acquire) == 0 {
24 return Ok(false);
25 }
26 let observation = self.shared.observed.fetch_add(1, Ordering::Relaxed);
27 let mut kept = false;
28 let result = self.keep_call(fact, observation, &mut kept);
29 if kept && let Some(waker) = self.shared.waker.get() {
30 waker();
31 }
32 result.map(|()| kept)
33 }
34
35 fn keep_call(
36 &self,
37 fact: &CallFact<'_>,
38 observation: u64,
39 kept: &mut bool,
40 ) -> Result<(), TapError> {
41 let terminal_ms = call_ms(fact.received_at, fact.finished_at, 0)?;
42 let served_ms = call_ms(fact.received_at, fact.forwarded_at, 1)?;
43 if served_ms > terminal_ms {
44 return Err(TapError::HopsOutOfOrder {
45 hop: 1,
46 at_ms: served_ms,
47 before_ms: terminal_ms,
48 });
49 }
50 let subscribers = lock(&self.shared.subscribers, "tap subscribers")?;
51 for subscriber in subscribers.iter() {
52 if !subscriber.filter.matches(fact.subject) {
53 continue;
54 }
55 let mut state = lock(&subscriber.state, "tap subscriber")?;
56 if !state.admits() {
57 continue;
58 }
59 let mut hops = Vec::new();
60 if let Some(station) = fact.station {
61 hops.push(Hop {
62 node: Arc::clone(station),
63 at_ms: 0,
64 });
65 }
66 hops.push(Hop {
67 node: Arc::clone(&self.node),
68 at_ms: 0,
69 });
70 let reached: Arc<[Reached]> = fact.served_by.map_or_else(
71 || Arc::clone(&self.shared.no_stations),
72 |station| {
73 hops.push(Hop {
74 node: Arc::clone(station),
75 at_ms: served_ms,
76 });
77 Arc::from([Reached {
78 station: Arc::clone(station),
79 queued_at: fact.forwarded_at,
80 }])
81 },
82 );
83 hops.push(Hop {
84 node: Arc::clone(&self.node),
85 at_ms: terminal_ms,
86 });
87 let message = TapMessage {
88 ident: fact
89 .operation
90 .map_or(TapIdent::Observation(observation), |operation| {
91 TapIdent::Call {
92 connection: fact.connection,
93 operation,
94 }
95 }),
96 subject: fact.subject.to_owned(),
97 size: fact.size,
98 outcome: fact.outcome,
99 seen_at: fact.received_at,
100 source: TapSource::Connection(fact.connection),
101 station: fact.station.cloned(),
102 to_stations: Some(reached),
103 hops,
104 reply_to: None,
105 held: false,
106 payload: None,
107 call: Some(CallDetails {
108 latency_ms: (fact.outcome == crate::tap::TapOutcome::Answered)
109 .then_some(terminal_ms),
110 refusal: fact.refusal.map(str::to_owned),
111 }),
112 };
113 let one_in = state.one_in;
114 if state.ring.push(Admitted { one_in, message }) {
115 self.shared.dropped_total.fetch_add(1, Ordering::Relaxed);
116 }
117 state.after_push();
118 drop(state);
119 *kept = true;
120 }
121 drop(subscribers);
122 Ok(())
123 }
124}
125
126fn call_ms(start: Instant, end: Instant, hop: usize) -> Result<u64, TapError> {
127 let elapsed =
128 end.checked_duration_since(start)
129 .ok_or_else(|| TapError::HopBeforeFirstSight {
130 hop,
131 early_ms: u64::try_from(start.duration_since(end).as_millis()).unwrap_or(u64::MAX),
132 })?;
133 u64::try_from(elapsed.as_millis()).map_err(|_| TapError::HopOverflow { hop })
134}