liminal_server/tap/subscription/
publish.rs1use super::{
4 Admitted, Arc, Hop, Instant, Ordering, PublishFact, Reached, Recipient, Tap, TapError,
5 TapIdent, TapMessage, TapSource, elapsed_ms, gather, lock,
6};
7
8impl Tap {
9 pub fn observe(&self, fact: &PublishFact<'_>) -> Result<bool, TapError> {
28 self.observe_from(fact, None)
29 }
30
31 pub(crate) fn observe_embedded(
32 &self,
33 fact: &PublishFact<'_>,
34 host: &str,
35 ) -> Result<bool, TapError> {
36 self.observe_from(fact, Some(host))
37 }
38
39 fn observe_from(&self, fact: &PublishFact<'_>, host: Option<&str>) -> Result<bool, TapError> {
40 if self.shared.active.load(Ordering::Acquire) == 0 {
41 return Ok(false);
42 }
43 let observation = self.shared.observed.fetch_add(1, Ordering::Relaxed);
44 #[cfg(test)]
45 if fact.source == TapSource::Server && host.is_none() {
46 self.shared.observed_server.fetch_add(1, Ordering::Relaxed);
47 }
48 let mut kept = false;
49 let result = self.keep(fact, observation, &mut kept, host);
50 if kept && let Some(waker) = self.shared.waker.get() {
51 waker();
52 }
53 result.map(|()| kept)
54 }
55
56 pub(super) fn station_of(&self, source: TapSource) -> Result<Option<Arc<str>>, TapError> {
58 Ok(match source {
59 TapSource::Connection(connection) => lock(&self.shared.stations, "tap stations")?
60 .get(&connection)
61 .map(Arc::clone),
62 TapSource::Server => None,
63 })
64 }
65
66 fn stations_of(&self, recipients: &[Recipient]) -> Result<Arc<[Reached]>, TapError> {
72 if recipients.is_empty() {
73 return Ok(Arc::clone(&self.shared.no_stations));
74 }
75 let receivers = lock(&self.shared.receivers, "tap receivers")?;
76 let stations = lock(&self.shared.stations, "tap stations")?;
77 let station_at = |index: usize| {
78 recipients
79 .get(index)
80 .and_then(|(subscriber, _)| receivers.get(subscriber))
81 .and_then(|connection| stations.get(connection))
82 };
83 let first_at = |index: usize| {
86 station_at(index)
87 .filter(|station| !(0..index).any(|earlier| station_at(earlier) == Some(*station)))
88 .zip(recipients.get(index).map(|(_, queued_at)| *queued_at))
89 };
90 let named = (0..recipients.len())
91 .filter(|index| first_at(*index).is_some())
92 .count();
93 let list = gather(recipients.len(), named, first_at)?
94 .unwrap_or_else(|| Arc::clone(&self.shared.no_stations));
95 drop(stations);
96 drop(receivers);
97 Ok(list)
98 }
99
100 fn hops(
116 &self,
117 fact: &PublishFact<'_>,
118 seen_at: Instant,
119 station: Option<&Arc<str>>,
120 reached: Option<&[Reached]>,
121 failures: Option<&mut Vec<TapError>>,
122 ) -> Vec<Hop> {
123 let reached = reached.unwrap_or_default();
124 let appended_at = fact.recorded.and_then(|recorded| recorded.appended_at);
125 let depot = self.depot.as_ref().zip(appended_at);
126 let mut hops = Vec::with_capacity(
127 usize::from(station.is_some())
128 + usize::from(depot.is_some())
129 + usize::from(appended_at.is_some())
130 + reached.len(),
131 );
132 let mut early = None;
133 let mut overflow = None;
134 let mut out_of_order = None;
135 let mut place = 0;
136 let mut pass = |node: &Arc<str>, at: Option<Instant>| {
137 let hop = place;
138 place += 1;
139 let at_ms = match at {
140 None => 0,
141 Some(at) if at < seen_at => {
142 early.get_or_insert_with(|| {
143 elapsed_ms(seen_at.duration_since(at))
144 .map_or(TapError::HopOverflow { hop }, |early_ms| {
145 TapError::HopBeforeFirstSight { hop, early_ms }
146 })
147 });
148 return;
149 }
150 Some(at) => {
151 let Some(at_ms) = elapsed_ms(at.duration_since(seen_at)) else {
152 overflow.get_or_insert(TapError::HopOverflow { hop });
153 return;
154 };
155 at_ms
156 }
157 };
158 if let Some(before) = hops.last().map(|kept: &Hop| kept.at_ms)
159 && at_ms < before
160 {
161 out_of_order.get_or_insert(TapError::HopsOutOfOrder {
162 hop,
163 at_ms,
164 before_ms: before,
165 });
166 }
167 hops.push(Hop {
168 node: Arc::clone(node),
169 at_ms,
170 });
171 };
172 if let Some(station) = station {
173 pass(station, None);
174 }
175 if let Some((depot, appended_at)) = depot {
176 pass(depot, Some(appended_at));
177 }
178 if let Some(appended_at) = appended_at {
179 pass(&self.node, Some(appended_at));
180 }
181 for reached in reached {
182 pass(&reached.station, Some(reached.queued_at));
183 }
184 if let Some(failures) = failures {
185 failures.extend([early, overflow, out_of_order].into_iter().flatten());
186 }
187 hops
188 }
189
190 fn keep(
191 &self,
192 fact: &PublishFact<'_>,
193 observation: u64,
194 kept: &mut bool,
195 host: Option<&str>,
196 ) -> Result<(), TapError> {
197 let mut seen_at = None;
198 let mut station = None;
200 let mut to_stations = None;
201 let mut failures = Vec::new();
205 let mut hops_reported = false;
206 let subscribers = lock(&self.shared.subscribers, "tap subscribers")?;
207 for subscriber in subscribers.iter() {
208 if !subscriber.filter.matches(fact.subject) {
209 continue;
210 }
211 let mut state = lock(&subscriber.state, "tap subscriber")?;
212 if !state.admits() {
213 continue;
214 }
215 let one_in = state.one_in;
216 if station.is_none() {
217 station = Some(match host {
218 Some(host) => Some(Arc::from(format!("liminal.{host}"))),
219 None => self.station_of(fact.source)?,
220 });
221 to_stations = Some(
222 match fact
223 .recorded
224 .map(|recorded| self.stations_of(recorded.recipients))
225 {
226 Some(Ok(list)) => Some(list),
227 Some(Err(error @ TapError::StationsDisagree { .. })) => {
229 failures.push(error);
230 None
231 }
232 Some(Err(error)) => return Err(error),
233 None => None,
234 },
235 );
236 }
237 let first_sight = *seen_at.get_or_insert_with(|| {
240 fact.recorded
241 .map_or_else(Instant::now, |recorded| recorded.received_at)
242 });
243 let hops = self.hops(
246 fact,
247 first_sight,
248 station.as_ref().and_then(Option::as_ref),
249 to_stations.as_ref().and_then(Option::as_deref),
250 (!hops_reported).then_some(&mut failures),
251 );
252 hops_reported = true;
253 let message = TapMessage {
254 ident: fact
255 .message_id
256 .map_or(TapIdent::Observation(observation), TapIdent::Message),
257 subject: fact.subject.to_owned(),
258 size: u64::try_from(fact.payload.len()).unwrap_or(u64::MAX),
259 outcome: fact.outcome,
260 seen_at: first_sight,
261 source: fact.source,
262 station: station.clone().flatten(),
263 to_stations: to_stations.clone().flatten(),
264 hops,
265 reply_to: fact.reply_to.map(str::to_owned),
266 held: false,
267 call: None,
268 payload: subscriber.grant.map(|_| fact.payload.to_vec()),
269 };
270 if state.ring.push(Admitted { one_in, message }) {
271 self.shared.dropped_total.fetch_add(1, Ordering::Relaxed);
272 }
273 state.after_push();
274 drop(state);
275 *kept = true;
276 }
277 drop(subscribers);
278 match failures.len() {
279 0 => Ok(()),
280 1 => failures.pop().map_or(Ok(()), Err),
281 _ => Err(TapError::Several(failures)),
282 }
283 }
284}