fundamentum_sdk_mqtt/models/
portforward.rs

1//! `PortForward` module
2//!
3use std::{
4    collections::HashMap,
5    hash::{DefaultHasher, Hash, Hasher},
6};
7
8use bytes::Bytes;
9use serde::{Deserialize, Serialize};
10
11use crate::{Device, Error, PublishOptions, Publishable};
12
13/// `PortForward`
14#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
15pub struct PortForward<P>
16where
17    P: Into<Bytes> + Clone + Send,
18{
19    headers: HashMap<String, String>,
20    payload: P,
21}
22
23impl<P> PortForward<P>
24where
25    P: Into<Bytes> + Clone + Send,
26{
27    /// Create a new `PortForward` message.
28    #[must_use]
29    pub const fn new(headers: HashMap<String, String>, payload: P) -> Self {
30        Self { headers, payload }
31    }
32}
33
34impl<P> Publishable for PortForward<P>
35where
36    P: Into<Bytes> + Clone + Send,
37{
38    type Error = Error;
39
40    fn topic(&self, device: &Device) -> impl Into<String> + Send {
41        format!(
42            "registries/{}/devices/{}/pfwd/rx",
43            device.registry_id(),
44            device.serial(),
45        )
46    }
47
48    fn payload(&self) -> Result<impl Into<bytes::Bytes> + Send, Error> {
49        Ok(self.payload.clone())
50    }
51
52    fn publish_overrides(&self) -> PublishOptions {
53        PublishOptions {
54            user_properties: Some(self.headers.clone().into_iter().collect()),
55            ..Default::default()
56        }
57    }
58}
59
60impl<P> Hash for PortForward<P>
61where
62    P: Into<Bytes> + Clone + Hash + Send,
63{
64    fn hash<H: Hasher>(&self, state: &mut H) {
65        let mut kv_hashes: Vec<u64> = self
66            .headers
67            .iter()
68            .map(|(k, v)| {
69                let mut hasher = DefaultHasher::new();
70                k.hash(&mut hasher);
71                v.hash(&mut hasher);
72                hasher.finish()
73            })
74            .collect();
75
76        kv_hashes.sort_unstable();
77
78        for h in kv_hashes {
79            h.hash(state);
80        }
81
82        self.payload.hash(state);
83    }
84}