autopush_common/
notification.rs1use std::collections::HashMap;
3
4use serde_derive::{Deserialize, Serialize};
5use uuid::Uuid;
6
7use crate::util::ms_since_epoch;
8
9#[derive(Serialize, Default, Deserialize, Clone, Debug)]
10pub struct Notification {
14 #[serde(rename = "channelID")]
16 pub channel_id: Uuid,
17 pub version: String,
18 #[serde(skip_serializing)]
19 pub timestamp: u64,
20 #[serde(default = "default_ttl", skip_serializing)]
22 pub ttl: u64,
23 #[serde(skip_serializing)]
25 pub topic: Option<String>,
26 #[serde(skip_serializing_if = "Option::is_none")]
27 pub data: Option<String>,
28 #[serde(skip_serializing)]
29 pub sortkey_timestamp: Option<u64>,
30 #[serde(skip_serializing_if = "Option::is_none")]
31 pub headers: Option<HashMap<String, String>>,
32 #[serde(skip_serializing_if = "Option::is_none")]
33 pub reliability_id: Option<String>,
34 #[cfg(feature = "reliable_report")]
35 #[serde(skip_serializing_if = "Option::is_none")]
36 pub reliable_state: Option<crate::reliability::ReliabilityState>,
37}
38
39pub const TOPIC_NOTIFICATION_PREFIX: &str = "01";
40pub const STANDARD_NOTIFICATION_PREFIX: &str = "02";
41
42impl Notification {
43 pub fn chidmessageid(&self) -> String {
54 let chid = self.channel_id.as_hyphenated();
55
56 if let Some(ref topic) = self.topic {
57 format!("{TOPIC_NOTIFICATION_PREFIX}:{chid}:{topic}")
58 } else if let Some(sortkey_timestamp) = self.sortkey_timestamp {
59 format!(
60 "{STANDARD_NOTIFICATION_PREFIX}:{}:{}",
61 if sortkey_timestamp == 0 {
62 ms_since_epoch()
63 } else {
64 sortkey_timestamp
65 },
66 chid
67 )
68 } else {
69 warn!("🚨 LEGACY MESSAGE!? {:?} ", self);
70 format!("{}:{}", chid, self.version)
72 }
73 }
74
75 pub fn expiry(&self) -> u64 {
76 self.timestamp + self.ttl
77 }
78
79 pub fn expired(&self, at_sec: u64) -> bool {
82 at_sec >= self.expiry()
83 }
84
85 #[cfg(feature = "reliable_report")]
86 pub async fn record_reliability(
87 &mut self,
88 reliability: &crate::reliability::PushReliability,
89 state: crate::reliability::ReliabilityState,
90 ) {
91 self.reliable_state = reliability
92 .record(
93 &self.reliability_id,
94 state,
95 &self.reliable_state,
96 Some(self.expiry()),
97 )
98 .await
99 .inspect_err(|e| {
100 warn!("🔍⚠️ Unable to record reliability state log: {:?}", e);
101 })
102 .unwrap_or(Some(state));
103 }
104
105 #[cfg(feature = "reliable_report")]
106 pub fn clone_without_reliability_state(&self) -> Self {
107 let mut cloned = self.clone();
108 cloned.reliable_state = None;
109 cloned
110 }
111}
112
113pub(crate) fn default_ttl() -> u64 {
114 0
115}