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 {
13 #[serde(rename = "channelID")]
14 pub channel_id: Uuid,
15 pub version: String,
16 #[serde(default = "default_ttl", skip_serializing)]
17 pub ttl: u64,
18 #[serde(skip_serializing)]
19 pub topic: Option<String>,
20 #[serde(skip_serializing)]
21 pub timestamp: u64,
22 #[serde(skip_serializing_if = "Option::is_none")]
23 pub data: Option<String>,
24 #[serde(skip_serializing)]
25 pub sortkey_timestamp: Option<u64>,
26 #[serde(skip_serializing_if = "Option::is_none")]
27 pub headers: Option<HashMap<String, String>>,
28 #[serde(skip_serializing_if = "Option::is_none")]
29 pub reliability_id: Option<String>,
30 #[cfg(feature = "reliable_report")]
31 #[serde(skip_serializing_if = "Option::is_none")]
32 pub reliable_state: Option<crate::reliability::ReliabilityState>,
33}
34
35pub const TOPIC_NOTIFICATION_PREFIX: &str = "01";
36pub const STANDARD_NOTIFICATION_PREFIX: &str = "02";
37
38impl Notification {
39 pub fn chidmessageid(&self) -> String {
50 let chid = self.channel_id.as_hyphenated();
51 if let Some(ref topic) = self.topic {
52 format!("{TOPIC_NOTIFICATION_PREFIX}:{chid}:{topic}")
53 } else if let Some(sortkey_timestamp) = self.sortkey_timestamp {
54 format!(
55 "{STANDARD_NOTIFICATION_PREFIX}:{}:{}",
56 if sortkey_timestamp == 0 {
57 ms_since_epoch()
58 } else {
59 sortkey_timestamp
60 },
61 chid
62 )
63 } else {
64 warn!("🚨 LEGACY MESSAGE!? {:?} ", self);
65 format!("{}:{}", chid, self.version)
67 }
68 }
69
70 pub fn expiry(&self) -> u64 {
71 self.timestamp + self.ttl
72 }
73
74 pub fn expired(&self, at_sec: u64) -> bool {
77 at_sec >= self.expiry()
78 }
79
80 #[cfg(feature = "reliable_report")]
81 pub async fn record_reliability(
82 &mut self,
83 reliability: &crate::reliability::PushReliability,
84 state: crate::reliability::ReliabilityState,
85 ) {
86 self.reliable_state = reliability
87 .record(
88 &self.reliability_id,
89 state,
90 &self.reliable_state,
91 Some(self.expiry()),
92 )
93 .await
94 .inspect_err(|e| {
95 warn!("🔍⚠️ Unable to record reliability state log: {:?}", e);
96 })
97 .unwrap_or(Some(state));
98 }
99
100 #[cfg(feature = "reliable_report")]
101 pub fn clone_without_reliability_state(&self) -> Self {
102 let mut cloned = self.clone();
103 cloned.reliable_state = None;
104 cloned
105 }
106}
107
108fn default_ttl() -> u64 {
109 0
110}