pubsub.rs 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. use rand::{rngs::OsRng, Rng};
  2. use std::{
  3. collections::HashMap,
  4. sync::{Arc, Mutex},
  5. };
  6. use crate::error::{Error, Result};
  7. pub type SubscriptionId = usize;
  8. // Waiting for trait aliases
  9. pub trait Piped: Clone + Send + 'static {}
  10. impl<T> Piped for T where T: Clone + Send + 'static {}
  11. #[derive(Debug)]
  12. /// Subscription to the Publisher. Created using `publisher.subscribe().await`.
  13. pub struct Subscription<T: Piped> {
  14. id: SubscriptionId,
  15. recv_queue: smol::channel::Receiver<T>,
  16. parent: Arc<Publisher<T>>,
  17. }
  18. impl<T: Piped> Subscription<T> {
  19. pub fn get_id(&self) -> SubscriptionId {
  20. self.id
  21. }
  22. /// Receive message.
  23. pub async fn receive(&self) -> Result<T> {
  24. let msg_result = self.recv_queue.recv().await;
  25. msg_result.or(Err(Error::PublisherDestroyed))
  26. }
  27. }
  28. impl<T: Piped> Drop for Subscription<T> {
  29. fn drop(&mut self) {
  30. self.parent.unsubscribe(self.id)
  31. }
  32. }
  33. pub type PublisherPtr<T> = Arc<Publisher<T>>;
  34. #[derive(Debug)]
  35. pub struct Publisher<T> {
  36. subs: Mutex<HashMap<SubscriptionId, smol::channel::Sender<T>>>,
  37. }
  38. impl<T: Piped> Publisher<T> {
  39. pub fn new() -> Arc<Self> {
  40. Arc::new(Self { subs: Mutex::new(HashMap::new()) })
  41. }
  42. pub fn subscribe(self: Arc<Self>) -> Subscription<T> {
  43. let (sendr, recvr) = smol::channel::unbounded();
  44. let sub_id = OsRng.gen();
  45. // Optional to check whether this ID already exists.
  46. // It is nearly impossible to ever happen.
  47. self.subs.lock().unwrap().insert(sub_id, sendr);
  48. Subscription { id: sub_id, recv_queue: recvr, parent: self.clone() }
  49. }
  50. fn unsubscribe(&self, sub_id: SubscriptionId) {
  51. self.subs.lock().unwrap().remove(&sub_id);
  52. }
  53. /// Publish a message to all listening subscriptions.
  54. pub fn notify(&self, msg: T) {
  55. for (id, sub) in self.subs.lock().unwrap().iter() {
  56. if let Err(e) = sub.try_send(msg.clone()) {
  57. // This should never happen since Drop calls unsubscribe()
  58. panic!("Error in notify() call for sub={}! {}", id, e);
  59. }
  60. }
  61. }
  62. }