1use log::{debug, error, warn};
2use serde::{Deserialize, Serialize};
3
4use super::tether_compliant_topic::TetherOrCustomTopic;
5
6pub trait ChannelDefinitionCommon<'a> {
7 fn name(&'a self) -> &'a str;
8 fn generated_topic(&'a self) -> &'a str;
10 fn topic(&'a self) -> &'a TetherOrCustomTopic;
12 fn qos(&'a self) -> i32;
13}
14
15#[derive(Serialize, Deserialize, Debug)]
16pub struct ChannelReceiverDefinition {
17 name: String,
18 topic: TetherOrCustomTopic,
19 qos: i32,
20}
21
22impl ChannelDefinitionCommon<'_> for ChannelReceiverDefinition {
23 fn name(&self) -> &str {
24 &self.name
25 }
26
27 fn generated_topic(&self) -> &str {
28 match &self.topic {
29 TetherOrCustomTopic::Custom(s) => {
30 debug!(
31 "Channel named \"{}\" has custom topic \"{}\"",
32 &self.name, &s
33 );
34 s
35 }
36 TetherOrCustomTopic::Tether(t) => {
37 debug!(
38 "Channel named \"{}\" has Tether-compliant topic \"{:?}\"",
39 &self.name, t
40 );
41 t.topic()
42 }
43 }
44 }
45
46 fn topic(&'_ self) -> &'_ TetherOrCustomTopic {
47 &self.topic
48 }
49
50 fn qos(&self) -> i32 {
51 self.qos
52 }
53}
54
55impl ChannelReceiverDefinition {
56 pub fn new(
57 name: &str,
58 topic: TetherOrCustomTopic,
59 qos: Option<i32>,
60 ) -> ChannelReceiverDefinition {
61 ChannelReceiverDefinition {
62 name: String::from(name),
63 topic,
64 qos: qos.unwrap_or(1),
65 }
66 }
67
68 pub fn matches(&self, incoming_topic: &TetherOrCustomTopic) -> bool {
79 match incoming_topic {
80 TetherOrCustomTopic::Tether(incoming_three_parts) => match &self.topic {
81 TetherOrCustomTopic::Tether(my_tpt) => {
82 let matches_role =
83 my_tpt.role() == "+" || my_tpt.role().eq(incoming_three_parts.role());
84 let matches_channel_name = my_tpt.channel_name() == "+"
85 || my_tpt
86 .channel_name()
87 .eq(incoming_three_parts.channel_name());
88 let matches_id = match my_tpt.id() {
89 Some(specified_id) => match incoming_three_parts.id() {
90 Some(incoming_id) => specified_id == incoming_id,
91 None => false,
92 },
93 None => true,
94 };
95
96 debug!("Test match for Channel named \"{}\" with def {:?} against {:?} => matches_role? {}, matches_id? {}, matches_channel_name? {}", &self.name, &self.topic, &incoming_three_parts, matches_role, matches_id, matches_channel_name);
97 matches_role && matches_id && matches_channel_name
98 }
99 TetherOrCustomTopic::Custom(my_custom_topic) => {
100 debug!(
101 "Custom/manual topic \"{}\" on Channel \"{}\" cannot be matched automatically; please filter manually for this",
102 &my_custom_topic,
103 self.name()
104 );
105 my_custom_topic.as_str() == "#"
106 || my_custom_topic.as_str() == incoming_three_parts.topic()
107 }
108 },
109 TetherOrCustomTopic::Custom(incoming_custom) => match &self.topic {
110 TetherOrCustomTopic::Custom(my_custom_topic) => {
111 if my_custom_topic.as_str() == "#"
112 || my_custom_topic.as_str() == incoming_custom.as_str()
113 {
114 true
115 } else {
116 warn!(
117 "Incoming topic \"{}\" is not a Tether-Compliant topic",
118 &incoming_custom
119 );
120 false
121 }
122 }
123 TetherOrCustomTopic::Tether(_) => {
124 error!("Incoming is NOT Tether Compliant Topic but this Channel DOES have Tether Compliant Topic; cannot decide match");
125 false
126 }
127 },
128 }
129 }
130}
131
132#[derive(Serialize, Deserialize, Debug)]
133pub struct ChannelSenderDefinition {
134 name: String,
135 topic: TetherOrCustomTopic,
136 qos: i32,
137 retain: bool,
138}
139
140impl ChannelDefinitionCommon<'_> for ChannelSenderDefinition {
141 fn name(&'_ self) -> &'_ str {
142 &self.name
143 }
144
145 fn generated_topic(&self) -> &str {
146 match &self.topic {
147 TetherOrCustomTopic::Custom(s) => s,
148 TetherOrCustomTopic::Tether(t) => t.topic(),
149 }
150 }
151
152 fn topic(&'_ self) -> &'_ TetherOrCustomTopic {
153 &self.topic
154 }
155
156 fn qos(&'_ self) -> i32 {
157 self.qos
158 }
159}
160
161impl ChannelSenderDefinition {
162 pub fn new(
163 name: &str,
164 topic: TetherOrCustomTopic,
165 qos: Option<i32>,
166 retain: Option<bool>,
167 ) -> ChannelSenderDefinition {
168 ChannelSenderDefinition {
169 name: String::from(name),
170 topic,
171 qos: qos.unwrap_or(1),
172 retain: retain.unwrap_or(false),
173 }
174 }
175
176 pub fn retain(&self) -> bool {
177 self.retain
178 }
179}
180
181#[derive(Serialize, Deserialize, Debug)]
182pub enum ChannelDefinition {
183 ChannelReceiver(ChannelReceiverDefinition),
184 ChannelSender(ChannelSenderDefinition),
185}
186
187impl ChannelDefinition {
188 pub fn name(&self) -> &str {
189 match self {
190 ChannelDefinition::ChannelReceiver(p) => p.name(),
191 ChannelDefinition::ChannelSender(p) => p.name(),
192 }
193 }
194
195 pub fn generated_topic(&self) -> &str {
196 match self {
197 ChannelDefinition::ChannelReceiver(p) => p.generated_topic(),
198 ChannelDefinition::ChannelSender(p) => p.generated_topic(),
199 }
200 }
201
202 pub fn matches(&self, topic: &TetherOrCustomTopic) -> bool {
203 match self {
204 ChannelDefinition::ChannelReceiver(p) => p.matches(topic),
205 ChannelDefinition::ChannelSender(_) => {
206 error!("We don't check matches for Channel Senders");
207 false
208 }
209 }
210 }
211}
212
213#[cfg(test)]
214mod tests {
215
216 use crate::{
217 tether_compliant_topic::{parse_channel_name, TetherCompliantTopic, TetherOrCustomTopic},
218 ChannelDefinitionCommon, ChannelReceiverDefinition,
219 };
220
221 #[test]
222 fn receiver_match_tpt() {
223 let channel_def = ChannelReceiverDefinition::new(
224 "testChannel",
225 TetherOrCustomTopic::Tether(TetherCompliantTopic::new_for_subscribe(
226 "testChannel",
227 None,
228 None,
229 )),
230 None,
231 );
232
233 assert_eq!(&channel_def.name, "testChannel");
234 assert_eq!(channel_def.generated_topic(), "+/testChannel/#");
235 assert_eq!(
236 parse_channel_name("someRole/testChannel"),
237 Some("testChannel")
238 );
239 assert_eq!(
240 parse_channel_name("someRole/testChannel/something"),
241 Some("testChannel")
242 );
243 assert!(channel_def.matches(&TetherOrCustomTopic::Tether(
244 TetherCompliantTopic::new_three("dummy", "testChannel", "#")
245 )));
246 assert!(!channel_def.matches(&TetherOrCustomTopic::Tether(
247 TetherCompliantTopic::new_three("dummy", "anotherChannel", "#")
248 )));
249 }
250
251 #[test]
252 fn receiver_match_tpt_custom_role() {
253 let channel_def = ChannelReceiverDefinition::new(
254 "customChanel",
255 TetherOrCustomTopic::Tether(TetherCompliantTopic::new_for_subscribe(
256 "customChanel",
257 Some("customRole"),
258 None,
259 )),
260 None,
261 );
262
263 assert_eq!(&channel_def.name, "customChanel");
264 assert_eq!(channel_def.generated_topic(), "customRole/customChanel/#");
265 assert!(channel_def.matches(&TetherOrCustomTopic::Tether(
266 TetherCompliantTopic::new_three("customRole", "customChanel", "#")
267 )));
268 assert!(channel_def.matches(&TetherOrCustomTopic::Tether(
269 TetherCompliantTopic::new_three("customRole", "customChanel", "andAnythingElse")
270 )));
271 assert!(!channel_def.matches(&TetherOrCustomTopic::Tether(
272 TetherCompliantTopic::new_three("customRole", "notMyChannel", "#")
273 ))); assert!(!channel_def.matches(&TetherOrCustomTopic::Tether(
275 TetherCompliantTopic::new_three("someOtherRole", "customChanel", "#")
276 ))); }
278
279 #[test]
280 fn receiver_match_custom_id() {
281 let channel_def = ChannelReceiverDefinition::new(
282 "customChanel",
283 TetherOrCustomTopic::Tether(TetherCompliantTopic::new_for_subscribe(
284 "customChanel",
285 None,
286 Some("specificID"),
287 )),
288 None,
289 );
290
291 assert_eq!(&channel_def.name, "customChanel");
292 assert_eq!(channel_def.generated_topic(), "+/customChanel/specificID");
293 assert!(channel_def.matches(&TetherOrCustomTopic::Tether(
294 TetherCompliantTopic::new_three("anyRole", "customChanel", "specificID",)
295 )));
296 assert!(channel_def.matches(&TetherOrCustomTopic::Tether(
297 TetherCompliantTopic::new_three("anotherRole", "customChanel", "specificID",)
298 ))); assert!(!channel_def.matches(&TetherOrCustomTopic::Tether(
300 TetherCompliantTopic::new_three("anyRole", "notMyChannel", "specificID",)
301 ))); assert!(!channel_def.matches(&TetherOrCustomTopic::Tether(
303 TetherCompliantTopic::new_three("anyRole", "customChanel", "anotherID",)
304 ))); }
306
307 #[test]
308 fn receiver_match_both() {
309 let channel_def = ChannelReceiverDefinition::new(
310 "customChanel",
311 TetherOrCustomTopic::Tether(TetherCompliantTopic::new_for_subscribe(
312 "customChanel",
313 Some("specificRole"),
314 Some("specificID"),
315 )),
316 None,
317 );
318
319 assert_eq!(&channel_def.name, "customChanel");
320 assert_eq!(
321 channel_def.generated_topic(),
322 "specificRole/customChanel/specificID"
323 );
324 assert!(channel_def.matches(&TetherOrCustomTopic::Tether(
325 TetherCompliantTopic::new_three("specificRole", "customChanel", "specificID",)
326 )));
327 assert!(!channel_def.matches(&TetherOrCustomTopic::Custom(
328 "specificRole/notMyChannel/specificID".into()
329 ))); assert!(!channel_def.matches(&TetherOrCustomTopic::Custom(
331 "specificRole/customChanel/anotherID".into()
332 ))); assert!(!channel_def.matches(&TetherOrCustomTopic::Custom(
334 "anotherRole/customChanel/anotherID".into()
335 ))); }
337
338 #[test]
339 fn receiver_match_custom_topic() {
340 let channel_def = ChannelReceiverDefinition::new(
341 "customChanel",
342 TetherOrCustomTopic::Custom("one/two/three/four/five".into()), None,
344 );
345
346 assert_eq!(channel_def.name(), "customChanel");
347 assert!(channel_def.matches(&TetherOrCustomTopic::Custom(
349 "one/two/three/four/five".into()
350 )));
351
352 assert!(!channel_def.matches(&TetherOrCustomTopic::Custom("one/one/one/one/one".into())));
354 }
355
356 #[test]
357 fn receiver_match_wildcard() {
358 let channel_def = ChannelReceiverDefinition::new(
359 "everything",
360 TetherOrCustomTopic::Custom("#".into()), None,
362 );
363
364 assert_eq!(channel_def.name(), "everything");
365
366 assert!(channel_def.matches(&TetherOrCustomTopic::Tether(
368 TetherCompliantTopic::new_three("any", "chanelName", "#")
369 )));
370
371 assert!(channel_def.matches(&TetherOrCustomTopic::Custom(
373 "one/two/three/four/five".into()
374 )));
375 }
376}