1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
use super::Action;
use crate::message::MessageConfig;
use crate::message::MessageFormat;
use crate::message::MessageParams;
use anyhow::Result;
use async_trait::async_trait;
use ntfy::Auth;
use ntfy::Dispatcher;
use ntfy::Payload;
use ntfy::Priority;
use ntfy::Url;
use serde::Deserialize;
#[derive(Deserialize, Debug)]
#[serde(remote = "Priority")]
#[serde(rename_all = "snake_case")]
pub enum NtfyPriority {
Max = 5,
High = 4,
Default = 3,
Low = 2,
Min = 1,
}
#[derive(Deserialize, Debug)]
pub struct NtfyCredentials {
username: String,
password: String,
}
#[derive(Deserialize, Debug)]
pub struct NtfyConfig {
url: Option<String>,
proxy: Option<String>,
topic: Option<String>,
pub credentials: Option<NtfyCredentials>,
#[serde(with = "NtfyPriority")]
#[serde(default)]
pub priority: Priority,
pub tags: Option<Vec<String>>,
pub attach: Option<Url>,
pub filename: Option<String>,
pub delay: Option<String>,
pub email: Option<String>,
}
impl NtfyConfig {
pub fn url(&self) -> &str {
self.url.as_deref().unwrap_or("https://ntfy.sh")
}
pub fn topic(&self) -> &str {
self.topic.as_deref().unwrap_or(env!("CARGO_PKG_NAME"))
}
}
pub struct NtfyAction<'a> {
message_config: &'a MessageConfig,
dispatcher: Dispatcher,
payload_template: Payload,
}
impl<'a> NtfyAction<'a> {
pub fn new(message_config: &'a MessageConfig, ntfy_config: &'a NtfyConfig) -> Result<Self> {
let mut dispatcher_builder = Dispatcher::builder(ntfy_config.url());
if let Some(cred) = &ntfy_config.credentials {
dispatcher_builder =
dispatcher_builder.credentials(Auth::new(&cred.username, &cred.password));
}
if let Some(proxy) = &ntfy_config.proxy {
dispatcher_builder = dispatcher_builder.proxy(proxy);
}
let mut payload = Payload::new(ntfy_config.topic())
.markdown(match message_config.format() {
MessageFormat::Plain => false,
MessageFormat::Markdown => true,
MessageFormat::Html => true,
})
.priority(ntfy_config.priority.clone())
.tags(
ntfy_config
.tags
.as_deref()
.unwrap_or(&["rotating_light".to_string()]),
);
if let Some(attach) = &ntfy_config.attach {
payload = payload.attach(attach.clone());
}
if let Some(filename) = &ntfy_config.filename {
payload = payload.filename(filename.clone());
}
if let Some(delay) = &ntfy_config.delay {
payload = payload.delay(delay.parse()?);
}
if let Some(email) = &ntfy_config.email {
payload = payload.email(email.clone());
}
Ok(Self {
message_config,
dispatcher: dispatcher_builder.build()?,
payload_template: payload,
})
}
}
#[async_trait]
impl Action<'_> for NtfyAction<'_> {
fn name(&self) -> &'static str {
"ntfy"
}
async fn run(&self, params: Option<&MessageParams<'_, '_>>) -> Result<()> {
let payload = self
.payload_template
.clone()
.title(self.message_config.subject(params)?)
.message(self.message_config.body(params)?)
.click(self.message_config.get_tx_url(params)?.parse()?);
self.dispatcher.send(&payload).await?;
Ok(())
}
}
|