subscriber.rs 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. use async_std::sync::Mutex;
  2. use std::sync::Arc;
  3. use fxhash::FxHashMap;
  4. use rand::Rng;
  5. pub type SubscriberPtr<T> = Arc<Subscriber<T>>;
  6. pub type SubscriptionId = u64;
  7. pub struct Subscription<T> {
  8. id: SubscriptionId,
  9. recv_queue: async_channel::Receiver<T>,
  10. parent: Arc<Subscriber<T>>,
  11. }
  12. impl<T: Clone> Subscription<T> {
  13. pub async fn receive(&self) -> T {
  14. let message_result = self.recv_queue.recv().await;
  15. match message_result {
  16. Ok(message_result) => message_result,
  17. Err(err) => {
  18. panic!("MessageSubscription::receive() recv_queue failed! {}", err);
  19. }
  20. }
  21. }
  22. // Must be called manually since async Drop is not possible in Rust
  23. pub async fn unsubscribe(&self) {
  24. self.parent.clone().unsubscribe(self.id).await
  25. }
  26. }
  27. // Simple broadcast (publish-subscribe) class
  28. pub struct Subscriber<T> {
  29. subs: Mutex<FxHashMap<u64, async_channel::Sender<T>>>,
  30. }
  31. impl<T: Clone> Subscriber<T> {
  32. pub fn new() -> Arc<Self> {
  33. Arc::new(Self { subs: Mutex::new(FxHashMap::default()) })
  34. }
  35. fn random_id() -> SubscriptionId {
  36. let mut rng = rand::thread_rng();
  37. rng.gen()
  38. }
  39. pub async fn subscribe(self: Arc<Self>) -> Subscription<T> {
  40. let (sender, recvr) = async_channel::unbounded();
  41. let sub_id = Self::random_id();
  42. self.subs.lock().await.insert(sub_id, sender);
  43. Subscription { id: sub_id, recv_queue: recvr, parent: self.clone() }
  44. }
  45. async fn unsubscribe(self: Arc<Self>, sub_id: SubscriptionId) {
  46. self.subs.lock().await.remove(&sub_id);
  47. }
  48. pub async fn notify(&self, message_result: T) {
  49. for sub in (*self.subs.lock().await).values() {
  50. match sub.send(message_result.clone()).await {
  51. Ok(()) => {}
  52. Err(err) => {
  53. panic!("Error returned sending message in notify() call! {}", err);
  54. }
  55. }
  56. }
  57. }
  58. }