Improve the web service

This commit is contained in:
lemon-sh 2022-01-30 18:26:09 +01:00
parent 336ed231f7
commit d191a339f8
4 changed files with 64 additions and 44 deletions

View file

@ -1,4 +1,4 @@
use rusqlite::{params, OptionalExtension};
use rusqlite::{params, OptionalExtension, Params};
use serde::Serialize;
use tokio::sync::{
mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
@ -10,7 +10,7 @@ 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>>>)
Random20(oneshot::Sender<Option<Vec<Quote>>>),
}
pub struct DbExecutor {
@ -63,35 +63,39 @@ impl DbExecutor {
tx.send(quote).unwrap();
}
Task::Search(tx, query) => {
tx.send(match self.db
.prepare("select quote,username from quotes where quote like '%'||?1||'%' order by quote asc limit 50")
.and_then(|mut v| v.query(params![query])
.and_then(|mut v| {
let mut quotes: Vec<Quote> = Vec::with_capacity(50);
while let Some(row) = v.next()? {
quotes.push(Quote {
quote: row.get(0)?,
author: row.get(1)?,
});
}
Ok(quotes)
}))
{
Ok(o) => {
Some(o)
}
Err(e) => {
tracing::error!("A database error has occurred: {}", e);
None
}
}).unwrap();
tx.send(self.yield_quotes("select quote,username from quotes where quote like '%'||?1||'%' order by quote asc limit 50", params![query])).unwrap();
}
Task::Random20(tx) => {
tx.send(None).unwrap();
tx.send(self.yield_quotes(
"select quote,username from quotes order by random() limit 20",
params![],
))
.unwrap();
}
}
}
}
fn yield_quotes<P: Params>(&self, sql: &str, params: P) -> Option<Vec<Quote>> {
match self.db.prepare(sql).and_then(|mut v| {
v.query(params).and_then(|mut v| {
let mut quotes: Vec<Quote> = Vec::with_capacity(50);
while let Some(row) = v.next()? {
quotes.push(Quote {
quote: row.get(0)?,
author: row.get(1)?,
});
}
Ok(quotes)
})
}) {
Ok(o) => Some(o),
Err(e) => {
tracing::error!("A database error has occurred: {}", e);
None
}
}
}
}
pub struct ExecutorConnection {
@ -107,13 +111,20 @@ impl Clone for ExecutorConnection {
}
macro_rules! executor_wrapper {
($name:ident, $task:expr, $ret:ty, $($arg:ident: $ty:ty),*) => {
pub async fn $name(&self, $($arg: $ty),*) -> $ret {
let (otx, orx) = oneshot::channel();
self.tx.send($task(otx, $($arg),*)).unwrap();
orx.await.unwrap()
}
}
($name:ident, $task:expr, $ret:ty, $($arg:ident: $ty:ty),*) => {
pub async fn $name(&self, $($arg: $ty),*) -> $ret {
let (otx, orx) = oneshot::channel();
self.tx.send($task(otx, $($arg),*)).unwrap();
orx.await.unwrap()
}
};
($name:ident, $task:expr, $ret:ty) => {
pub async fn $name(&self) -> $ret {
let (otx, orx) = oneshot::channel();
self.tx.send($task(otx)).unwrap();
orx.await.unwrap()
}
};
}
impl ExecutorConnection {
@ -125,5 +136,11 @@ impl ExecutorConnection {
Option<Quote>,
author: Option<String>
);
executor_wrapper!(search, Task::Search, Option<Vec<Quote>>, query: String);
executor_wrapper!(
search,
Task::Search,
Option<Vec<Quote>>,
query: String
);
executor_wrapper!(random20, Task::Random20, Option<Vec<Quote>>);
}

View file

@ -296,7 +296,7 @@ async fn handle_privmsg(
if target == author {
state
.client
.send_privmsg(target, "You can't grab yourself")?;
.send_privmsg(origin, "You can't grab yourself")?;
return Ok(());
}
if let Some(prev_msg) = state.last_msgs.get(target) {
@ -308,16 +308,16 @@ async fn handle_privmsg(
})
.await
{
state.client.send_privmsg(target, "Quote added")?;
state.client.send_privmsg(origin, "Quote added")?;
} else {
state
.client
.send_privmsg(target, "A database error has occurred")?;
.send_privmsg(origin, "A database error has occurred")?;
}
} else {
state
.client
.send_privmsg(target, "No previous messages to grab")?;
.send_privmsg(origin, "No previous messages to grab")?;
}
} else {
state.client.send_privmsg(origin, "No nickname to grab")?;

View file

@ -19,7 +19,7 @@
<form method="get">
<label>
Search query
<input type="text" name="query" placeholder="Search..." required>
<input type="text" name="q" placeholder="Search..." required>
</label>
<button type="submit">Search</button>
</form>

View file

@ -58,16 +58,19 @@ struct QuotesTemplate {
#[derive(Deserialize)]
struct QuotesQuery {
query: Option<String>,
q: Option<String>
}
async fn handle_get_quote(query: QuotesQuery, db: ExecutorConnection) -> impl Reply {
let template = if let Some(query) = query.query {
if let Some(quotes) = db.search(query.clone()).await {
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, query)),
flash: Some(format!(
"Displaying {}/50 results for query \"{}\"",
quotes_count, q
)),
}
} else {
QuotesTemplate {
@ -77,8 +80,8 @@ async fn handle_get_quote(query: QuotesQuery, db: ExecutorConnection) -> impl Re
}
} else {
QuotesTemplate {
quotes: None,
flash: None,
quotes: db.random20().await,
flash: Some("Displaying up to 20 random quotes".into()),
}
};
match HANDLEBARS.render("quotes", &template) {