Remove web service

This commit is contained in:
lemonsh 2022-07-15 17:40:41 +02:00
parent 02ae7570db
commit 2968081358
5 changed files with 13 additions and 219 deletions

View file

@ -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 }

View file

@ -9,8 +9,8 @@ use tokio::sync::{
enum Task {
AddQuote(oneshot::Sender<bool>, Quote),
GetQuote(oneshot::Sender<Option<Quote>>, Option<String>),
Search(oneshot::Sender<Option<Vec<Quote>>>, String),
Random20(oneshot::Sender<Option<Vec<Quote>>>),
SearchQuotes(oneshot::Sender<Option<Vec<Quote>>>, String),
RandomNQuotes(oneshot::Sender<Option<Vec<Quote>>>, 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<Quote>,
author: Option<String>
);
executor_wrapper!(search, Task::Search, Option<Vec<Quote>>, query: String);
executor_wrapper!(random20, Task::Random20, Option<Vec<Quote>>);
executor_wrapper!(search_quotes, Task::SearchQuotes, Option<Vec<Quote>>, query: String);
executor_wrapper!(random_n_quotes, Task::RandomNQuotes, Option<Vec<Quote>>, count: u8);
}

View file

@ -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<String>,
http_listen: Option<SocketAddr>,
git_channel: String,
// reserved for future
_http_listen: Option<SocketAddr>,
_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));

View file

@ -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<Client>,
wh_channel: String,
listen: SocketAddr,
mut cancel: Receiver<()>,
) {
let quote_get = warp::get()
.and(warp::path("quotes"))
.and(warp::query::<QuotesQuery>())
.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<Vec<Quote>>,
flash: Option<String>,
}
#[derive(Deserialize)]
struct QuotesQuery {
q: Option<String>,
}
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<Client>, 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()
}

View file

@ -1,49 +0,0 @@
<!doctype html>
<html lang="en" data-theme="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<style>
main {
--primary: #d81b60;
--primary-hover: #e91e63;
--primary-focus: rgba(216, 27, 96, 0.25);
--primary-inverse: #FFF;
}
</style>
<link rel="stylesheet" href="https://unpkg.com/@picocss/pico@latest/css/pico.classless.min.css">
<title># überbot quotes</title>
</head>
<body>
<main>
<form method="get">
<label>
Search query
<input type="text" name="q" placeholder="Search..." required>
</label>
<button type="submit">Search</button>
</form>
{% if flash %}
<p>{{ flash }}</p>
{% endif %}
{% if quotes %}
<table>
<thead>
<tr>
<td>Author</td>
<td>Quote</td>
</tr>
</thead>
<tbody>
{% for q in quotes %}
<tr>
<td>{{ q.author }}</td>
<td>{{ q.quote }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</main>
</body>
</html>