M src/main.rs => src/main.rs +5 -55
@@ 8,17 8,15 @@
use std::sync::Arc;
use axum::{
- Json, Router,
- http::HeaderMap,
- response::{Html, IntoResponse},
+ Router,
+ response::Html,
routing::{get, post},
};
use clap::Parser;
use reqwest::StatusCode;
-use serde::Deserialize;
use tokio::net::TcpListener;
use tower_http::trace::TraceLayer;
-use tracing::{error, info};
+use tracing::info;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
mod config;
@@ 26,6 24,7 @@ use config::Config;
mod state;
use state::State;
+mod routes;
mod service;
const LICENSE_HTML: &str = include_str!("../static/license.html");
@@ 74,7 73,7 @@ async fn main() {
"/message",
post({
let shared_state = Arc::clone(&state);
- move |headers, body| message(shared_state, headers, body)
+ move |headers, body| routes::message::message(shared_state, headers, body)
}),
)
.layer(TraceLayer::new_for_http())
@@ 85,52 84,3 @@ async fn main() {
let listener = TcpListener::bind(addr).await.unwrap();
axum::serve(listener, router).await.unwrap();
}
-
-#[derive(Deserialize)]
-struct MessageForm {
- title: String,
- message: String,
- #[serde(default)]
- format_commonmark: bool,
-}
-
-async fn message(
- state: Arc<State>,
- 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 notifier = match state.notifiers.iter().find(|(_k, v)| v.token == 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");
- }
- }
- }
-
- (StatusCode::OK, "")
-}
A src/routes/message.rs => src/routes/message.rs +64 -0
@@ 0,0 1,64 @@
+/*
+ * 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 std::sync::Arc;
+
+use axum::{Json, http::HeaderMap, response::IntoResponse};
+use reqwest::StatusCode;
+use serde::Deserialize;
+use tracing::{error, info};
+
+use crate::state::State;
+
+#[derive(Deserialize)]
+pub struct MessageForm {
+ pub title: String,
+ pub message: String,
+ #[serde(default)]
+ pub format_commonmark: bool,
+}
+
+pub async fn message(
+ state: Arc<State>,
+ 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 notifier = match state.notifiers.iter().find(|(_k, v)| v.token == 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");
+ }
+ }
+ }
+
+ (StatusCode::OK, "")
+}
A src/routes/mod.rs => src/routes/mod.rs +8 -0
@@ 0,0 1,8 @@
+/*
+ * 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.
+ */
+
+pub mod message;
M src/service/email.rs => src/service/email.rs +1 -1
@@ 14,8 14,8 @@ use lettre::{
use serde::{Deserialize, Serialize};
use crate::{
- MessageForm,
config::{ServiceConfig, deserialize_token},
+ routes::message::MessageForm,
};
use super::Service;
M src/service/gotify.rs => src/service/gotify.rs +1 -1
@@ 9,8 9,8 @@ use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use crate::{
- MessageForm,
config::{ServiceConfig, deserialize_token},
+ routes::message::MessageForm,
};
use super::Service;
M src/service/matrix.rs => src/service/matrix.rs +1 -1
@@ 10,8 10,8 @@ use serde::{Deserialize, Serialize};
use serde_json::json;
use crate::{
- MessageForm,
config::{ServiceConfig, deserialize_token},
+ routes::message::MessageForm,
};
use super::Service;
M src/service/mod.rs => src/service/mod.rs +1 -1
@@ 8,7 8,7 @@
use async_trait::async_trait;
use pastey::paste;
-use crate::{MessageForm, config::ServiceConfig};
+use crate::{config::ServiceConfig, routes::message::MessageForm};
pub mod email;
pub mod gotify;