chore: moved telegram notifier as optional feature

This commit is contained in:
əlemi 2023-12-22 23:37:02 +01:00
parent 62a7cdbbef
commit dbcf022019
Signed by: alemi
GPG key ID: A4895B84D311642C
4 changed files with 60 additions and 63 deletions

View file

@ -13,7 +13,13 @@ html-escape = "0.2.13"
lazy_static = "1.4.0" lazy_static = "1.4.0"
serde = { version = "1.0.189", features = ["derive"] } serde = { version = "1.0.189", features = ["derive"] }
serde_json = "1.0.107" serde_json = "1.0.107"
teloxide = { version = "0.12.2", features = ["macros"] }
tokio = { version = "1.33.0", features = ["macros", "rt-multi-thread"] } tokio = { version = "1.33.0", features = ["macros", "rt-multi-thread"] }
tracing = "0.1.39" tracing = "0.1.39"
tracing-subscriber = "0.3.17" tracing-subscriber = "0.3.17"
# telegram provider
teloxide = { version = "0.12.2", features = ["macros"], optional = true }
thiserror = "1.0.51"
[features]
default = []
telegram = ["dep:teloxide"]

View file

@ -1,20 +1,20 @@
use std::net::SocketAddr; use std::net::SocketAddr;
use axum::{routing::{get, put, post}, http::StatusCode, Json, Router, Form};
use serde::{Deserialize, Serialize};
use clap::Parser; use clap::Parser;
use teloxide::prelude::*;
use tokio::sync::RwLock;
lazy_static::lazy_static! { use crate::{storage::JsonFileStorageStrategy, routes::Context, notifications::console::ConsoleTracingNotifier};
static ref BOT : Bot = Bot::from_env();
static ref CHAT_ID : RwLock<ChatId> = RwLock::new(ChatId(0)); // TODO ewwwwwww mod notifications;
}
mod routes;
mod model;
mod storage;
#[derive(Debug, Clone, Parser)] #[derive(Debug, Clone, Parser)]
/// api for sending anonymous telegram messages to a specific user /// api for sending anonymous telegram messages to a specific user
struct CliArgs { struct CliArgs {
/// chat id of target user // chat id of target user
target: i64, //target: i64,
#[arg(long, short, default_value = "127.0.0.1:37812")] #[arg(long, short, default_value = "127.0.0.1:37812")]
/// host to bind onto /// host to bind onto
@ -27,63 +27,19 @@ async fn main() {
let args = CliArgs::parse(); let args = CliArgs::parse();
*CHAT_ID.write().await = ChatId(args.target);
let app = Router::new()
.route("/send", get(suggestion_help))
.route("/send", post(suggestion_form))
.route("/send", put(suggestion_json));
let addr : SocketAddr = args.addr.parse().expect("invalid host provided"); let addr : SocketAddr = args.addr.parse().expect("invalid host provided");
let storage = Box::new(JsonFileStorageStrategy::new("./storage.json"));
let state = Context::new(storage)
.register(Box::new(ConsoleTracingNotifier {}));
let router = routes::create_router_with_app_routes(state);
tracing::info!("listening on {}", addr); tracing::info!("listening on {}", addr);
axum::Server::bind(&addr) axum::Server::bind(&addr)
.serve(app.into_make_service()) .serve(router.into_make_service())
.await .await
.unwrap(); .unwrap();
} }
async fn suggestion_help() -> (StatusCode, Json<Suggestion>) {
let body = "use this endpoint to send me direct messages. this is the accepted structure. on PUT send as json, on POST send as form-urlencoded".to_string();
(StatusCode::OK, Json(Suggestion { author: None, contact: None, body }))
}
async fn suggestion_json(Json(payload): Json<Suggestion>) -> (StatusCode, Json<Acknowledgement>) {
suggestion_inner(payload).await
}
async fn suggestion_form(Form(payload): Form<Suggestion>) -> (StatusCode, Json<Acknowledgement>) {
suggestion_inner(payload).await
}
async fn suggestion_inner(payload: Suggestion) -> (StatusCode, Json<Acknowledgement>) {
let message = format!(
"[<code>{}</code>] <i>{}</i> | {}",
html_escape::encode_text(payload.author.as_deref().unwrap_or("anon")),
html_escape::encode_text(payload.contact.as_deref().unwrap_or("N/A")),
html_escape::encode_text(&payload.body)
);
match BOT
.send_message(*CHAT_ID.read().await, message)
.parse_mode(teloxide::types::ParseMode::Html)
.await
{
Ok(x) => (StatusCode::OK, Json(Acknowledgement::Sent(x.text().unwrap_or("").into()))),
Err(e) => (StatusCode::INTERNAL_SERVER_ERROR, Json(Acknowledgement::Refused(e.to_string()))),
}
}
#[derive(Serialize, Deserialize)]
struct Suggestion {
author: Option<String>,
contact: Option<String>,
body: String,
}
#[derive(Serialize)]
enum Acknowledgement {
Sent(String),
Refused(String),
}

11
src/notifications/mod.rs Normal file
View file

@ -0,0 +1,11 @@
#[cfg(feature = "telegram")]
pub mod telegram;
pub mod console;
#[async_trait::async_trait]
pub trait NotificationProcessor<T> : Send + Sync {
async fn process(&self, notification: &T);
}

View file

@ -0,0 +1,24 @@
use teloxide::prelude::*;
lazy_static::lazy_static! {
static ref BOT : Bot = Bot::from_env();
static ref CHAT_ID : RwLock<ChatId> = RwLock::new(ChatId(0)); // TODO ewwwwwww
}
async fn suggestion_inner(payload: Suggestion) -> (StatusCode, Json<Acknowledgement>) {
let message = format!(
"[<code>{}</code>] <i>{}</i> | {}",
html_escape::encode_text(payload.author.as_deref().unwrap_or("anon")),
html_escape::encode_text(payload.contact.as_deref().unwrap_or("N/A")),
html_escape::encode_text(&payload.body)
);
match BOT
.send_message(*CHAT_ID.read().await, message)
.parse_mode(teloxide::types::ParseMode::Html)
.await
{
Ok(x) => (StatusCode::OK, Json(Acknowledgement::Sent(x.text().unwrap_or("").into()))),
Err(e) => (StatusCode::INTERNAL_SERVER_ERROR, Json(Acknowledgement::Refused(e.to_string()))),
}
}