subscriber.rs 1.9 KB

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