M src/routes/message.rs => src/routes/message.rs +7 -29
@@ 10,9 10,8 @@ use std::sync::Arc;
use axum::{Json, http::HeaderMap, response::IntoResponse};
use reqwest::StatusCode;
use serde::Deserialize;
-use tracing::{error, info};
-use crate::state::State;
+use crate::{routes::extract_token, state::State};
#[derive(Deserialize)]
pub struct MessageForm {
@@ 27,38 26,17 @@ pub async fn message(
headers: HeaderMap,
Json(message): Json<MessageForm>,
) -> impl IntoResponse {
- let token = match headers.get("Authorization") {
- Some(token) => match token.to_str() {
- Ok(token) => token,
- Err(_) => {
- return (StatusCode::UNAUTHORIZED, "unauthorized");
- }
- },
- None => {
- return (StatusCode::UNAUTHORIZED, "unauthorized");
- }
- };
+ let token = extract_token!(headers);
- let notifier = match state.notifiers.iter().find(|(_k, v)| v.token == token) {
+ let notifier = match state.find_notifier(token) {
Some(n) => n,
None => return (StatusCode::UNAUTHORIZED, "unauthorized"),
};
- info!(msg = "message", notifier = notifier.0);
-
- for (_k, v) in state
- .services
- .iter()
- .filter(|(k, _v)| notifier.1.services.contains(k))
- {
- match v.send(&message).await {
- Ok(_) => {}
- Err(err) => {
- error!(msg = "message sending failed", ?err);
- return (StatusCode::INTERNAL_SERVER_ERROR, "failed to send message");
- }
- }
- }
+ if let Err(err) = state.send_message(notifier, &message).await {
+ tracing::error!(?err, "message sending failed");
+ return (StatusCode::INTERNAL_SERVER_ERROR, "failed to send message");
+ };
(StatusCode::OK, "")
}
M src/routes/mod.rs => src/routes/mod.rs +18 -0
@@ 6,3 6,21 @@
*/
pub mod message;
+
+macro_rules! extract_token {
+ ($headers:expr) => {
+ match $headers.get("Authorization") {
+ Some(token) => match token.to_str() {
+ Ok(token) => token,
+ Err(_) => {
+ return (StatusCode::UNAUTHORIZED, "unauthorized");
+ }
+ },
+ None => {
+ return (StatusCode::UNAUTHORIZED, "unauthorized");
+ }
+ }
+ };
+}
+
+use extract_token;
M src/service/email.rs => src/service/email.rs +4 -1
@@ 59,7 59,10 @@ impl EmailService {
#[async_trait]
impl Service for EmailService {
- async fn send(&self, form: &MessageForm) -> Result<(), Box<dyn std::error::Error>> {
+ async fn send(
+ &self,
+ form: &MessageForm,
+ ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let message = Message::builder()
.from(Mailbox::new(
self.config.from_name.clone(),
M src/service/gotify.rs => src/service/gotify.rs +4 -1
@@ 45,7 45,10 @@ impl GotifyService {
#[async_trait]
impl Service for GotifyService {
- async fn send(&self, form: &MessageForm) -> Result<(), Box<dyn std::error::Error>> {
+ async fn send(
+ &self,
+ form: &MessageForm,
+ ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let _ = self
.client
.post(format!("{}/message", self.config.instance))
M src/service/matrix.rs => src/service/matrix.rs +4 -1
@@ 61,7 61,10 @@ impl MatrixService {
#[async_trait]
impl Service for MatrixService {
- async fn send(&self, form: &MessageForm) -> Result<(), Box<dyn std::error::Error>> {
+ async fn send(
+ &self,
+ form: &MessageForm,
+ ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let body = if form.format_commonmark {
let bold_title = format!("**{}**", form.title.trim());
let title_parser = pulldown_cmark::Parser::new_ext(&bold_title, COMMONMARK_OPTIONS);
M src/service/mod.rs => src/service/mod.rs +4 -1
@@ 16,7 16,10 @@ pub mod matrix;
#[async_trait]
pub trait Service {
- async fn send(&self, form: &MessageForm) -> Result<(), Box<dyn std::error::Error>>;
+ async fn send(
+ &self,
+ form: &MessageForm,
+ ) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
}
macro_rules! make_service_match {
M src/state.rs => src/state.rs +25 -0
@@ 9,6 9,7 @@ use std::{collections::HashMap, sync::Arc};
use crate::{
config::{Config, NotifierConfig},
+ routes::message::MessageForm,
service::{self, Service},
};
@@ 40,4 41,28 @@ impl State {
notifiers: config.notifiers.clone(),
})
}
+
+ pub fn find_notifier(&self, token: &str) -> Option<(&String, &NotifierConfig)> {
+ self.notifiers.iter().find(|(_k, v)| v.token == token)
+ }
+
+ pub async fn send_message(
+ &self,
+ notifier: (&String, &NotifierConfig),
+ form: &MessageForm,
+ ) -> Result<(), Vec<Box<dyn std::error::Error + Send + Sync>>> {
+ let mut errs = vec![];
+
+ for (_k, v) in self
+ .services
+ .iter()
+ .filter(|(k, _v)| notifier.1.services.contains(k))
+ {
+ if let Err(err) = v.send(form).await {
+ errs.push(err);
+ };
+ }
+
+ if !errs.is_empty() { Err(errs) } else { Ok(()) }
+ }
}