1use crate::message::{self, Msg};
2use log::{error, info, trace};
3use serde_json::json;
4use std::collections::{BTreeMap, HashMap};
5use tokio;
6use tokio::sync::broadcast::Sender;
7
8type ClientChannelMap = HashMap<String, Sender<Msg>>;
9
10#[derive(Debug, Clone)]
12pub struct TopicMap {
13 pub map: BTreeMap<String, ClientChannelMap>,
14}
15impl TopicMap {
16 pub fn query(&self, topic: String) -> String {
18 let v: Vec<String>;
19 if topic == "*" {
20 v = self
21 .map
22 .iter()
23 .map(|(k, v)| format!("{}: {}", k, v.len()))
24 .collect();
25 json!({topic: v}).to_string()
26 } else if self.map.contains_key(&topic) {
27 v = vec![format!("{}", self.map.get(&topic).unwrap().len())];
28 json!({topic: v}).to_string()
29 } else {
30 "".to_string()
31 }
32 }
33 pub fn add_channel(&mut self, topic: String, client_id: String, channel: Sender<Msg>) {
35 if self.map.contains_key(&topic.clone()) {
36 if let Some(channels) = self.map.get_mut(&topic.clone()) {
37 channels.entry(client_id).or_insert(channel);
38 }
40 } else {
41 let mut client_map = ClientChannelMap::new();
42 client_map.insert(client_id, channel);
43 self.map.insert(topic, client_map);
44 }
45 }
46 pub fn remove_channel(&mut self, topic: String, client_id: String) {
48 if self.map.contains_key(&topic) {
49 if let Some(channels) = self.map.get_mut(&topic) {
50 channels.remove(&client_id);
51 }
52 trace!("channels: {:?}", self.map);
53 }
54 }
55 pub fn add_topic(&mut self, topic: String) {
57 self.map.entry(topic).or_default();
58 }
59
60 pub async fn publish(&mut self, msg: Msg) {
62 if !self.map.contains_key(&msg.topic) {
63 return;
64 }
65 let topic = msg.topic.clone();
66
67 if let Some(channels) = self.map.get_mut(&topic.clone()) {
68 let dead_channels = channels
69 .iter()
70 .map(|(client_id, channel)| {
71 info!("sending msg to the {}", client_id);
72 match channel.send(msg.clone()) {
73 Ok(_n) => "".to_string(),
74 Err(e) => {
75 error!(
76 "error occurred: {} while sending the message to the channel {}",
77 e.to_string(),
78 client_id
79 );
80 error!("cleaning up");
81 client_id.clone()
82 }
83 }
84 })
85 .collect::<Vec<_>>();
86 info!("dead_channels: {:?}", dead_channels);
87 let _ = dead_channels
88 .iter()
89 .map(|client_id| {
90 self.remove_channel(topic.clone(), client_id.clone());
91 })
92 .collect::<Vec<_>>();
93 }
94 }
95}
96
97pub fn get_global_broadcaster() -> tokio::sync::broadcast::Sender<Msg> {
99 let channel_capacity_str = std::env::var("PUB_SUB_CAP").unwrap_or("1024".to_string());
100 let channel_capacity = channel_capacity_str.parse::<u16>().unwrap_or_else(|x| {
101 error!("invalid channel channel_capacity: {}", x);
102 error!("using the default value 1024");
103 1024
104 });
105 info!(
106 "creating broadcast channel with capacity: {}",
107 channel_capacity
108 );
109 let (glob_tx, _) = tokio::sync::broadcast::channel(channel_capacity.into());
110 glob_tx
111}
112
113pub async fn topic_manager(chan: Sender<Msg>) {
115 let mut map: TopicMap = TopicMap {
116 map: BTreeMap::new(),
117 };
118 let mut rx = chan.subscribe();
119 loop {
120 match rx.recv().await {
121 Ok(msg) => {
122 if !msg.topic.is_empty() {
123 info!("topic received: {}", msg.topic);
124 match msg.header.pkt_type {
125 message::PktType::PUBLISH => {
126 trace!("publishing to map:{:?}", map);
127 map.publish(msg).await;
128 }
129 message::PktType::SUBSCRIBE => {
130 if msg.client_id.is_some() || msg.channel.is_some() {
131 map.add_channel(
132 msg.topic,
133 msg.client_id.unwrap(),
134 msg.channel.unwrap(),
135 );
136 trace!("map: {:?}", map);
137 }
138 }
139 message::PktType::UNSUBSCRIBE => {
140 if msg.client_id.is_some() {
141 info!("unsubscribing:");
142 map.remove_channel(msg.topic, msg.client_id.unwrap());
143 }
144 }
145 message::PktType::QUERY => {
146 info!("querying");
147 let query_resp = map.query(msg.topic.clone());
148 info!("query_resp: {}", query_resp.clone());
149 let resp_msg = match msg.response_msg(query_resp.into_bytes()) {
150 Ok(rm) => rm,
151 Err(e) => {
152 error!(
153 "error while getting the response to the query message: {}",
154 e.to_string()
155 );
156 continue;
157 }
158 };
159 info!("generated query resp: {:?}", resp_msg);
160 match msg.channel.unwrap().send(resp_msg) {
161 Ok(n) => n,
162 Err(e) => {
163 error!(
164 "error while sending the query response: {}",
165 e.to_string()
166 );
167 0
168 }
169 };
170 }
171 _ => {}
172 };
173 }
174 }
175 Err(e) => {
176 error!(
177 "error occurred while receiving the topic: {}",
178 e.to_string()
179 );
180 }
182 };
183 }
184}