1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Default, Serialize, Deserialize)]
4pub struct NtfyMsg {
5 pub topic: String,
6 #[serde(skip_serializing_if = "Option::is_none")]
7 pub message: Option<String>,
8 #[serde(skip_serializing_if = "Option::is_none")]
9 pub title: Option<String>,
10 #[serde(skip_serializing_if = "Option::is_none")]
11 pub tags: Option<Vec<String>>,
12 #[serde(skip_serializing_if = "Option::is_none")]
13 pub priority: Option<NtfyPriority>,
14 #[serde(skip_serializing_if = "Option::is_none")]
15 pub attach: Option<String>,
16 #[serde(skip_serializing_if = "Option::is_none")]
17 pub filename: Option<String>,
18 #[serde(skip_serializing_if = "Option::is_none")]
19 pub click: Option<String>,
20 #[serde(skip_serializing_if = "Option::is_none")]
21 pub actions: Option<Vec<NtfyAction>>,
22 #[serde(skip_serializing_if = "Option::is_none")]
23 pub delay: Option<String>,
24 #[serde(skip_serializing_if = "Option::is_none")]
25 pub email: Option<String>,
26}
27
28impl NtfyMsg {
29 pub fn new(topic: &str) -> NtfyMsg {
30 NtfyMsg {
31 topic: String::from(topic),
32 ..Default::default()
33 }
34 }
35
36 pub fn builder(topic: &str) -> NtfyMsgBuilder {
37 NtfyMsgBuilder::new(topic)
38 }
39}
40
41pub struct NtfyMsgBuilder {
42 msg: NtfyMsg,
43}
44
45impl NtfyMsgBuilder {
46 pub fn new(topic: &str) -> NtfyMsgBuilder {
47 NtfyMsgBuilder {
48 msg: NtfyMsg::new(topic),
49 }
50 }
51
52 pub fn topic(mut self, topic: &str) -> NtfyMsgBuilder {
53 self.msg.topic = String::from(topic);
54 self
55 }
56
57 pub fn message(mut self, message: &str) -> NtfyMsgBuilder {
58 self.msg.message = Some(String::from(message));
59 self
60 }
61
62 pub fn title(mut self, title: &str) -> NtfyMsgBuilder {
63 self.msg.title = Some(String::from(title));
64 self
65 }
66
67 pub fn tags(mut self, tags: Vec<String>) -> NtfyMsgBuilder {
68 self.msg.tags = Some(tags);
69 self
70 }
71
72 pub fn add_tag(mut self, tag: &str) -> NtfyMsgBuilder {
73 if self.msg.tags.is_none() {
74 self.msg.tags = Some(vec![String::from(tag)]);
75 } else {
76 self.msg.tags.as_mut().unwrap().push(String::from(tag));
77 }
78 self
79 }
80
81 pub fn priority(mut self, priority: NtfyPriority) -> NtfyMsgBuilder {
82 self.msg.priority = Some(priority);
83 self
84 }
85
86 pub fn attach(mut self, attach: &str) -> NtfyMsgBuilder {
87 self.msg.attach = Some(String::from(attach));
88 self
89 }
90
91 pub fn filename(mut self, filename: &str) -> NtfyMsgBuilder {
92 self.msg.filename = Some(String::from(filename));
93 self
94 }
95
96 pub fn click(mut self, click: &str) -> NtfyMsgBuilder {
97 self.msg.click = Some(String::from(click));
98 self
99 }
100
101 pub fn actions(mut self, actions: Vec<NtfyAction>) -> NtfyMsgBuilder {
102 self.msg.actions = Some(actions);
103 self
104 }
105
106 pub fn add_action(mut self, action: NtfyAction) -> NtfyMsgBuilder {
107 if self.msg.actions.is_none() {
108 self.msg.actions = Some(vec![action]);
109 } else {
110 self.msg.actions.as_mut().unwrap().push(action);
111 }
112 self
113 }
114
115 pub fn delay(mut self, delay: &str) -> NtfyMsgBuilder {
116 self.msg.delay = Some(String::from(delay));
117 self
118 }
119
120 pub fn email(mut self, email: &str) -> NtfyMsgBuilder {
121 self.msg.email = Some(String::from(email));
122 self
123 }
124
125 pub fn build(self) -> NtfyMsg {
126 self.msg
127 }
128}
129
130#[derive(Debug, Clone, Default, Serialize, Deserialize)]
131pub struct NtfyAction {
132 pub action: NtfyActionType,
133 pub label: String,
134 pub url: String,
135 #[serde(skip_serializing_if = "Option::is_none")]
136 pub clear: Option<bool>,
137}
138
139impl NtfyAction {
140 pub fn new(label: String, url: String) -> NtfyAction {
141 NtfyAction {
142 action: NtfyActionType::View,
143 label,
144 url,
145 clear: None,
146 }
147 }
148}
149
150#[repr(u8)]
151#[non_exhaustive]
152#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
153#[serde(from = "u8")]
154#[serde(into = "u8")]
155pub enum NtfyPriority {
156 Minimum,
157 Low,
158 Default,
159 High,
160 Maximum,
161}
162
163impl Default for NtfyPriority {
164 fn default() -> Self {
165 NtfyPriority::Default
166 }
167}
168
169impl From<NtfyPriority> for u8 {
170 fn from(priority: NtfyPriority) -> Self {
171 match priority {
172 NtfyPriority::Minimum => 1,
173 NtfyPriority::Low => 2,
174 NtfyPriority::Default => 3,
175 NtfyPriority::High => 4,
176 NtfyPriority::Maximum => 5,
177 }
178 }
179}
180
181impl From<u8> for NtfyPriority {
182 fn from(value: u8) -> Self {
183 match value {
184 1 => NtfyPriority::Minimum,
185 2 => NtfyPriority::Low,
186 4 => NtfyPriority::High,
187 5 => NtfyPriority::Maximum,
188 _ => NtfyPriority::Default,
189 }
190 }
191}
192
193#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
194#[serde(rename_all = "lowercase")]
195pub enum NtfyActionType {
196 View,
197 Broadcast,
198 Http,
199}
200
201impl NtfyActionType {
202 pub fn value(&self) -> &'static str {
203 match self {
204 Self::View => "view",
205 Self::Broadcast => "broadcast",
206 Self::Http => "http",
207 }
208 }
209}
210
211impl Default for NtfyActionType {
212 fn default() -> Self {
213 NtfyActionType::View
214 }
215}
216
217#[derive(Debug, Clone, Default, Serialize, Deserialize)]
220pub struct NtfyResponse {
221 pub id: String,
222 pub time: u64,
223 pub event: String,
224 pub topic: String,
225 #[serde(skip_serializing_if = "Option::is_none")]
226 pub message: Option<String>,
227 #[serde(skip_serializing_if = "Option::is_none")]
228 pub title: Option<String>,
229 #[serde(skip_serializing_if = "Option::is_none")]
230 pub tags: Option<Vec<String>>,
231 #[serde(skip_serializing_if = "Option::is_none")]
232 pub priority: Option<NtfyPriority>,
233 #[serde(skip_serializing_if = "Option::is_none")]
234 pub click: Option<String>,
235 #[serde(skip_serializing_if = "Option::is_none")]
236 pub action: Option<Vec<NtfyAction>>,
237 #[serde(skip_serializing_if = "Option::is_none")]
238 pub attachment: Option<NtfyAttachment>,
239}
240
241#[derive(Debug, Clone, Default, Serialize, Deserialize)]
242pub struct NtfyAttachment {
243 pub name: String,
244 pub url: String,
245 #[serde(skip_serializing_if = "Option::is_none")]
246 pub r#type: Option<String>,
247 #[serde(skip_serializing_if = "Option::is_none")]
248 pub size: Option<u64>,
249 #[serde(skip_serializing_if = "Option::is_none")]
250 pub expires: Option<u64>,
251}
252
253#[derive(Debug, Clone, Default, Serialize, Deserialize)]
254pub struct NtfyErrorResponse {
255 pub code: u64,
256 pub http: u16,
257 pub error: String,
258 pub link: String,
259}