1use std::{
2 collections::{BTreeMap, HashMap, VecDeque},
3 fmt,
4 sync::atomic::{AtomicU64, Ordering},
5 task::{Poll, ready},
6};
7
8use rand::RngExt;
9use web_async::Lock;
10
11use super::BroadcastConsumer;
12use crate::{
13 AsPath, Broadcast, BroadcastProducer, Error, Path, PathOwned, PathPrefixes,
14 coding::{Decode, DecodeError, Encode, EncodeError},
15};
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
25pub struct Origin {
26 pub id: u64,
28}
29
30impl Origin {
31 pub(crate) const UNKNOWN: Self = Self { id: 0 };
34
35 pub fn random() -> Self {
44 let mut rng = rand::rng();
45 let id = rng.random_range(1..(1u64 << 53));
46 Self { id }
47 }
48
49 pub fn produce(self) -> OriginProducer {
51 OriginProducer::new(self)
52 }
53}
54
55impl From<u64> for Origin {
56 fn from(id: u64) -> Self {
57 Self { id }
58 }
59}
60
61impl fmt::Display for Origin {
62 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63 self.id.fmt(f)
64 }
65}
66
67impl<V: Copy> Encode<V> for Origin
68where
69 u64: Encode<V>,
70{
71 fn encode<W: bytes::BufMut>(&self, w: &mut W, version: V) -> Result<(), EncodeError> {
72 self.id.encode(w, version)
73 }
74}
75
76impl<V: Copy> Decode<V> for Origin
77where
78 u64: Decode<V>,
79{
80 fn decode<R: bytes::Buf>(r: &mut R, version: V) -> Result<Self, DecodeError> {
81 let id = u64::decode(r, version)?;
82 if id >= 1u64 << 62 {
83 return Err(DecodeError::InvalidValue);
84 }
85 Ok(Self { id })
86 }
87}
88
89pub(crate) const MAX_HOPS: usize = 32;
95
96#[derive(Debug, Clone, Default, PartialEq, Eq)]
101#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
102pub struct OriginList(Vec<Origin>);
103
104#[derive(Debug, Clone, Copy, PartialEq, Eq)]
106#[non_exhaustive]
107pub struct TooManyOrigins;
108
109impl fmt::Display for TooManyOrigins {
110 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111 write!(f, "too many origins (max {MAX_HOPS})")
112 }
113}
114
115impl std::error::Error for TooManyOrigins {}
116
117impl From<TooManyOrigins> for DecodeError {
118 fn from(_: TooManyOrigins) -> Self {
119 DecodeError::BoundsExceeded
120 }
121}
122
123impl OriginList {
124 pub fn new() -> Self {
126 Self(Vec::new())
127 }
128
129 pub fn push(&mut self, origin: Origin) -> Result<(), TooManyOrigins> {
131 if self.0.len() >= MAX_HOPS {
132 return Err(TooManyOrigins);
133 }
134 self.0.push(origin);
135 Ok(())
136 }
137
138 pub fn replace_first(&mut self, target: Origin, replacement: Origin) -> bool {
141 for entry in &mut self.0 {
142 if *entry == target {
143 *entry = replacement;
144 return true;
145 }
146 }
147 false
148 }
149
150 pub fn contains(&self, origin: &Origin) -> bool {
152 self.0.contains(origin)
153 }
154
155 pub fn len(&self) -> usize {
157 self.0.len()
158 }
159
160 pub fn is_empty(&self) -> bool {
162 self.0.is_empty()
163 }
164
165 pub fn iter(&self) -> std::slice::Iter<'_, Origin> {
167 self.0.iter()
168 }
169
170 pub fn as_slice(&self) -> &[Origin] {
172 &self.0
173 }
174}
175
176impl TryFrom<Vec<Origin>> for OriginList {
177 type Error = TooManyOrigins;
178
179 fn try_from(v: Vec<Origin>) -> Result<Self, Self::Error> {
180 if v.len() > MAX_HOPS {
181 return Err(TooManyOrigins);
182 }
183 Ok(Self(v))
184 }
185}
186
187impl<'a> IntoIterator for &'a OriginList {
188 type Item = &'a Origin;
189 type IntoIter = std::slice::Iter<'a, Origin>;
190
191 fn into_iter(self) -> Self::IntoIter {
192 self.iter()
193 }
194}
195
196impl<V: Copy> Encode<V> for OriginList
197where
198 u64: Encode<V>,
199 Origin: Encode<V>,
200{
201 fn encode<W: bytes::BufMut>(&self, w: &mut W, version: V) -> Result<(), EncodeError> {
202 (self.0.len() as u64).encode(w, version)?;
203 for origin in &self.0 {
204 origin.encode(w, version)?;
205 }
206 Ok(())
207 }
208}
209
210impl<V: Copy> Decode<V> for OriginList
211where
212 u64: Decode<V>,
213 Origin: Decode<V>,
214{
215 fn decode<R: bytes::Buf>(r: &mut R, version: V) -> Result<Self, DecodeError> {
216 let count = u64::decode(r, version)? as usize;
217 if count > MAX_HOPS {
218 return Err(DecodeError::BoundsExceeded);
219 }
220 let mut list = Vec::with_capacity(count);
221 for _ in 0..count {
222 list.push(Origin::decode(r, version)?);
223 }
224 Ok(Self(list))
225 }
226}
227
228static NEXT_CONSUMER_ID: AtomicU64 = AtomicU64::new(0);
229
230#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
231struct ConsumerId(u64);
232
233impl ConsumerId {
234 fn new() -> Self {
235 Self(NEXT_CONSUMER_ID.fetch_add(1, Ordering::Relaxed))
236 }
237}
238
239struct OriginBroadcast {
241 path: PathOwned,
242 active: BroadcastConsumer,
243 backup: VecDeque<BroadcastConsumer>,
244}
245
246fn route_key(name: &Path, hops: &OriginList) -> (usize, u64) {
254 const SEED: u64 = 0x420C0DECB00B; const FNV_PRIME: u64 = 0x0000_0100_0000_01b3;
261
262 let mut hash = SEED;
263 for &byte in name.as_str().as_bytes() {
264 hash = (hash ^ u64::from(byte)).wrapping_mul(FNV_PRIME);
265 }
266 for hop in hops {
267 for &byte in &hop.id.to_le_bytes() {
268 hash = (hash ^ u64::from(byte)).wrapping_mul(FNV_PRIME);
269 }
270 }
271
272 (hops.len(), hash)
273}
274
275enum PendingUpdate {
284 Announce(BroadcastConsumer),
285 Unannounce,
286 UnannounceAnnounce(BroadcastConsumer),
287}
288
289#[derive(Default)]
294struct OriginConsumerState {
295 pending: BTreeMap<PathOwned, PendingUpdate>,
296}
297
298impl OriginConsumerState {
299 fn apply_announce(&mut self, path: PathOwned, broadcast: BroadcastConsumer) {
300 let new = match self.pending.remove(&path) {
301 None | Some(PendingUpdate::Announce(_)) => PendingUpdate::Announce(broadcast),
303 Some(PendingUpdate::Unannounce | PendingUpdate::UnannounceAnnounce(_)) => {
305 PendingUpdate::UnannounceAnnounce(broadcast)
306 }
307 };
308 self.pending.insert(path, new);
309 }
310
311 fn apply_unannounce(&mut self, path: PathOwned) {
312 match self.pending.remove(&path) {
313 Some(PendingUpdate::Announce(_)) => {}
315 None | Some(PendingUpdate::Unannounce) => {
316 self.pending.insert(path, PendingUpdate::Unannounce);
317 }
318 Some(PendingUpdate::UnannounceAnnounce(_)) => {
321 self.pending.insert(path, PendingUpdate::Unannounce);
322 }
323 }
324 }
325
326 fn take(&mut self) -> Option<OriginAnnounce> {
328 let path = self.pending.keys().next()?.clone();
329 match self.pending.remove(&path).unwrap() {
330 PendingUpdate::Announce(broadcast) => Some((path, Some(broadcast))),
331 PendingUpdate::Unannounce => Some((path, None)),
332 PendingUpdate::UnannounceAnnounce(broadcast) => {
333 self.pending.insert(path.clone(), PendingUpdate::Announce(broadcast));
336 Some((path, None))
337 }
338 }
339 }
340}
341
342#[derive(Clone)]
343struct OriginConsumerNotify {
344 root: PathOwned,
345 state: kio::Producer<OriginConsumerState>,
346}
347
348impl OriginConsumerNotify {
349 fn announce(&self, path: impl AsPath, broadcast: BroadcastConsumer) {
350 let path = path.as_path().strip_prefix(&self.root).unwrap().to_owned();
351 self.state
352 .write()
353 .ok()
354 .expect("consumer closed")
355 .apply_announce(path, broadcast);
356 }
357
358 fn reannounce(&self, path: impl AsPath, broadcast: BroadcastConsumer) {
359 let path = path.as_path().strip_prefix(&self.root).unwrap().to_owned();
360 let mut state = self.state.write().ok().expect("consumer closed");
361 state.apply_unannounce(path.clone());
362 state.apply_announce(path, broadcast);
363 }
364
365 fn unannounce(&self, path: impl AsPath) {
366 let path = path.as_path().strip_prefix(&self.root).unwrap().to_owned();
367 self.state.write().ok().expect("consumer closed").apply_unannounce(path);
368 }
369}
370
371struct NotifyNode {
372 parent: Option<Lock<NotifyNode>>,
373
374 consumers: HashMap<ConsumerId, OriginConsumerNotify>,
377}
378
379impl NotifyNode {
380 fn new(parent: Option<Lock<NotifyNode>>) -> Self {
381 Self {
382 parent,
383 consumers: HashMap::new(),
384 }
385 }
386
387 fn announce(&mut self, path: impl AsPath, broadcast: &BroadcastConsumer) {
388 for consumer in self.consumers.values() {
389 consumer.announce(path.as_path(), broadcast.clone());
390 }
391
392 if let Some(parent) = &self.parent {
393 parent.lock().announce(path, broadcast);
394 }
395 }
396
397 fn reannounce(&mut self, path: impl AsPath, broadcast: &BroadcastConsumer) {
398 for consumer in self.consumers.values() {
399 consumer.reannounce(path.as_path(), broadcast.clone());
400 }
401
402 if let Some(parent) = &self.parent {
403 parent.lock().reannounce(path, broadcast);
404 }
405 }
406
407 fn unannounce(&mut self, path: impl AsPath) {
408 for consumer in self.consumers.values() {
409 consumer.unannounce(path.as_path());
410 }
411
412 if let Some(parent) = &self.parent {
413 parent.lock().unannounce(path);
414 }
415 }
416}
417
418struct OriginNode {
419 broadcast: Option<OriginBroadcast>,
421
422 nested: HashMap<String, Lock<OriginNode>>,
424
425 notify: Lock<NotifyNode>,
427}
428
429impl OriginNode {
430 fn new(parent: Option<Lock<NotifyNode>>) -> Self {
431 Self {
432 broadcast: None,
433 nested: HashMap::new(),
434 notify: Lock::new(NotifyNode::new(parent)),
435 }
436 }
437
438 fn leaf(&mut self, path: &Path) -> Lock<OriginNode> {
439 let (dir, rest) = path.next_part().expect("leaf called with empty path");
440
441 let next = self.entry(dir);
442 if rest.is_empty() { next } else { next.lock().leaf(&rest) }
443 }
444
445 fn entry(&mut self, dir: &str) -> Lock<OriginNode> {
446 match self.nested.get(dir) {
447 Some(next) => next.clone(),
448 None => {
449 let next = Lock::new(OriginNode::new(Some(self.notify.clone())));
450 self.nested.insert(dir.to_string(), next.clone());
451 next
452 }
453 }
454 }
455
456 fn publish(&mut self, full: impl AsPath, broadcast: &BroadcastConsumer, relative: impl AsPath) {
457 let full = full.as_path();
458 let rest = relative.as_path();
459
460 if let Some((dir, relative)) = rest.next_part() {
462 self.entry(dir).lock().publish(&full, broadcast, &relative);
464 } else if let Some(existing) = &mut self.broadcast {
465 if existing.active.is_clone(broadcast) || existing.backup.iter().any(|b| b.is_clone(broadcast)) {
473 return;
474 }
475
476 if route_key(&full, &broadcast.hops) < route_key(&full, &existing.active.hops) {
477 let old = existing.active.clone();
478 existing.active = broadcast.clone();
479 existing.backup.push_back(old);
480
481 self.notify.lock().reannounce(full, broadcast);
482 } else {
483 existing.backup.push_back(broadcast.clone());
486 }
487 } else {
488 self.broadcast = Some(OriginBroadcast {
490 path: full.to_owned(),
491 active: broadcast.clone(),
492 backup: VecDeque::new(),
493 });
494 self.notify.lock().announce(full, broadcast);
495 }
496 }
497
498 fn consume(&mut self, id: ConsumerId, mut notify: OriginConsumerNotify) {
499 self.consume_initial(&mut notify);
500 self.notify.lock().consumers.insert(id, notify);
501 }
502
503 fn consume_initial(&mut self, notify: &mut OriginConsumerNotify) {
504 if let Some(broadcast) = &self.broadcast {
505 notify.announce(&broadcast.path, broadcast.active.clone());
506 }
507
508 for nested in self.nested.values() {
510 nested.lock().consume_initial(notify);
511 }
512 }
513
514 fn consume_broadcast(&self, rest: impl AsPath) -> Option<BroadcastConsumer> {
515 let rest = rest.as_path();
516
517 if let Some((dir, rest)) = rest.next_part() {
518 let node = self.nested.get(dir)?.lock();
519 node.consume_broadcast(&rest)
520 } else {
521 self.broadcast.as_ref().map(|b| b.active.clone())
522 }
523 }
524
525 fn unconsume(&mut self, id: ConsumerId) {
526 self.notify.lock().consumers.remove(&id).expect("consumer not found");
527 if self.is_empty() {
528 }
531 }
532
533 fn remove(&mut self, full: impl AsPath, broadcast: BroadcastConsumer, relative: impl AsPath) {
535 let full = full.as_path();
536 let relative = relative.as_path();
537
538 if let Some((dir, relative)) = relative.next_part() {
539 let nested = self.entry(dir);
540 let mut locked = nested.lock();
541 locked.remove(&full, broadcast, &relative);
542
543 if locked.is_empty() {
544 drop(locked);
545 self.nested.remove(dir);
546 }
547 } else {
548 let entry = match &mut self.broadcast {
549 Some(existing) => existing,
550 None => return,
551 };
552
553 let pos = entry.backup.iter().position(|b| b.is_clone(&broadcast));
555 if let Some(pos) = pos {
556 entry.backup.remove(pos);
557 return;
559 }
560
561 assert!(entry.active.is_clone(&broadcast));
563
564 let best = entry
567 .backup
568 .iter()
569 .enumerate()
570 .min_by_key(|(_, b)| route_key(&full, &b.hops))
571 .map(|(i, _)| i);
572 if let Some(idx) = best {
573 let active = entry.backup.remove(idx).expect("index in range");
574 entry.active = active;
575 self.notify.lock().reannounce(full, &entry.active);
576 } else {
577 self.broadcast = None;
579 self.notify.lock().unannounce(full);
580 }
581 }
582 }
583
584 fn is_empty(&self) -> bool {
585 self.broadcast.is_none() && self.nested.is_empty() && self.notify.lock().consumers.is_empty()
586 }
587}
588
589#[derive(Clone)]
590struct OriginNodes {
591 nodes: Vec<(PathOwned, Lock<OriginNode>)>,
592}
593
594impl OriginNodes {
595 pub fn select(&self, prefixes: &PathPrefixes) -> Option<Self> {
598 let mut roots = Vec::new();
599
600 for (root, state) in &self.nodes {
601 for prefix in prefixes {
602 if root.has_prefix(prefix) {
603 roots.push((root.to_owned(), state.clone()));
605 continue;
606 }
607
608 if let Some(suffix) = prefix.strip_prefix(root) {
609 let nested = state.lock().leaf(&suffix);
611 roots.push((prefix.to_owned(), nested));
612 }
613 }
614 }
615
616 if roots.is_empty() {
617 None
618 } else {
619 Some(Self { nodes: roots })
620 }
621 }
622
623 pub fn root(&self, new_root: impl AsPath) -> Option<Self> {
624 let new_root = new_root.as_path();
625 let mut roots = Vec::new();
626
627 if new_root.is_empty() {
628 return Some(self.clone());
629 }
630
631 for (root, state) in &self.nodes {
632 if let Some(suffix) = root.strip_prefix(&new_root) {
633 roots.push((suffix.to_owned(), state.clone()));
635 } else if let Some(suffix) = new_root.strip_prefix(root) {
636 let nested = state.lock().leaf(&suffix);
639 roots.push(("".into(), nested));
640 }
641 }
642
643 if roots.is_empty() {
644 None
645 } else {
646 Some(Self { nodes: roots })
647 }
648 }
649
650 pub fn get(&self, path: impl AsPath) -> Option<(Lock<OriginNode>, PathOwned)> {
652 let path = path.as_path();
653
654 for (root, state) in &self.nodes {
655 if let Some(suffix) = path.strip_prefix(root) {
656 return Some((state.clone(), suffix.to_owned()));
657 }
658 }
659
660 None
661 }
662}
663
664impl Default for OriginNodes {
665 fn default() -> Self {
666 Self {
667 nodes: vec![("".into(), Lock::new(OriginNode::new(None)))],
668 }
669 }
670}
671
672pub type OriginAnnounce = (PathOwned, Option<BroadcastConsumer>);
674
675#[derive(Clone)]
677pub struct OriginProducer {
678 info: Origin,
682
683 nodes: OriginNodes,
686
687 root: PathOwned,
689
690 dynamic: kio::Producer<OriginDynamicState>,
694}
695
696impl std::ops::Deref for OriginProducer {
697 type Target = Origin;
698
699 fn deref(&self) -> &Self::Target {
700 &self.info
701 }
702}
703
704impl OriginProducer {
705 pub fn new(info: Origin) -> Self {
708 Self {
709 info,
710 nodes: OriginNodes::default(),
711 root: PathOwned::default(),
712 dynamic: kio::Producer::default(),
713 }
714 }
715
716 pub fn create_broadcast(&self, path: impl AsPath) -> Option<BroadcastProducer> {
721 let broadcast = Broadcast::new().produce();
722 self.publish_broadcast(path, broadcast.consume()).then_some(broadcast)
723 }
724
725 pub fn publish_broadcast(&self, path: impl AsPath, broadcast: BroadcastConsumer) -> bool {
738 let path = path.as_path();
739
740 if broadcast.hops.contains(&self.info) {
742 return false;
743 }
744
745 let (root, rest) = match self.nodes.get(&path) {
746 Some(root) => root,
747 None => return false,
748 };
749
750 let full = self.root.join(&path);
751
752 if full.parts().count() > Path::MAX_PARTS {
756 return false;
757 }
758
759 root.lock().publish(&full, &broadcast, &rest);
760 let root = root.clone();
761
762 web_async::spawn(async move {
763 broadcast.closed().await;
764 root.lock().remove(&full, broadcast, &rest);
765 });
766
767 true
768 }
769
770 pub fn scope(&self, prefixes: &[Path]) -> Option<OriginProducer> {
776 let prefixes = PathPrefixes::new(prefixes);
777 Some(OriginProducer {
778 info: self.info,
779 nodes: self.nodes.select(&prefixes)?,
780 root: self.root.clone(),
781 dynamic: self.dynamic.clone(),
782 })
783 }
784
785 pub fn dynamic(&self) -> OriginDynamic {
794 OriginDynamic::new(self.info, self.root.clone(), self.dynamic.clone())
795 }
796
797 pub fn consume(&self) -> OriginConsumer {
799 OriginConsumer::new(self.info, self.root.clone(), self.nodes.clone(), self.dynamic.consume())
800 }
801
802 #[deprecated(note = "use `consume().get_broadcast(path)` once `consume()` is cheap")]
807 pub fn get_broadcast(&self, path: impl AsPath) -> Option<BroadcastConsumer> {
808 let path = path.as_path();
809 let (root, rest) = self.nodes.get(&path)?;
810 let state = root.lock();
811 state.consume_broadcast(&rest)
812 }
813
814 pub fn with_root(&self, prefix: impl AsPath) -> Option<Self> {
819 let prefix = prefix.as_path();
820
821 Some(Self {
822 info: self.info,
823 root: self.root.join(&prefix).to_owned(),
824 nodes: self.nodes.root(&prefix)?,
825 dynamic: self.dynamic.clone(),
826 })
827 }
828
829 pub fn root(&self) -> &Path<'_> {
831 &self.root
832 }
833
834 pub fn allowed(&self) -> impl Iterator<Item = &Path<'_>> {
837 self.nodes.nodes.iter().map(|(root, _)| root)
838 }
839
840 pub fn absolute(&self, path: impl AsPath) -> Path<'_> {
842 self.root.join(path)
843 }
844}
845
846pub struct OriginConsumer {
850 id: ConsumerId,
851 info: Origin,
853 nodes: OriginNodes,
854
855 state: kio::Producer<OriginConsumerState>,
858
859 root: PathOwned,
861
862 dynamic: kio::Consumer<OriginDynamicState>,
865}
866
867impl std::ops::Deref for OriginConsumer {
868 type Target = Origin;
869
870 fn deref(&self) -> &Self::Target {
871 &self.info
872 }
873}
874
875impl OriginConsumer {
876 fn new(info: Origin, root: PathOwned, nodes: OriginNodes, dynamic: kio::Consumer<OriginDynamicState>) -> Self {
877 let state = kio::Producer::<OriginConsumerState>::default();
878 let id = ConsumerId::new();
879
880 for (_, node) in &nodes.nodes {
881 let notify = OriginConsumerNotify {
882 root: root.clone(),
883 state: state.clone(),
884 };
885 node.lock().consume(id, notify);
886 }
887
888 Self {
889 id,
890 info,
891 nodes,
892 state,
893 root,
894 dynamic,
895 }
896 }
897
898 pub async fn announced(&mut self) -> Option<OriginAnnounce> {
906 kio::wait(|waiter| self.poll_announced(waiter)).await
907 }
908
909 pub fn poll_announced(&mut self, waiter: &kio::Waiter) -> Poll<Option<OriginAnnounce>> {
915 let mut state = match ready!(self.state.poll(waiter, |state| {
916 if state.pending.is_empty() {
917 Poll::Pending
918 } else {
919 Poll::Ready(())
920 }
921 })) {
922 Ok(state) => state,
923 Err(_) => return Poll::Ready(None),
925 };
926 Poll::Ready(Some(state.take().expect("predicate guaranteed an update")))
927 }
928
929 pub fn try_announced(&mut self) -> Option<OriginAnnounce> {
934 self.state.write().ok()?.take()
935 }
936
937 pub fn consume(&self) -> Self {
939 self.clone()
940 }
941
942 pub fn get_broadcast(&self, path: impl AsPath) -> Option<BroadcastConsumer> {
950 let path = path.as_path();
951 let (root, rest) = self.nodes.get(&path)?;
952 let state = root.lock();
953 state.consume_broadcast(&rest)
954 }
955
956 pub async fn announced_broadcast(&self, path: impl AsPath) -> Option<BroadcastConsumer> {
965 let path = path.as_path();
966
967 let mut consumer = self.scope(std::slice::from_ref(&path))?;
969
970 if !consumer.allowed().any(|allowed| path.has_prefix(allowed)) {
974 return None;
975 }
976
977 loop {
978 let (announced, broadcast) = consumer.announced().await?;
979 if announced.as_path() == path {
981 if let Some(broadcast) = broadcast {
982 return Some(broadcast);
983 }
984 }
985 }
986 }
987
988 pub fn scope(&self, prefixes: &[Path]) -> Option<OriginConsumer> {
994 let prefixes = PathPrefixes::new(prefixes);
995 Some(OriginConsumer::new(
996 self.info,
997 self.root.clone(),
998 self.nodes.select(&prefixes)?,
999 self.dynamic.clone(),
1000 ))
1001 }
1002
1003 pub fn with_root(&self, prefix: impl AsPath) -> Option<Self> {
1008 let prefix = prefix.as_path();
1009
1010 Some(Self::new(
1011 self.info,
1012 self.root.join(&prefix).to_owned(),
1013 self.nodes.root(&prefix)?,
1014 self.dynamic.clone(),
1015 ))
1016 }
1017
1018 pub fn request_broadcast(&self, path: impl AsPath) -> kio::Pending<BroadcastRequested> {
1034 let path = path.as_path();
1035
1036 if let Some(broadcast) = self.get_broadcast(&path) {
1038 return kio::Pending::new(BroadcastRequested::ready(broadcast));
1039 }
1040
1041 let absolute = self.root.join(&path).to_owned();
1044
1045 let Ok(mut state) = self.dynamic.write() else {
1046 return kio::Pending::new(BroadcastRequested::failed(Error::Dropped));
1047 };
1048
1049 let consumer = if let Some(producer) = state.requests.get(&absolute) {
1051 producer.consume()
1052 } else {
1053 if state.dynamic == 0 {
1054 return kio::Pending::new(BroadcastRequested::failed(Error::Unroutable));
1055 }
1056
1057 let producer = kio::Producer::<PendingBroadcast>::default();
1058 let consumer = producer.consume();
1059 state.requests.insert(absolute.clone(), producer);
1060 state.request_order.push_back(absolute);
1061 consumer
1062 };
1063
1064 kio::Pending::new(BroadcastRequested::pending(consumer))
1065 }
1066
1067 pub fn root(&self) -> &Path<'_> {
1069 &self.root
1070 }
1071
1072 pub fn allowed(&self) -> impl Iterator<Item = &Path<'_>> {
1075 self.nodes.nodes.iter().map(|(root, _)| root)
1076 }
1077
1078 pub fn absolute(&self, path: impl AsPath) -> Path<'_> {
1080 self.root.join(path)
1081 }
1082}
1083
1084impl Drop for OriginConsumer {
1085 fn drop(&mut self) {
1086 for (_, root) in &self.nodes.nodes {
1087 root.lock().unconsume(self.id);
1088 }
1089 }
1090}
1091
1092impl Clone for OriginConsumer {
1093 fn clone(&self) -> Self {
1094 OriginConsumer::new(self.info, self.root.clone(), self.nodes.clone(), self.dynamic.clone())
1095 }
1096}
1097
1098#[derive(Default)]
1104struct OriginDynamicState {
1105 requests: HashMap<PathOwned, kio::Producer<PendingBroadcast>>,
1110
1111 request_order: VecDeque<PathOwned>,
1113
1114 dynamic: usize,
1117}
1118
1119impl OriginDynamicState {
1120 fn reject_requests(&mut self) {
1123 self.requests.clear();
1124 self.request_order.clear();
1125 }
1126}
1127
1128#[derive(Default)]
1135struct PendingBroadcast {
1136 resolved: Option<Result<BroadcastConsumer, Error>>,
1137}
1138
1139pub struct OriginDynamic {
1150 info: Origin,
1151 root: PathOwned,
1152 state: kio::Producer<OriginDynamicState>,
1153}
1154
1155impl Clone for OriginDynamic {
1156 fn clone(&self) -> Self {
1157 if let Ok(mut state) = self.state.write() {
1161 state.dynamic += 1;
1162 }
1163
1164 Self {
1165 info: self.info,
1166 root: self.root.clone(),
1167 state: self.state.clone(),
1168 }
1169 }
1170}
1171
1172impl OriginDynamic {
1173 fn new(info: Origin, root: PathOwned, state: kio::Producer<OriginDynamicState>) -> Self {
1174 if let Ok(mut state) = state.write() {
1175 state.dynamic += 1;
1176 }
1177
1178 Self { info, root, state }
1179 }
1180
1181 pub fn info(&self) -> &Origin {
1183 &self.info
1184 }
1185
1186 fn poll<F>(&self, waiter: &kio::Waiter, f: F) -> Poll<Result<kio::Mut<'_, OriginDynamicState>, Error>>
1188 where
1189 F: FnMut(&kio::Ref<'_, OriginDynamicState>) -> Poll<()>,
1190 {
1191 Poll::Ready(match ready!(self.state.poll(waiter, f)) {
1192 Ok(state) => Ok(state),
1193 Err(_) => Err(Error::Dropped),
1194 })
1195 }
1196
1197 pub fn poll_requested_broadcast(&mut self, waiter: &kio::Waiter) -> Poll<Result<BroadcastRequest, Error>> {
1199 let mut state = ready!(self.poll(waiter, |state| {
1200 if state.request_order.is_empty() {
1201 Poll::Pending
1202 } else {
1203 Poll::Ready(())
1204 }
1205 }))?;
1206
1207 let path = state.request_order.pop_front().expect("predicate guaranteed a request");
1208 let producer = state.requests.remove(&path).expect("request_order out of sync");
1209 Poll::Ready(Ok(BroadcastRequest { path, producer }))
1210 }
1211
1212 pub async fn requested_broadcast(&mut self) -> Result<BroadcastRequest, Error> {
1215 kio::wait(|waiter| self.poll_requested_broadcast(waiter)).await
1216 }
1217
1218 pub fn root(&self) -> &Path<'_> {
1220 &self.root
1221 }
1222}
1223
1224impl Drop for OriginDynamic {
1225 fn drop(&mut self) {
1226 if let Ok(mut state) = self.state.write() {
1227 state.dynamic = state.dynamic.saturating_sub(1);
1229 if state.dynamic == 0 {
1230 state.reject_requests();
1232 }
1233 }
1234 }
1235}
1236
1237pub struct BroadcastRequest {
1244 path: PathOwned,
1246
1247 producer: kio::Producer<PendingBroadcast>,
1250}
1251
1252impl BroadcastRequest {
1253 pub fn path(&self) -> &Path<'_> {
1255 &self.path
1256 }
1257
1258 pub fn accept(self, broadcast: BroadcastConsumer) {
1264 if let Ok(mut state) = self.producer.write() {
1265 state.resolved = Some(Ok(broadcast));
1266 }
1267 }
1269
1270 pub fn reject(self, err: Error) {
1272 if let Ok(mut state) = self.producer.write() {
1273 state.resolved = Some(Err(err));
1274 }
1275 }
1276}
1277
1278pub struct BroadcastRequested {
1285 inner: Requested,
1286}
1287
1288enum Requested {
1289 Ready(BroadcastConsumer),
1291 Failed(Error),
1294 Pending(kio::Consumer<PendingBroadcast>),
1296}
1297
1298impl BroadcastRequested {
1299 fn ready(broadcast: BroadcastConsumer) -> Self {
1300 Self {
1301 inner: Requested::Ready(broadcast),
1302 }
1303 }
1304
1305 fn failed(error: Error) -> Self {
1306 Self {
1307 inner: Requested::Failed(error),
1308 }
1309 }
1310
1311 fn pending(consumer: kio::Consumer<PendingBroadcast>) -> Self {
1312 Self {
1313 inner: Requested::Pending(consumer),
1314 }
1315 }
1316
1317 pub fn poll_ok(&self, waiter: &kio::Waiter) -> Poll<Result<BroadcastConsumer, Error>> {
1319 match &self.inner {
1320 Requested::Ready(broadcast) => Poll::Ready(Ok(broadcast.clone())),
1321 Requested::Failed(error) => Poll::Ready(Err(error.clone())),
1322 Requested::Pending(consumer) => Poll::Ready(
1323 match ready!(consumer.poll(waiter, |state| match &state.resolved {
1324 Some(result) => Poll::Ready(result.clone()),
1325 None => Poll::Pending,
1326 })) {
1327 Ok(result) => result,
1328 Err(_closed) => Err(Error::Unroutable),
1330 },
1331 ),
1332 }
1333 }
1334}
1335
1336impl kio::Future for BroadcastRequested {
1337 type Output = Result<BroadcastConsumer, Error>;
1338
1339 fn poll(&self, waiter: &kio::Waiter) -> Poll<Self::Output> {
1340 self.poll_ok(waiter)
1341 }
1342}
1343
1344#[cfg(test)]
1345use futures::FutureExt;
1346
1347#[cfg(test)]
1348impl OriginConsumer {
1349 pub fn assert_next(&mut self, expected: impl AsPath, broadcast: &BroadcastConsumer) {
1350 let expected = expected.as_path();
1351 let (path, active) = self.announced().now_or_never().expect("next blocked").expect("no next");
1352 assert_eq!(path, expected, "wrong path");
1353 assert!(active.unwrap().is_clone(broadcast), "should be the same broadcast");
1354 }
1355
1356 pub fn assert_try_next(&mut self, expected: impl AsPath, broadcast: &BroadcastConsumer) {
1357 let expected = expected.as_path();
1358 let (path, active) = self.try_announced().expect("no next");
1359 assert_eq!(path, expected, "wrong path");
1360 assert!(active.unwrap().is_clone(broadcast), "should be the same broadcast");
1361 }
1362
1363 pub fn assert_next_none(&mut self, expected: impl AsPath) {
1364 let expected = expected.as_path();
1365 let (path, active) = self.announced().now_or_never().expect("next blocked").expect("no next");
1366 assert_eq!(path, expected, "wrong path");
1367 assert!(active.is_none(), "should be unannounced");
1368 }
1369
1370 pub fn assert_next_wait(&mut self) {
1371 if let Some(res) = self.announced().now_or_never() {
1372 panic!("next should block: got {:?}", res.map(|(path, _)| path));
1373 }
1374 }
1375
1376 }
1385
1386#[cfg(test)]
1387mod tests {
1388 use futures::FutureExt;
1389
1390 use crate::Broadcast;
1391
1392 use super::*;
1393
1394 #[test]
1395 fn origin_list_push_fails_at_limit() {
1396 let mut list = OriginList::new();
1397 for _ in 0..MAX_HOPS {
1398 list.push(Origin::random()).unwrap();
1399 }
1400 assert_eq!(list.len(), MAX_HOPS);
1401 assert_eq!(list.push(Origin::random()), Err(TooManyOrigins));
1402 }
1403
1404 #[test]
1405 fn origin_list_replace_first() {
1406 let mut list = OriginList::new();
1407 for _ in 0..3 {
1408 list.push(Origin::UNKNOWN).unwrap();
1409 }
1410
1411 assert!(list.replace_first(Origin::UNKNOWN, Origin::from(7)));
1413 assert_eq!(list.as_slice(), &[Origin::from(7), Origin::UNKNOWN, Origin::UNKNOWN]);
1414
1415 assert!(!list.replace_first(Origin::from(99), Origin::from(8)));
1417 assert_eq!(list.len(), 3);
1418 }
1419
1420 #[test]
1421 fn origin_list_try_from_vec_enforces_limit() {
1422 let under: Vec<Origin> = (0..MAX_HOPS).map(|_| Origin::random()).collect();
1423 assert!(OriginList::try_from(under).is_ok());
1424
1425 let over: Vec<Origin> = (0..MAX_HOPS + 1).map(|_| Origin::random()).collect();
1426 assert_eq!(OriginList::try_from(over), Err(TooManyOrigins));
1427 }
1428
1429 #[tokio::test]
1430 async fn test_announce() {
1431 tokio::time::pause();
1432
1433 let origin = Origin::random().produce();
1434 let broadcast1 = Broadcast::new().produce();
1435 let broadcast2 = Broadcast::new().produce();
1436
1437 let mut consumer1 = origin.consume();
1438 consumer1.assert_next_wait();
1440
1441 origin.publish_broadcast("test1", broadcast1.consume());
1443
1444 consumer1.assert_next("test1", &broadcast1.consume());
1445 consumer1.assert_next_wait();
1446
1447 let mut consumer2 = origin.consume();
1450
1451 origin.publish_broadcast("test2", broadcast2.consume());
1453
1454 consumer1.assert_next("test2", &broadcast2.consume());
1455 consumer1.assert_next_wait();
1456
1457 consumer2.assert_next("test1", &broadcast1.consume());
1458 consumer2.assert_next("test2", &broadcast2.consume());
1459 consumer2.assert_next_wait();
1460
1461 drop(broadcast1);
1463
1464 tokio::time::sleep(tokio::time::Duration::from_millis(1)).await;
1466
1467 consumer1.assert_next_none("test1");
1469 consumer2.assert_next_none("test1");
1470 consumer1.assert_next_wait();
1471 consumer2.assert_next_wait();
1472
1473 let mut consumer3 = origin.consume();
1475 consumer3.assert_next("test2", &broadcast2.consume());
1476 consumer3.assert_next_wait();
1477
1478 drop(broadcast2);
1480
1481 tokio::time::sleep(tokio::time::Duration::from_millis(1)).await;
1483
1484 consumer1.assert_next_none("test2");
1485 consumer2.assert_next_none("test2");
1486 consumer3.assert_next_none("test2");
1487
1488 }
1494
1495 #[tokio::test]
1496 async fn test_duplicate() {
1497 tokio::time::pause();
1498
1499 let origin = Origin::random().produce();
1500
1501 let broadcast1 = Broadcast::new().produce();
1502 let broadcast2 = Broadcast::new().produce();
1503 let broadcast3 = Broadcast::new().produce();
1504
1505 let consumer1 = broadcast1.consume();
1506 let consumer2 = broadcast2.consume();
1507 let consumer3 = broadcast3.consume();
1508
1509 let mut consumer = origin.consume();
1510
1511 origin.publish_broadcast("test", consumer1.clone());
1512 origin.publish_broadcast("test", consumer2.clone());
1513 origin.publish_broadcast("test", consumer3.clone());
1514 assert!(consumer.get_broadcast("test").is_some());
1515
1516 consumer.assert_next("test", &consumer1);
1519 consumer.assert_next_wait();
1520
1521 drop(broadcast2);
1523
1524 tokio::time::sleep(tokio::time::Duration::from_millis(1)).await;
1526
1527 assert!(consumer.get_broadcast("test").is_some());
1528 consumer.assert_next_wait();
1529
1530 drop(broadcast1);
1532
1533 tokio::time::sleep(tokio::time::Duration::from_millis(1)).await;
1535
1536 assert!(consumer.get_broadcast("test").is_some());
1537 consumer.assert_next_none("test");
1538 consumer.assert_next("test", &consumer3);
1539
1540 drop(broadcast3);
1542
1543 tokio::time::sleep(tokio::time::Duration::from_millis(1)).await;
1545 assert!(consumer.get_broadcast("test").is_none());
1546
1547 consumer.assert_next_none("test");
1548 consumer.assert_next_wait();
1549 }
1550
1551 #[tokio::test]
1552 async fn test_duplicate_reverse() {
1553 tokio::time::pause();
1554
1555 let origin = Origin::random().produce();
1556 let broadcast1 = Broadcast::new().produce();
1557 let broadcast2 = Broadcast::new().produce();
1558
1559 origin.publish_broadcast("test", broadcast1.consume());
1560 origin.publish_broadcast("test", broadcast2.consume());
1561 assert!(origin.consume().get_broadcast("test").is_some());
1562
1563 drop(broadcast2);
1565
1566 tokio::time::sleep(tokio::time::Duration::from_millis(1)).await;
1568 assert!(origin.consume().get_broadcast("test").is_some());
1569
1570 drop(broadcast1);
1571
1572 tokio::time::sleep(tokio::time::Duration::from_millis(1)).await;
1574 assert!(origin.consume().get_broadcast("test").is_none());
1575 }
1576
1577 #[tokio::test]
1578 async fn test_deterministic_tiebreak() {
1579 tokio::time::pause();
1580
1581 fn route(ids: &[u64]) -> BroadcastProducer {
1583 let hops = OriginList::try_from(ids.iter().copied().map(Origin::from).collect::<Vec<_>>()).unwrap();
1584 Broadcast { hops }.produce()
1585 }
1586
1587 fn winner(first: &[u64], second: &[u64]) -> OriginList {
1589 let origin = Origin::random().produce();
1590 let a = route(first);
1591 let b = route(second);
1592 origin.publish_broadcast("test", a.consume());
1593 origin.publish_broadcast("test", b.consume());
1594 let hops = origin.consume().get_broadcast("test").unwrap().hops.clone();
1595 drop((a, b));
1597 hops
1598 }
1599
1600 let forward = winner(&[10, 20], &[30, 40]);
1603 let reverse = winner(&[30, 40], &[10, 20]);
1604 assert_eq!(forward, reverse, "tie-break must not depend on publish order");
1605
1606 assert_eq!(winner(&[10, 20], &[30]).len(), 1);
1608 assert_eq!(winner(&[30], &[10, 20]).len(), 1);
1609 }
1610
1611 #[tokio::test]
1612 async fn test_double_publish() {
1613 tokio::time::pause();
1614
1615 let origin = Origin::random().produce();
1616 let broadcast = Broadcast::new().produce();
1617
1618 origin.publish_broadcast("test", broadcast.consume());
1620 origin.publish_broadcast("test", broadcast.consume());
1621
1622 assert!(origin.consume().get_broadcast("test").is_some());
1623
1624 drop(broadcast);
1625
1626 tokio::time::sleep(tokio::time::Duration::from_millis(1)).await;
1628 assert!(origin.consume().get_broadcast("test").is_none());
1629 }
1630 #[tokio::test]
1635 async fn test_many_announces() {
1636 let origin = Origin::random().produce();
1637 let broadcast = Broadcast::new().produce();
1638
1639 let mut consumer = origin.consume();
1640 for i in 0..256 {
1641 origin.publish_broadcast(format!("test{i:03}"), broadcast.consume());
1642 }
1643
1644 for i in 0..256 {
1645 consumer.assert_next(format!("test{i:03}"), &broadcast.consume());
1646 }
1647 consumer.assert_next_wait();
1648 }
1649
1650 #[tokio::test]
1651 async fn test_many_announces_try() {
1652 let origin = Origin::random().produce();
1653 let broadcast = Broadcast::new().produce();
1654
1655 let mut consumer = origin.consume();
1656 for i in 0..256 {
1657 origin.publish_broadcast(format!("test{i:03}"), broadcast.consume());
1658 }
1659
1660 for i in 0..256 {
1661 consumer.assert_try_next(format!("test{i:03}"), &broadcast.consume());
1662 }
1663 }
1664
1665 #[tokio::test]
1666 async fn test_with_root_basic() {
1667 let origin = Origin::random().produce();
1668 let broadcast = Broadcast::new().produce();
1669
1670 let foo_producer = origin.with_root("foo").expect("should create root");
1672 assert_eq!(foo_producer.root().as_str(), "foo");
1673
1674 let mut consumer = origin.consume();
1675
1676 assert!(foo_producer.publish_broadcast("bar/baz", broadcast.consume()));
1678 consumer.assert_next("foo/bar/baz", &broadcast.consume());
1680
1681 let mut foo_consumer = foo_producer.consume();
1683 foo_consumer.assert_next("bar/baz", &broadcast.consume());
1684 }
1685
1686 #[tokio::test]
1687 async fn test_with_root_nested() {
1688 let origin = Origin::random().produce();
1689 let broadcast = Broadcast::new().produce();
1690
1691 let foo_producer = origin.with_root("foo").expect("should create foo root");
1693 let foo_bar_producer = foo_producer.with_root("bar").expect("should create bar root");
1694 assert_eq!(foo_bar_producer.root().as_str(), "foo/bar");
1695
1696 let mut consumer = origin.consume();
1697
1698 assert!(foo_bar_producer.publish_broadcast("baz", broadcast.consume()));
1700 consumer.assert_next("foo/bar/baz", &broadcast.consume());
1702
1703 let mut foo_bar_consumer = foo_bar_producer.consume();
1705 foo_bar_consumer.assert_next("baz", &broadcast.consume());
1706 }
1707
1708 #[tokio::test]
1709 async fn test_publish_scope_allows() {
1710 let origin = Origin::random().produce();
1711 let broadcast = Broadcast::new().produce();
1712
1713 let limited_producer = origin
1715 .scope(&["allowed/path1".into(), "allowed/path2".into()])
1716 .expect("should create limited producer");
1717
1718 assert!(limited_producer.publish_broadcast("allowed/path1", broadcast.consume()));
1720 assert!(limited_producer.publish_broadcast("allowed/path1/nested", broadcast.consume()));
1721 assert!(limited_producer.publish_broadcast("allowed/path2", broadcast.consume()));
1722
1723 assert!(!limited_producer.publish_broadcast("notallowed", broadcast.consume()));
1725 assert!(!limited_producer.publish_broadcast("allowed", broadcast.consume())); assert!(!limited_producer.publish_broadcast("other/path", broadcast.consume()));
1727 }
1728
1729 #[tokio::test]
1730 async fn test_publish_max_parts() {
1731 let origin = Origin::random().produce();
1732 let broadcast = Broadcast::new().produce();
1733
1734 let at_limit = (0..Path::MAX_PARTS)
1735 .map(|i| i.to_string())
1736 .collect::<Vec<_>>()
1737 .join("/");
1738 assert!(origin.publish_broadcast(at_limit.as_str(), broadcast.consume()));
1739
1740 let too_deep = format!("{at_limit}/extra");
1741 assert!(!origin.publish_broadcast(too_deep.as_str(), broadcast.consume()));
1742
1743 let rooted = origin.with_root("root").expect("wildcard allows any root");
1745 assert!(!rooted.publish_broadcast(at_limit.as_str(), broadcast.consume()));
1746 }
1747
1748 #[tokio::test]
1749 async fn test_publish_scope_empty() {
1750 let origin = Origin::random().produce();
1751
1752 assert!(origin.scope(&[]).is_none());
1754 }
1755
1756 #[tokio::test]
1757 async fn test_consume_scope_filters() {
1758 let origin = Origin::random().produce();
1759 let broadcast1 = Broadcast::new().produce();
1760 let broadcast2 = Broadcast::new().produce();
1761 let broadcast3 = Broadcast::new().produce();
1762
1763 let mut consumer = origin.consume();
1764
1765 origin.publish_broadcast("allowed", broadcast1.consume());
1767 origin.publish_broadcast("allowed/nested", broadcast2.consume());
1768 origin.publish_broadcast("notallowed", broadcast3.consume());
1769
1770 let mut limited_consumer = origin
1772 .consume()
1773 .scope(&["allowed".into()])
1774 .expect("should create limited consumer");
1775
1776 limited_consumer.assert_next("allowed", &broadcast1.consume());
1778 limited_consumer.assert_next("allowed/nested", &broadcast2.consume());
1779 limited_consumer.assert_next_wait(); consumer.assert_next("allowed", &broadcast1.consume());
1783 consumer.assert_next("allowed/nested", &broadcast2.consume());
1784 consumer.assert_next("notallowed", &broadcast3.consume());
1785 }
1786
1787 #[tokio::test]
1788 async fn test_consume_scope_multiple_prefixes() {
1789 let origin = Origin::random().produce();
1790 let broadcast1 = Broadcast::new().produce();
1791 let broadcast2 = Broadcast::new().produce();
1792 let broadcast3 = Broadcast::new().produce();
1793
1794 origin.publish_broadcast("foo/test", broadcast1.consume());
1795 origin.publish_broadcast("bar/test", broadcast2.consume());
1796 origin.publish_broadcast("baz/test", broadcast3.consume());
1797
1798 let mut limited_consumer = origin
1800 .consume()
1801 .scope(&["foo".into(), "bar".into()])
1802 .expect("should create limited consumer");
1803
1804 limited_consumer.assert_next("bar/test", &broadcast2.consume());
1806 limited_consumer.assert_next("foo/test", &broadcast1.consume());
1807 limited_consumer.assert_next_wait(); }
1809
1810 #[tokio::test]
1811 async fn test_with_root_and_publish_scope() {
1812 let origin = Origin::random().produce();
1813 let broadcast = Broadcast::new().produce();
1814
1815 let foo_producer = origin.with_root("foo").expect("should create foo root");
1817
1818 let limited_producer = foo_producer
1820 .scope(&["bar".into(), "goop/pee".into()])
1821 .expect("should create limited producer");
1822
1823 let mut consumer = origin.consume();
1824
1825 assert!(limited_producer.publish_broadcast("bar", broadcast.consume()));
1827 assert!(limited_producer.publish_broadcast("bar/nested", broadcast.consume()));
1828 assert!(limited_producer.publish_broadcast("goop/pee", broadcast.consume()));
1829 assert!(limited_producer.publish_broadcast("goop/pee/nested", broadcast.consume()));
1830
1831 assert!(!limited_producer.publish_broadcast("baz", broadcast.consume()));
1833 assert!(!limited_producer.publish_broadcast("goop", broadcast.consume())); assert!(!limited_producer.publish_broadcast("goop/other", broadcast.consume()));
1835
1836 consumer.assert_next("foo/bar", &broadcast.consume());
1838 consumer.assert_next("foo/bar/nested", &broadcast.consume());
1839 consumer.assert_next("foo/goop/pee", &broadcast.consume());
1840 consumer.assert_next("foo/goop/pee/nested", &broadcast.consume());
1841 }
1842
1843 #[tokio::test]
1844 async fn test_with_root_and_consume_scope() {
1845 let origin = Origin::random().produce();
1846 let broadcast1 = Broadcast::new().produce();
1847 let broadcast2 = Broadcast::new().produce();
1848 let broadcast3 = Broadcast::new().produce();
1849
1850 origin.publish_broadcast("foo/bar/test", broadcast1.consume());
1852 origin.publish_broadcast("foo/goop/pee/test", broadcast2.consume());
1853 origin.publish_broadcast("foo/other/test", broadcast3.consume());
1854
1855 let foo_producer = origin.with_root("foo").expect("should create foo root");
1857
1858 let mut limited_consumer = foo_producer
1860 .consume()
1861 .scope(&["bar".into(), "goop/pee".into()])
1862 .expect("should create limited consumer");
1863
1864 limited_consumer.assert_next("bar/test", &broadcast1.consume());
1866 limited_consumer.assert_next("goop/pee/test", &broadcast2.consume());
1867 limited_consumer.assert_next_wait(); }
1869
1870 #[tokio::test]
1871 async fn test_with_root_unauthorized() {
1872 let origin = Origin::random().produce();
1873
1874 let limited_producer = origin
1876 .scope(&["allowed".into()])
1877 .expect("should create limited producer");
1878
1879 assert!(limited_producer.with_root("notallowed").is_none());
1881
1882 let allowed_root = limited_producer
1884 .with_root("allowed")
1885 .expect("should create allowed root");
1886 assert_eq!(allowed_root.root().as_str(), "allowed");
1887 }
1888
1889 #[tokio::test]
1890 async fn test_wildcard_permission() {
1891 let origin = Origin::random().produce();
1892 let broadcast = Broadcast::new().produce();
1893
1894 let root_producer = origin.clone();
1896
1897 assert!(root_producer.publish_broadcast("any/path", broadcast.consume()));
1899 assert!(root_producer.publish_broadcast("other/path", broadcast.consume()));
1900
1901 let foo_producer = root_producer.with_root("foo").expect("should create any root");
1903 assert_eq!(foo_producer.root().as_str(), "foo");
1904 }
1905
1906 #[tokio::test]
1907 async fn test_consume_broadcast_with_permissions() {
1908 let origin = Origin::random().produce();
1909 let broadcast1 = Broadcast::new().produce();
1910 let broadcast2 = Broadcast::new().produce();
1911
1912 origin.publish_broadcast("allowed/test", broadcast1.consume());
1913 origin.publish_broadcast("notallowed/test", broadcast2.consume());
1914
1915 let limited_consumer = origin
1917 .consume()
1918 .scope(&["allowed".into()])
1919 .expect("should create limited consumer");
1920
1921 let result = limited_consumer.get_broadcast("allowed/test");
1923 assert!(result.is_some());
1924 assert!(result.unwrap().is_clone(&broadcast1.consume()));
1925
1926 assert!(limited_consumer.get_broadcast("notallowed/test").is_none());
1928
1929 let consumer = origin.consume();
1931 assert!(consumer.get_broadcast("allowed/test").is_some());
1932 assert!(consumer.get_broadcast("notallowed/test").is_some());
1933 }
1934
1935 #[tokio::test]
1936 async fn test_nested_paths_with_permissions() {
1937 let origin = Origin::random().produce();
1938 let broadcast = Broadcast::new().produce();
1939
1940 let limited_producer = origin.scope(&["a/b/c".into()]).expect("should create limited producer");
1942
1943 assert!(limited_producer.publish_broadcast("a/b/c", broadcast.consume()));
1945 assert!(limited_producer.publish_broadcast("a/b/c/d", broadcast.consume()));
1946 assert!(limited_producer.publish_broadcast("a/b/c/d/e", broadcast.consume()));
1947
1948 assert!(!limited_producer.publish_broadcast("a", broadcast.consume()));
1950 assert!(!limited_producer.publish_broadcast("a/b", broadcast.consume()));
1951 assert!(!limited_producer.publish_broadcast("a/b/other", broadcast.consume()));
1952 }
1953
1954 #[tokio::test]
1955 async fn test_multiple_consumers_with_different_permissions() {
1956 let origin = Origin::random().produce();
1957 let broadcast1 = Broadcast::new().produce();
1958 let broadcast2 = Broadcast::new().produce();
1959 let broadcast3 = Broadcast::new().produce();
1960
1961 origin.publish_broadcast("foo/test", broadcast1.consume());
1963 origin.publish_broadcast("bar/test", broadcast2.consume());
1964 origin.publish_broadcast("baz/test", broadcast3.consume());
1965
1966 let mut foo_consumer = origin
1968 .consume()
1969 .scope(&["foo".into()])
1970 .expect("should create foo consumer");
1971
1972 let mut bar_consumer = origin
1973 .consume()
1974 .scope(&["bar".into()])
1975 .expect("should create bar consumer");
1976
1977 let mut foobar_consumer = origin
1978 .consume()
1979 .scope(&["foo".into(), "bar".into()])
1980 .expect("should create foobar consumer");
1981
1982 foo_consumer.assert_next("foo/test", &broadcast1.consume());
1984 foo_consumer.assert_next_wait();
1985
1986 bar_consumer.assert_next("bar/test", &broadcast2.consume());
1987 bar_consumer.assert_next_wait();
1988
1989 foobar_consumer.assert_next("bar/test", &broadcast2.consume());
1990 foobar_consumer.assert_next("foo/test", &broadcast1.consume());
1991 foobar_consumer.assert_next_wait();
1992 }
1993
1994 #[tokio::test]
1995 async fn test_select_with_empty_prefix() {
1996 let origin = Origin::random().produce();
1997 let broadcast1 = Broadcast::new().produce();
1998 let broadcast2 = Broadcast::new().produce();
1999
2000 let demo_producer = origin.with_root("demo").expect("should create demo root");
2002 let limited_producer = demo_producer
2003 .scope(&["worm-node".into(), "foobar".into()])
2004 .expect("should create limited producer");
2005
2006 assert!(limited_producer.publish_broadcast("worm-node/test", broadcast1.consume()));
2008 assert!(limited_producer.publish_broadcast("foobar/test", broadcast2.consume()));
2009
2010 let mut consumer = limited_producer
2012 .consume()
2013 .scope(&["".into()])
2014 .expect("should create consumer with empty prefix");
2015
2016 let a1 = consumer.try_announced().expect("expected first announcement");
2018 let a2 = consumer.try_announced().expect("expected second announcement");
2019 consumer.assert_next_wait();
2020
2021 let mut paths: Vec<_> = [&a1, &a2].iter().map(|(p, _)| p.to_string()).collect();
2022 paths.sort();
2023 assert_eq!(paths, ["foobar/test", "worm-node/test"]);
2024 }
2025
2026 #[tokio::test]
2027 async fn test_select_narrowing_scope() {
2028 let origin = Origin::random().produce();
2029 let broadcast1 = Broadcast::new().produce();
2030 let broadcast2 = Broadcast::new().produce();
2031 let broadcast3 = Broadcast::new().produce();
2032
2033 let demo_producer = origin.with_root("demo").expect("should create demo root");
2035 let limited_producer = demo_producer
2036 .scope(&["worm-node".into(), "foobar".into()])
2037 .expect("should create limited producer");
2038
2039 assert!(limited_producer.publish_broadcast("worm-node", broadcast1.consume()));
2041 assert!(limited_producer.publish_broadcast("worm-node/foo", broadcast2.consume()));
2042 assert!(limited_producer.publish_broadcast("foobar/bar", broadcast3.consume()));
2043
2044 let mut worm_consumer = limited_producer
2046 .consume()
2047 .scope(&["worm-node".into()])
2048 .expect("should create worm-node consumer");
2049
2050 worm_consumer.assert_next("worm-node", &broadcast1.consume());
2052 worm_consumer.assert_next("worm-node/foo", &broadcast2.consume());
2053 worm_consumer.assert_next_wait(); let mut foo_consumer = limited_producer
2057 .consume()
2058 .scope(&["worm-node/foo".into()])
2059 .expect("should create worm-node/foo consumer");
2060
2061 foo_consumer.assert_next("worm-node/foo", &broadcast2.consume());
2062 foo_consumer.assert_next_wait(); }
2064
2065 #[tokio::test]
2066 async fn test_select_multiple_roots_with_empty_prefix() {
2067 let origin = Origin::random().produce();
2068 let broadcast1 = Broadcast::new().produce();
2069 let broadcast2 = Broadcast::new().produce();
2070 let broadcast3 = Broadcast::new().produce();
2071
2072 let limited_producer = origin
2074 .scope(&["app1".into(), "app2".into(), "shared".into()])
2075 .expect("should create limited producer");
2076
2077 assert!(limited_producer.publish_broadcast("app1/data", broadcast1.consume()));
2079 assert!(limited_producer.publish_broadcast("app2/config", broadcast2.consume()));
2080 assert!(limited_producer.publish_broadcast("shared/resource", broadcast3.consume()));
2081
2082 let mut consumer = limited_producer
2084 .consume()
2085 .scope(&["".into()])
2086 .expect("should create consumer with empty prefix");
2087
2088 consumer.assert_next("app1/data", &broadcast1.consume());
2090 consumer.assert_next("app2/config", &broadcast2.consume());
2091 consumer.assert_next("shared/resource", &broadcast3.consume());
2092 consumer.assert_next_wait();
2093 }
2094
2095 #[tokio::test]
2096 async fn test_publish_scope_with_empty_prefix() {
2097 let origin = Origin::random().produce();
2098 let broadcast = Broadcast::new().produce();
2099
2100 let limited_producer = origin
2102 .scope(&["services/api".into(), "services/web".into()])
2103 .expect("should create limited producer");
2104
2105 let same_producer = limited_producer
2107 .scope(&["".into()])
2108 .expect("should create producer with empty prefix");
2109
2110 assert!(same_producer.publish_broadcast("services/api", broadcast.consume()));
2112 assert!(same_producer.publish_broadcast("services/web", broadcast.consume()));
2113 assert!(!same_producer.publish_broadcast("services/db", broadcast.consume()));
2114 assert!(!same_producer.publish_broadcast("other", broadcast.consume()));
2115 }
2116
2117 #[tokio::test]
2118 async fn test_select_narrowing_to_deeper_path() {
2119 let origin = Origin::random().produce();
2120 let broadcast1 = Broadcast::new().produce();
2121 let broadcast2 = Broadcast::new().produce();
2122 let broadcast3 = Broadcast::new().produce();
2123
2124 let limited_producer = origin.scope(&["org".into()]).expect("should create limited producer");
2126
2127 assert!(limited_producer.publish_broadcast("org/team1/project1", broadcast1.consume()));
2129 assert!(limited_producer.publish_broadcast("org/team1/project2", broadcast2.consume()));
2130 assert!(limited_producer.publish_broadcast("org/team2/project1", broadcast3.consume()));
2131
2132 let mut team2_consumer = limited_producer
2134 .consume()
2135 .scope(&["org/team2".into()])
2136 .expect("should create team2 consumer");
2137
2138 team2_consumer.assert_next("org/team2/project1", &broadcast3.consume());
2139 team2_consumer.assert_next_wait(); let mut project1_consumer = limited_producer
2143 .consume()
2144 .scope(&["org/team1/project1".into()])
2145 .expect("should create project1 consumer");
2146
2147 project1_consumer.assert_next("org/team1/project1", &broadcast1.consume());
2149 project1_consumer.assert_next_wait();
2150 }
2151
2152 #[tokio::test]
2153 async fn test_select_with_non_matching_prefix() {
2154 let origin = Origin::random().produce();
2155
2156 let limited_producer = origin
2158 .scope(&["allowed/path".into()])
2159 .expect("should create limited producer");
2160
2161 assert!(limited_producer.consume().scope(&["different/path".into()]).is_none());
2163
2164 assert!(limited_producer.scope(&["other/path".into()]).is_none());
2166 }
2167
2168 #[tokio::test]
2171 async fn test_with_root_trailing_slash_consumer() {
2172 let origin = Origin::random().produce();
2173
2174 let prefix = "some_prefix/".to_string();
2176 let mut consumer = origin.consume().with_root(prefix).unwrap();
2177
2178 let b = origin.create_broadcast("some_prefix/test").unwrap();
2179 consumer.assert_next("test", &b.consume());
2180 }
2181
2182 #[tokio::test]
2184 async fn test_with_root_trailing_slash_producer() {
2185 let origin = Origin::random().produce();
2186
2187 let prefix = "some_prefix/".to_string();
2189 let rooted = origin.with_root(prefix).unwrap();
2190
2191 let b = rooted.create_broadcast("test").unwrap();
2192
2193 let mut consumer = rooted.consume();
2194 consumer.assert_next("test", &b.consume());
2195 }
2196
2197 #[tokio::test]
2199 async fn test_with_root_trailing_slash_unannounce() {
2200 tokio::time::pause();
2201
2202 let origin = Origin::random().produce();
2203
2204 let prefix = "some_prefix/".to_string();
2205 let mut consumer = origin.consume().with_root(prefix).unwrap();
2206
2207 let b = origin.create_broadcast("some_prefix/test").unwrap();
2208 consumer.assert_next("test", &b.consume());
2209
2210 drop(b);
2212 tokio::time::sleep(tokio::time::Duration::from_millis(1)).await;
2213
2214 consumer.assert_next_none("test");
2216 }
2217
2218 #[tokio::test]
2219 async fn test_select_maintains_access_with_wider_prefix() {
2220 let origin = Origin::random().produce();
2221 let broadcast1 = Broadcast::new().produce();
2222 let broadcast2 = Broadcast::new().produce();
2223
2224 let demo_producer = origin.with_root("demo").expect("should create demo root");
2226 let user_producer = demo_producer
2227 .scope(&["worm-node".into(), "foobar".into()])
2228 .expect("should create user producer");
2229
2230 assert!(user_producer.publish_broadcast("worm-node/data", broadcast1.consume()));
2232 assert!(user_producer.publish_broadcast("foobar", broadcast2.consume()));
2233
2234 let mut consumer = user_producer
2236 .consume()
2237 .scope(&["".into()])
2238 .expect("scope with empty prefix should not fail when user has specific permissions");
2239
2240 let a1 = consumer.try_announced().expect("expected first announcement");
2242 let a2 = consumer.try_announced().expect("expected second announcement");
2243 consumer.assert_next_wait();
2244
2245 let mut paths: Vec<_> = [&a1, &a2].iter().map(|(p, _)| p.to_string()).collect();
2246 paths.sort();
2247 assert_eq!(paths, ["foobar", "worm-node/data"]);
2248
2249 let mut narrow_consumer = user_producer
2251 .consume()
2252 .scope(&["worm-node".into()])
2253 .expect("should be able to narrow scope to worm-node");
2254
2255 narrow_consumer.assert_next("worm-node/data", &broadcast1.consume());
2256 narrow_consumer.assert_next_wait(); }
2258
2259 #[tokio::test]
2260 async fn test_duplicate_prefixes_deduped() {
2261 let origin = Origin::random().produce();
2262 let broadcast = Broadcast::new().produce();
2263
2264 let producer = origin
2266 .scope(&["demo".into(), "demo".into()])
2267 .expect("should create producer");
2268
2269 assert!(producer.publish_broadcast("demo/stream", broadcast.consume()));
2270
2271 let mut consumer = producer.consume();
2272 consumer.assert_next("demo/stream", &broadcast.consume());
2273 consumer.assert_next_wait();
2274 }
2275
2276 #[tokio::test]
2277 async fn test_overlapping_prefixes_deduped() {
2278 let origin = Origin::random().produce();
2279 let broadcast = Broadcast::new().produce();
2280
2281 let producer = origin
2283 .scope(&["demo".into(), "demo/foo".into()])
2284 .expect("should create producer");
2285
2286 assert!(producer.publish_broadcast("demo/bar/stream", broadcast.consume()));
2288
2289 let mut consumer = producer.consume();
2290 consumer.assert_next("demo/bar/stream", &broadcast.consume());
2291 consumer.assert_next_wait();
2292 }
2293
2294 #[tokio::test]
2295 async fn test_overlapping_prefixes_no_duplicate_announcements() {
2296 let origin = Origin::random().produce();
2297 let broadcast = Broadcast::new().produce();
2298
2299 let producer = origin
2301 .scope(&["demo".into(), "demo/foo".into()])
2302 .expect("should create producer");
2303
2304 assert!(producer.publish_broadcast("demo/foo/stream", broadcast.consume()));
2305
2306 let mut consumer = producer.consume();
2307 consumer.assert_next("demo/foo/stream", &broadcast.consume());
2309 consumer.assert_next_wait();
2310 }
2311
2312 #[tokio::test]
2313 async fn test_allowed_returns_deduped_prefixes() {
2314 let origin = Origin::random().produce();
2315
2316 let producer = origin
2317 .scope(&["demo".into(), "demo/foo".into(), "anon".into()])
2318 .expect("should create producer");
2319
2320 let allowed: Vec<_> = producer.allowed().collect();
2321 assert_eq!(allowed.len(), 2, "demo/foo should be subsumed by demo");
2322 }
2323
2324 #[tokio::test]
2325 async fn test_announced_broadcast_already_announced() {
2326 let origin = Origin::random().produce();
2327 let broadcast = Broadcast::new().produce();
2328
2329 origin.publish_broadcast("test", broadcast.consume());
2330
2331 let consumer = origin.consume();
2332 let result = consumer.announced_broadcast("test").await.expect("should find it");
2333 assert!(result.is_clone(&broadcast.consume()));
2334 }
2335
2336 #[tokio::test]
2337 async fn test_announced_broadcast_delayed() {
2338 tokio::time::pause();
2339
2340 let origin = Origin::random().produce();
2341 let broadcast = Broadcast::new().produce();
2342
2343 let consumer = origin.consume();
2344
2345 let wait = tokio::spawn({
2347 let consumer = consumer.clone();
2348 async move { consumer.announced_broadcast("test").await }
2349 });
2350
2351 tokio::task::yield_now().await;
2353
2354 origin.publish_broadcast("test", broadcast.consume());
2355
2356 let result = wait.await.unwrap().expect("should find it");
2357 assert!(result.is_clone(&broadcast.consume()));
2358 }
2359
2360 #[tokio::test]
2361 async fn test_announced_broadcast_ignores_unrelated_paths() {
2362 tokio::time::pause();
2363
2364 let origin = Origin::random().produce();
2365 let other = Broadcast::new().produce();
2366 let target = Broadcast::new().produce();
2367
2368 let consumer = origin.consume();
2369
2370 let wait = tokio::spawn({
2371 let consumer = consumer.clone();
2372 async move { consumer.announced_broadcast("target").await }
2373 });
2374
2375 tokio::task::yield_now().await;
2376
2377 origin.publish_broadcast("other", other.consume());
2379 tokio::task::yield_now().await;
2380 assert!(!wait.is_finished(), "must not resolve on unrelated path");
2381
2382 origin.publish_broadcast("target", target.consume());
2383 let result = wait.await.unwrap().expect("should find target");
2384 assert!(result.is_clone(&target.consume()));
2385 }
2386
2387 #[tokio::test]
2388 async fn test_announced_broadcast_skips_nested_paths() {
2389 tokio::time::pause();
2390
2391 let origin = Origin::random().produce();
2392 let nested = Broadcast::new().produce();
2393 let exact = Broadcast::new().produce();
2394
2395 let consumer = origin.consume();
2396
2397 let wait = tokio::spawn({
2398 let consumer = consumer.clone();
2399 async move { consumer.announced_broadcast("foo").await }
2400 });
2401
2402 tokio::task::yield_now().await;
2403
2404 origin.publish_broadcast("foo/bar", nested.consume());
2406 tokio::task::yield_now().await;
2407 assert!(!wait.is_finished(), "must not resolve on a nested path");
2408
2409 origin.publish_broadcast("foo", exact.consume());
2410 let result = wait.await.unwrap().expect("should find foo exactly");
2411 assert!(result.is_clone(&exact.consume()));
2412 }
2413
2414 #[tokio::test]
2415 async fn test_announced_broadcast_disallowed() {
2416 let origin = Origin::random().produce();
2417 let limited = origin
2418 .consume()
2419 .scope(&["allowed".into()])
2420 .expect("should create limited");
2421
2422 assert!(limited.announced_broadcast("notallowed").await.is_none());
2424 }
2425
2426 #[tokio::test]
2427 async fn test_announced_broadcast_scope_too_narrow() {
2428 let origin = Origin::random().produce();
2431 let limited = origin
2432 .consume()
2433 .scope(&["foo/specific".into()])
2434 .expect("should create limited");
2435
2436 let result = limited
2438 .announced_broadcast("foo")
2439 .now_or_never()
2440 .expect("must not block");
2441 assert!(result.is_none());
2442 }
2443
2444 #[tokio::test]
2448 async fn test_coalesce_announce_then_unannounce() {
2449 tokio::time::pause();
2451
2452 let origin = Origin::random().produce();
2453 let mut consumer = origin.consume();
2454
2455 let broadcast = Broadcast::new().produce();
2456 origin.publish_broadcast("test", broadcast.consume());
2457 drop(broadcast);
2458
2459 tokio::time::sleep(tokio::time::Duration::from_millis(1)).await;
2460
2461 consumer.assert_next_wait();
2462 }
2463
2464 #[tokio::test]
2465 async fn test_coalesce_announce_unannounce_announce() {
2466 tokio::time::pause();
2469
2470 let origin = Origin::random().produce();
2471 let mut consumer = origin.consume();
2472
2473 let broadcast1 = Broadcast::new().produce();
2474 let broadcast2 = Broadcast::new().produce();
2475
2476 origin.publish_broadcast("test", broadcast1.consume());
2477 drop(broadcast1);
2478 tokio::time::sleep(tokio::time::Duration::from_millis(1)).await;
2479 origin.publish_broadcast("test", broadcast2.consume());
2480
2481 consumer.assert_next("test", &broadcast2.consume());
2482 consumer.assert_next_wait();
2483 }
2484
2485 #[tokio::test]
2486 async fn test_coalesce_unannounce_announce_preserved() {
2487 tokio::time::pause();
2490
2491 let origin = Origin::random().produce();
2492 let broadcast1 = Broadcast::new().produce();
2493 origin.publish_broadcast("test", broadcast1.consume());
2494
2495 let mut consumer = origin.consume();
2496 consumer.assert_next("test", &broadcast1.consume());
2497
2498 drop(broadcast1);
2500 tokio::time::sleep(tokio::time::Duration::from_millis(1)).await;
2501
2502 let broadcast2 = Broadcast::new().produce();
2503 origin.publish_broadcast("test", broadcast2.consume());
2504
2505 consumer.assert_next_none("test");
2507 consumer.assert_next("test", &broadcast2.consume());
2508 consumer.assert_next_wait();
2509 }
2510
2511 #[tokio::test]
2512 async fn test_coalesce_unannounce_announce_unannounce() {
2513 tokio::time::pause();
2516
2517 let origin = Origin::random().produce();
2518 let broadcast1 = Broadcast::new().produce();
2519 origin.publish_broadcast("test", broadcast1.consume());
2520
2521 let mut consumer = origin.consume();
2522 consumer.assert_next("test", &broadcast1.consume());
2523
2524 drop(broadcast1);
2525 tokio::time::sleep(tokio::time::Duration::from_millis(1)).await;
2526
2527 let broadcast2 = Broadcast::new().produce();
2528 origin.publish_broadcast("test", broadcast2.consume());
2529 drop(broadcast2);
2530 tokio::time::sleep(tokio::time::Duration::from_millis(1)).await;
2531
2532 consumer.assert_next_none("test");
2533 consumer.assert_next_wait();
2534 }
2535
2536 #[tokio::test]
2537 async fn test_coalesce_churn_bounded() {
2538 tokio::time::pause();
2543
2544 let origin = Origin::random().produce();
2545 let mut consumer = origin.consume();
2546
2547 for _ in 0..1000 {
2548 let broadcast = Broadcast::new().produce();
2549 origin.publish_broadcast("test", broadcast.consume());
2550 drop(broadcast);
2551 }
2552 tokio::time::sleep(tokio::time::Duration::from_millis(1)).await;
2553
2554 let mut collected = Vec::new();
2555 while let Some(update) = consumer.try_announced() {
2556 collected.push(update);
2557 }
2558 assert!(
2559 collected.len() <= 1,
2560 "expected at most one pending update, got {}",
2561 collected.len()
2562 );
2563 assert!(
2564 collected.iter().all(|(path, _)| path == &Path::new("test")),
2565 "unexpected path in pending updates",
2566 );
2567 }
2568
2569 #[tokio::test]
2571 async fn dynamic_request_unroutable_without_handler() {
2572 let origin = Origin::random().produce();
2573 let consumer = origin.consume();
2574 assert!(matches!(
2575 consumer.request_broadcast("missing").await,
2576 Err(Error::Unroutable)
2577 ));
2578 }
2579
2580 #[tokio::test(start_paused = true)]
2582 async fn dynamic_request_served_not_announced() {
2583 let origin = Origin::random().produce();
2584 let mut dynamic = origin.dynamic();
2585 let consumer = origin.consume();
2586
2587 let mut announced = origin.consume();
2589 announced.assert_next_wait();
2590
2591 let request_fut = consumer.request_broadcast("fallback");
2594
2595 let served = Broadcast::new().produce();
2597
2598 let request = dynamic.requested_broadcast().await.unwrap();
2599 assert_eq!(request.path(), &Path::new("fallback"));
2600 request.accept(served.consume());
2601
2602 let broadcast = request_fut.await.unwrap();
2603 assert!(broadcast.is_clone(&served.consume()));
2604
2605 announced.assert_next_wait();
2607 }
2608
2609 #[tokio::test(start_paused = true)]
2611 async fn dynamic_request_coalesces() {
2612 let origin = Origin::random().produce();
2613 let mut dynamic = origin.dynamic();
2614 let consumer = origin.consume();
2615
2616 let f1 = consumer.request_broadcast("dup");
2618 let f2 = consumer.request_broadcast("dup");
2619
2620 let request = dynamic.requested_broadcast().await.unwrap();
2622 assert_eq!(request.path(), &Path::new("dup"));
2623 assert!(
2624 dynamic.requested_broadcast().now_or_never().is_none(),
2625 "a coalesced request must not be served twice"
2626 );
2627
2628 let served = Broadcast::new().produce();
2630 request.accept(served.consume());
2631 assert!(f1.await.unwrap().is_clone(&served.consume()));
2632 assert!(f2.await.unwrap().is_clone(&served.consume()));
2633 }
2634
2635 #[tokio::test(start_paused = true)]
2637 async fn dynamic_request_rejected() {
2638 let origin = Origin::random().produce();
2639 let mut dynamic = origin.dynamic();
2640 let consumer = origin.consume();
2641
2642 let request_fut = consumer.request_broadcast("fallback");
2643
2644 let request = dynamic.requested_broadcast().await.unwrap();
2645 request.reject(Error::Cancel);
2646
2647 assert!(matches!(request_fut.await, Err(Error::Cancel)));
2648 }
2649
2650 #[tokio::test(start_paused = true)]
2653 async fn dynamic_request_handler_dropped() {
2654 let origin = Origin::random().produce();
2655 let dynamic = origin.dynamic();
2656 let consumer = origin.consume();
2657
2658 let request_fut = consumer.request_broadcast("fallback");
2659 drop(dynamic);
2660 assert!(matches!(request_fut.await, Err(Error::Unroutable)));
2661
2662 assert!(matches!(
2664 consumer.request_broadcast("again").await,
2665 Err(Error::Unroutable)
2666 ));
2667 }
2668
2669 #[tokio::test(start_paused = true)]
2673 async fn dynamic_request_accept_after_handler_dropped() {
2674 let origin = Origin::random().produce();
2675 let mut dynamic = origin.dynamic();
2676 let consumer = origin.consume();
2677
2678 let request_fut = consumer.request_broadcast("fallback");
2679
2680 let request = dynamic.requested_broadcast().await.unwrap();
2682 drop(dynamic);
2683
2684 let served = Broadcast::new().produce();
2686 request.accept(served.consume());
2687 assert!(request_fut.await.unwrap().is_clone(&served.consume()));
2688 }
2689
2690 #[tokio::test(start_paused = true)]
2692 async fn dynamic_request_prefers_announced() {
2693 let origin = Origin::random().produce();
2694 let mut dynamic = origin.dynamic();
2695 let consumer = origin.consume();
2696
2697 let broadcast = Broadcast::new().produce();
2698 assert!(origin.publish_broadcast("live", broadcast.consume()));
2699
2700 let got = consumer.request_broadcast("live").await.unwrap();
2701 assert!(
2702 got.is_clone(&broadcast.consume()),
2703 "should return the announced broadcast"
2704 );
2705 assert!(
2706 dynamic.requested_broadcast().now_or_never().is_none(),
2707 "an announced path must not queue a fallback request"
2708 );
2709 }
2710
2711 #[tokio::test(start_paused = true)]
2713 async fn dynamic_clone_keeps_alive() {
2714 let origin = Origin::random().produce();
2715 let dynamic = origin.dynamic();
2716 let consumer = origin.consume();
2717
2718 drop(dynamic.clone());
2719
2720 let request_fut = consumer.request_broadcast("fallback");
2723 assert!(
2724 request_fut.now_or_never().is_none(),
2725 "request should stay pending until served"
2726 );
2727 }
2728}