diff --git a/Cargo.toml b/Cargo.toml index 86dc791..8645ffa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,5 @@ meval = "0.2" lazy_static = "1.4" sedregex = "0.2" rusqlite = { version = "0.28", features = ["bundled"] } -warp = "0.3" futures-util = "0.3" irc = { version = "0.15", default-features = false, features = ["tls-rust"] } -tera = { version = "1.15", default-features = false } diff --git a/src/database.rs b/src/database.rs index bf288ef..cd5838a 100644 --- a/src/database.rs +++ b/src/database.rs @@ -9,8 +9,8 @@ use tokio::sync::{ enum Task { AddQuote(oneshot::Sender, Quote), GetQuote(oneshot::Sender>, Option), - Search(oneshot::Sender>>, String), - Random20(oneshot::Sender>>), + SearchQuotes(oneshot::Sender>>, String), + RandomNQuotes(oneshot::Sender>>, u8), } pub struct DbExecutor { @@ -29,8 +29,7 @@ impl DbExecutor { let (tx, rx) = unbounded_channel(); let db = rusqlite::Connection::open(dbpath)?; db.execute( - "create table if not exists quotes(id integer primary key,\ - username text not null, quote text not null)", + "create table if not exists quotes(id integer primary key, username text not null, quote text not null)", [], )?; tracing::debug!("Database connected ({})", dbpath); @@ -62,13 +61,13 @@ impl DbExecutor { }); tx.send(quote).unwrap(); } - Task::Search(tx, query) => { - tx.send(self.yield_quotes("select quote,username from quotes where quote like '%'||?1||'%' order by quote asc limit 50", params![query])).unwrap(); + Task::SearchQuotes(tx, query) => { + tx.send(self.yield_quotes("select quote,username from quotes where quote like '%'||?1||'%' order by quote asc limit 5", params![query])).unwrap(); } - Task::Random20(tx) => { + Task::RandomNQuotes(tx, count) => { tx.send(self.yield_quotes( - "select quote,username from quotes order by random() limit 20", - params![], + "select quote,username from quotes order by random() limit ?", + params![count], )) .unwrap(); } @@ -136,6 +135,6 @@ impl ExecutorConnection { Option, author: Option ); - executor_wrapper!(search, Task::Search, Option>, query: String); - executor_wrapper!(random20, Task::Random20, Option>); + executor_wrapper!(search_quotes, Task::SearchQuotes, Option>, query: String); + executor_wrapper!(random_n_quotes, Task::RandomNQuotes, Option>, count: u8); } diff --git a/src/main.rs b/src/main.rs index 557652b..530daa0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,7 +25,6 @@ use crate::database::{DbExecutor, ExecutorConnection, Quote}; mod bots; mod database; -mod web_service; // this will be displayed when the help command is used const HELP: &[&str] = &[ @@ -79,8 +78,9 @@ struct ClientConf { spotify_client_secret: String, prefix: String, db_path: Option, - http_listen: Option, - git_channel: String, + // reserved for future + _http_listen: Option, + _git_channel: String, } #[tokio::main] @@ -138,14 +138,6 @@ async fn main() -> anyhow::Result<()> { let (ctx, _) = broadcast::channel(1); let (etx, mut erx) = unbounded_channel(); - let web_task = tokio::spawn(web_service::run( - db_conn.clone(), - client.clone(), - client_config.git_channel, - http_listen, - ctx.subscribe(), - )); - let state = AppState { prefix: client_config.prefix, client: client.clone(), @@ -177,9 +169,6 @@ async fn main() -> anyhow::Result<()> { tracing::info!("Closing services..."); let _ = ctx.send(()); - web_task - .await - .unwrap_or_else(|e| tracing::warn!("Couldn't join the web service: {:?}", e)); message_loop_task .await .unwrap_or_else(|e| tracing::warn!("Couldn't join the web service: {:?}", e)); diff --git a/src/web_service.rs b/src/web_service.rs deleted file mode 100644 index f18510b..0000000 --- a/src/web_service.rs +++ /dev/null @@ -1,143 +0,0 @@ -use crate::database::Quote; -use crate::ExecutorConnection; -use irc::client::Client; -use lazy_static::lazy_static; -use reqwest::StatusCode; -use serde::{Deserialize, Serialize}; -use serde_json::Value::Null; -use std::net::SocketAddr; -use std::sync::Arc; -use tera::{Context, Tera}; -use tokio::sync::broadcast::Receiver; -use warp::{reply, Filter, Reply}; - -lazy_static! { - static ref TERA: Tera = Tera::new("templates/**/*").unwrap(); -} - -pub async fn run( - db: ExecutorConnection, - wh_irc: Arc, - wh_channel: String, - listen: SocketAddr, - mut cancel: Receiver<()>, -) { - let quote_get = warp::get() - .and(warp::path("quotes")) - .and(warp::query::()) - .and(warp::any().map(move || db.clone())) - .then(handle_get_quote); - - let webhook_post = warp::path("webhook") - .and(warp::post()) - .and(warp::body::json()) - .and(warp::any().map(move || wh_irc.clone())) - .and(warp::any().map(move || wh_channel.clone())) - .map(handle_webhook); - - let routes = webhook_post.or(quote_get); - warp::serve(routes) - .bind_with_graceful_shutdown(listen, async move { - let _ = cancel.recv().await; - }) - .1 - .await; - tracing::info!("Web service finished"); -} - -#[derive(Serialize)] -struct QuotesTemplate { - quotes: Option>, - flash: Option, -} - -#[derive(Deserialize)] -struct QuotesQuery { - q: Option, -} - -async fn handle_get_quote(query: QuotesQuery, db: ExecutorConnection) -> impl Reply { - let template = if let Some(q) = query.q { - if let Some(quotes) = db.search(q.clone()).await { - let quotes_count = quotes.len(); - QuotesTemplate { - quotes: Some(quotes), - flash: Some(format!( - "Displaying {}/50 results for query \"{}\"", - quotes_count, q - )), - } - } else { - QuotesTemplate { - quotes: None, - flash: Some("A database error has occurred".into()), - } - } - } else { - QuotesTemplate { - quotes: db.random20().await, - flash: Some("Displaying up to 20 random quotes".into()), - } - }; - match TERA.render("quotes.html", &Context::from_serialize(&template).unwrap()) { - Ok(o) => reply::html(o).into_response(), - Err(e) => { - tracing::warn!("Error while rendering template: {}", e); - reply::with_status( - "Failed to render template", - StatusCode::INTERNAL_SERVER_ERROR, - ) - .into_response() - } - } -} - -#[allow(clippy::needless_pass_by_value)] -fn handle_webhook(json: serde_json::Value, irc: Arc, channel: String) -> impl Reply { - if json["commits"] != Null { - let commits = json["commits"].as_array().unwrap(); - let repo = &json["repository"]["full_name"].as_str().unwrap().trim(); - if commits.len() == 1 { - let author = &json["commits"][0]["author"]["name"] - .as_str() - .unwrap() - .trim(); - let message = &json["commits"][0]["message"].as_str().unwrap().trim(); - if let Err(e) = irc.send_privmsg( - channel, - format!("New commit on {}: {} - {}", repo, message, author), - ) { - return reply::with_status( - format!("An error has occurred: {}", e), - StatusCode::INTERNAL_SERVER_ERROR, - ) - .into_response(); - } - } else { - if let Err(e) = irc.send_privmsg( - channel.clone(), - format!("{} new commits on {}:", commits.len(), repo), - ) { - return reply::with_status( - format!("An error has occurred: {}", e), - StatusCode::INTERNAL_SERVER_ERROR, - ) - .into_response(); - } - for commit in commits { - let author = &commit["author"]["name"].as_str().unwrap().trim(); - let message = &commit["message"].as_str().unwrap().trim(); - if let Err(e) = - irc.send_privmsg(channel.clone(), format!("{} - {}", author, message)) - { - return reply::with_status( - format!("An error has occurred: {}", e), - StatusCode::INTERNAL_SERVER_ERROR, - ) - .into_response(); - } - } - } - } - StatusCode::CREATED.into_response() -} diff --git a/templates/quotes.html b/templates/quotes.html deleted file mode 100644 index 1238708..0000000 --- a/templates/quotes.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - # überbot quotes - - -
-
- - -
- {% if flash %} -

{{ flash }}

- {% endif %} - {% if quotes %} - - - - - - - - - {% for q in quotes %} - - - - - {% endfor %} - -
AuthorQuote
{{ q.author }}{{ q.quote }}
- {% endif %} -
- - \ No newline at end of file