aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/actions/mod.rs
blob: bf784143c6385868d13919516b4b8e83752f6090 (plain) (blame)
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
}