message_subscriber.rs 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. use async_std::sync::Mutex;
  2. use std::{any::Any, io, io::Cursor, sync::Arc};
  3. use async_trait::async_trait;
  4. use fxhash::FxHashMap;
  5. use log::{debug, error, warn};
  6. use rand::Rng;
  7. use crate::{
  8. util::serial::{Decodable, Encodable},
  9. Error, Result,
  10. };
  11. use super::message::Message;
  12. /// 64bit identifier for message subscription.
  13. pub type MessageSubscriptionId = u64;
  14. type MessageResult<M> = Result<Arc<M>>;
  15. /// Handles message subscriptions through a subscription ID and a receiver
  16. /// channel.
  17. pub struct MessageSubscription<M: Message> {
  18. id: MessageSubscriptionId,
  19. recv_queue: async_channel::Receiver<MessageResult<M>>,
  20. parent: Arc<MessageDispatcher<M>>,
  21. }
  22. impl<M: Message> MessageSubscription<M> {
  23. /// Start receiving messages.
  24. pub async fn receive(&self) -> MessageResult<M> {
  25. match self.recv_queue.recv().await {
  26. Ok(message) => message,
  27. Err(err) => {
  28. panic!("MessageSubscription::receive() recv_queue failed! {}", err);
  29. }
  30. }
  31. }
  32. /// Unsubscribe from a message subscription. Must be called manually.
  33. pub async fn unsubscribe(&self) {
  34. self.parent.clone().unsubscribe(self.id).await
  35. }
  36. }
  37. #[async_trait]
  38. /// Generic interface for message dispatcher.
  39. trait MessageDispatcherInterface: Send + Sync {
  40. async fn trigger(&self, payload: Vec<u8>);
  41. async fn trigger_error(&self, err: Error);
  42. fn as_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;
  43. }
  44. /// A dispatchers that is unique to every Message. Maintains a list of subscribers that are subscribed to that unique Message type and handles sending messages across these subscriptions.
  45. struct MessageDispatcher<M: Message> {
  46. subs: Mutex<FxHashMap<MessageSubscriptionId, async_channel::Sender<MessageResult<M>>>>,
  47. }
  48. impl<M: Message> MessageDispatcher<M> {
  49. /// Create a new message dispatcher.
  50. fn new() -> Self {
  51. MessageDispatcher { subs: Mutex::new(FxHashMap::default()) }
  52. }
  53. /// Create a random ID.
  54. fn random_id() -> MessageSubscriptionId {
  55. let mut rng = rand::thread_rng();
  56. rng.gen()
  57. }
  58. /// Subscribe to a channel. Assigns a new ID and adds it to the list of
  59. /// subscribers.
  60. pub async fn subscribe(self: Arc<Self>) -> MessageSubscription<M> {
  61. let (sender, recvr) = async_channel::unbounded();
  62. let sub_id = Self::random_id();
  63. self.subs.lock().await.insert(sub_id, sender);
  64. MessageSubscription { id: sub_id, recv_queue: recvr, parent: self }
  65. }
  66. /// Unsubcribe from a channel. Removes the associated ID from the subscriber
  67. /// list.
  68. async fn unsubscribe(&self, sub_id: MessageSubscriptionId) {
  69. self.subs.lock().await.remove(&sub_id);
  70. }
  71. /// Private function to transmit a message to all subscriber channels. Automatically clear inactive
  72. /// channels. Used strictly internally.
  73. async fn _trigger_all(&self, message: MessageResult<M>) {
  74. debug!(
  75. target: "net",
  76. "MessageDispatcher<M={}>::trigger_all({}) [START, subs={}]",
  77. M::name(),
  78. if message.is_ok() { "msg" } else { "err" },
  79. self.subs.lock().await.len()
  80. );
  81. let mut garbage_ids = Vec::new();
  82. for (sub_id, sub) in &*self.subs.lock().await {
  83. match sub.send(message.clone()).await {
  84. Ok(()) => {}
  85. Err(_err) => {
  86. // Automatically clean out closed channels
  87. garbage_ids.push(*sub_id);
  88. // panic!("Error returned sending message in notify() call!
  89. // {}", err);
  90. }
  91. }
  92. }
  93. self.collect_garbage(garbage_ids).await;
  94. debug!(
  95. target: "net",
  96. "MessageDispatcher<M={}>::trigger_all({}) [END, subs={}]",
  97. M::name(),
  98. if message.is_ok() { "msg" } else { "err" },
  99. self.subs.lock().await.len()
  100. );
  101. }
  102. /// Remove inactive channels.
  103. async fn collect_garbage(&self, ids: Vec<MessageSubscriptionId>) {
  104. let mut subs = self.subs.lock().await;
  105. for id in &ids {
  106. subs.remove(id);
  107. }
  108. }
  109. }
  110. #[async_trait]
  111. // Local implementation of the Message Dispatcher Interface.
  112. impl<M: Message> MessageDispatcherInterface for MessageDispatcher<M> {
  113. /// Internal function to deserialize data into a message type and dispatch it across subscriber channels.
  114. async fn trigger(&self, payload: Vec<u8>) {
  115. // deserialize data into type
  116. // send down the pipes
  117. let cursor = Cursor::new(payload);
  118. match M::decode(cursor) {
  119. Ok(message) => {
  120. let message = Ok(Arc::new(message));
  121. self._trigger_all(message).await
  122. }
  123. Err(err) => {
  124. error!("Unable to decode data. Dropping...: {}", err);
  125. }
  126. }
  127. }
  128. /// Interal function that sends a Error message to all subscriber channels.
  129. async fn trigger_error(&self, err: Error) {
  130. self._trigger_all(Err(err)).await;
  131. }
  132. /// Converts to Any trait. Enables the dynamic modification of static types.
  133. fn as_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> {
  134. self
  135. }
  136. }
  137. /// Generic publish/subscribe class that maintains a list of dispatchers. Dispatchers transmit
  138. /// messages to subscribers and are specific to one message type.
  139. pub struct MessageSubsystem {
  140. dispatchers: Mutex<FxHashMap<&'static str, Arc<dyn MessageDispatcherInterface>>>,
  141. }
  142. impl MessageSubsystem {
  143. /// Create a new message subsystem.
  144. pub fn new() -> Self {
  145. MessageSubsystem { dispatchers: Mutex::new(FxHashMap::default()) }
  146. }
  147. /// Add a new dispatcher for specified Message.
  148. pub async fn add_dispatch<M: Message>(&self) {
  149. self.dispatchers.lock().await.insert(M::name(), Arc::new(MessageDispatcher::<M>::new()));
  150. }
  151. /// Subscribes to a Message. Using the Message name, the method returns an the associated MessageDispatcher from the list of
  152. /// dispatchers and calls subscribe().
  153. pub async fn subscribe<M: Message>(&self) -> Result<MessageSubscription<M>> {
  154. let dispatcher = self.dispatchers.lock().await.get(M::name()).cloned();
  155. let sub = match dispatcher {
  156. Some(dispatcher) => {
  157. let dispatcher: Arc<MessageDispatcher<M>> = dispatcher
  158. .as_any()
  159. .downcast::<MessageDispatcher<M>>()
  160. .expect("Multiple messages registered with different names");
  161. dispatcher.subscribe().await
  162. }
  163. None => {
  164. // normall return failure here
  165. // for now panic
  166. return Err(Error::NetworkOperationFailed)
  167. }
  168. };
  169. Ok(sub)
  170. }
  171. /// Transmits a payload to a dispatcher. Returns an error if the payload
  172. /// fails to transmit.
  173. pub async fn notify(&self, command: &str, payload: Vec<u8>) {
  174. let dispatcher = self.dispatchers.lock().await.get(command).cloned();
  175. match dispatcher {
  176. Some(dispatcher) => {
  177. dispatcher.trigger(payload).await;
  178. }
  179. None => {
  180. warn!(
  181. target: "MessageSubsystem::notify",
  182. "MessageSubsystem::notify(\"{}\", payload) did not find a dispatcher",
  183. command
  184. );
  185. }
  186. }
  187. }
  188. /// Transmits an error message across dispatchers.
  189. pub async fn trigger_error(&self, err: Error) {
  190. // TODO: this could be parallelized
  191. for dispatcher in self.dispatchers.lock().await.values() {
  192. dispatcher.trigger_error(err.clone()).await;
  193. }
  194. }
  195. }
  196. impl Default for MessageSubsystem {
  197. fn default() -> Self {
  198. Self::new()
  199. }
  200. }
  201. /// Test functions for message subsystem.
  202. // This is a test function for the message subsystem code above
  203. // Normall we would use the #[test] macro but cannot since it is async code
  204. // Instead we call it using smol::block_on() in the unit test code after this
  205. // func
  206. async fn _do_message_subscriber_test() {
  207. struct MyVersionMessage {
  208. x: u32,
  209. }
  210. impl Message for MyVersionMessage {
  211. fn name() -> &'static str {
  212. "verver"
  213. }
  214. }
  215. impl Encodable for MyVersionMessage {
  216. fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
  217. let mut len = 0;
  218. len += self.x.encode(&mut s)?;
  219. Ok(len)
  220. }
  221. }
  222. impl Decodable for MyVersionMessage {
  223. fn decode<D: io::Read>(mut d: D) -> Result<Self> {
  224. Ok(Self { x: Decodable::decode(&mut d)? })
  225. }
  226. }
  227. println!("hello");
  228. let subsystem = MessageSubsystem::new();
  229. subsystem.add_dispatch::<MyVersionMessage>().await;
  230. // subscribe
  231. // 1. get dispatcher
  232. // 2. cast to specific type
  233. // 3. do sub, return sub
  234. let sub = subsystem.subscribe::<MyVersionMessage>().await.unwrap();
  235. let msg = MyVersionMessage { x: 110 };
  236. let mut payload = Vec::new();
  237. msg.encode(&mut payload).unwrap();
  238. // receive message and publish
  239. // 1. based on string, lookup relevant dispatcher interface
  240. // 2. publish data there
  241. subsystem.notify("verver", payload).await;
  242. // receive
  243. // 1. do a get easy
  244. let msg2 = sub.receive().await.unwrap();
  245. assert_eq!(msg2.x, 110);
  246. println!("{}", msg2.x);
  247. subsystem.trigger_error(Error::ChannelStopped).await;
  248. let msg2 = sub.receive().await;
  249. assert!(msg2.is_err());
  250. sub.unsubscribe().await;
  251. }
  252. #[cfg(test)]
  253. mod tests {
  254. use super::*;
  255. #[test]
  256. fn test_message_subscriber() {
  257. smol::block_on(_do_message_subscriber_test());
  258. }
  259. }