DEVELOPMENT ENVIRONMENT

~liljamo/canwa

ref: 9621cd5d4e6923d4fd326a3bf31ffa1bd457a196 canwa/src/service/mod.rs -rw-r--r-- 1.4 KiB
9621cd5dJonni Liljamo feat: separate routes to module 10 days ago
                                                                                
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
/*
 * Copyright (C) 2025 Jonni Liljamo <jonni@liljamo.com>
 *
 * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for
 * more information.
 */

use async_trait::async_trait;
use pastey::paste;

use crate::{config::ServiceConfig, routes::message::MessageForm};

pub mod email;
pub mod gotify;
pub mod matrix;

#[async_trait]
pub trait Service {
    async fn send(&self, form: &MessageForm) -> Result<(), Box<dyn std::error::Error>>;
}

macro_rules! make_service_match {
    ($client:expr, $service_config:expr, $service:expr) => {
        paste! {
            Box::new($service::[<$service:upper_camel Service>]::new(
                $client,
                $service_config
                    .as_any()
                    .downcast_ref::<$service::[<$service:upper_camel Config>]>()
                    .ok_or("no such service")?.clone(),
            )?)
        }
    };
    ($client:expr, $service_config:expr, $($service:expr),+) => {
        match $service_config.typetag_name() {
            $(stringify!($service) => make_service_match!($client, $service_config, $service)),+,
            _ => unreachable!(),

        }
    };
}

pub fn build(
    client: reqwest::Client,
    service_config: &dyn ServiceConfig,
) -> Result<Box<dyn Service + Send + Sync>, Box<dyn std::error::Error>> {
    let config: Box<dyn Service + Send + Sync> =
        make_service_match!(client, service_config, email, gotify, matrix);
    Ok(config)
}