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
|
use std::fmt;
use anyhow::Result;
use async_trait::async_trait;
use log::{debug, info, warn};
use serde::Deserialize;
use crate::message::MessageConfig;
use crate::message::MessageParams;
mod command;
#[cfg(feature = "desktop")]
mod desktop_notification;
#[cfg(feature = "email")]
mod email;
#[cfg(feature = "nostr")]
mod nostr;
#[cfg(feature = "ntfy")]
mod ntfy;
#[cfg(feature = "telegram")]
mod telegram;
mod terminal_print;
#[derive(Deserialize, Debug)]
#[serde(rename_all = "snake_case")]
#[serde(tag = "type")]
pub enum AnyActionConfig {
TerminalPrint,
Command(self::command::CommandConfig),
#[cfg(feature = "desktop")]
DesktopNotification,
#[cfg(feature = "ntfy")]
Ntfy(self::ntfy::NtfyConfig),
#[cfg(feature = "email")]
Email(self::email::EmailConfig),
#[cfg(feature = "telegram")]
Telegram(self::telegram::TelegramConfig),
#[cfg(feature = "nostr")]
Nostr(self::nostr::NostrConfig),
}
impl fmt::Display for AnyActionConfig {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
AnyActionConfig::TerminalPrint => write!(f, "terminal_print"),
AnyActionConfig::Command(_) => write!(f, "command"),
#[cfg(feature = "desktop")]
AnyActionConfig::DesktopNotification => write!(f, "desktop_notification"),
#[cfg(feature = "ntfy")]
AnyActionConfig::Ntfy(_) => write!(f, "ntfy"),
#[cfg(feature = "email")]
AnyActionConfig::Email(_) => write!(f, "email"),
#[cfg(feature = "telegram")]
AnyActionConfig::Telegram(_) => write!(f, "telegram"),
#[cfg(feature = "nostr")]
AnyActionConfig::Nostr(_) => write!(f, "nostr"),
}
}
}
#[async_trait]
pub trait Action<'a> {
async fn run(&self, params: Option<&MessageParams<'_, '_>>) -> Result<()>;
}
pub async fn get_action<'a>(
message_config: &'a MessageConfig,
action_config: &'a AnyActionConfig,
) -> Result<Box<dyn Action<'a> + 'a + Sync>> {
Ok(match action_config {
AnyActionConfig::TerminalPrint => Box::new(self::terminal_print::TerminalPrintAction::new(
message_config,
)),
AnyActionConfig::Command(config) => {
Box::new(self::command::CommandAction::new(message_config, config)?)
}
#[cfg(feature = "desktop")]
AnyActionConfig::DesktopNotification => Box::new(
self::desktop_notification::DesktopNotificationAction::new(message_config),
),
#[cfg(feature = "ntfy")]
AnyActionConfig::Ntfy(config) => {
Box::new(self::ntfy::NtfyAction::new(message_config, config)?)
}
#[cfg(feature = "email")]
AnyActionConfig::Email(config) => {
Box::new(self::email::EmailAction::new(message_config, config)?)
}
#[cfg(feature = "telegram")]
AnyActionConfig::Telegram(config) => {
Box::new(self::telegram::TelegramAction::new(message_config, config)?)
}
#[cfg(feature = "nostr")]
AnyActionConfig::Nostr(config) => {
Box::new(self::nostr::NostrAction::new(message_config, config).await?)
}
})
}
pub async fn get_actions<'a>(
message_config: &'a MessageConfig,
actions_config: &'a [AnyActionConfig],
) -> Vec<Box<dyn Action<'a> + 'a + Sync>> {
let mut result: Vec<Box<dyn Action + Sync>> = Default::default();
// TODO: parallelize this. It's hard because the result vector needs to be shared.
for action_config in actions_config {
debug!("registering action '{}'", action_config);
match get_action(message_config, action_config).await {
Ok(action) => {
info!("registered action '{}'", action_config);
result.push(action);
}
Err(e) => {
warn!("could not register action '{}': {}", action_config, e);
}
}
}
result
}
|