fundamentum_sdk_mqtt/models/
portforward.rs1use 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#[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 #[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}