2021-03-10 03:08:34 +01:00
|
|
|
use rusqlite::params;
|
|
|
|
use warp::{Rejection, http::StatusCode};
|
|
|
|
|
|
|
|
use super::models;
|
|
|
|
use super::storage;
|
|
|
|
|
|
|
|
/// Inserts the given `message` into the database if it's valid.
|
2021-03-10 04:21:44 +01:00
|
|
|
pub async fn insert_message(mut message: models::Message, db_pool: storage::DatabaseConnectionPool) -> Result<impl warp::Reply, Rejection> {
|
2021-03-10 03:08:34 +01:00
|
|
|
// Validate the message
|
|
|
|
if !message.is_valid() { return Err(warp::reject::custom(models::ValidationError)); }
|
|
|
|
// Get a database connection
|
|
|
|
let db_conn = storage::get_db_conn(&db_pool)?;
|
|
|
|
// Insert the message
|
|
|
|
match db_conn.execute(
|
|
|
|
"INSERT INTO messages (text) VALUES (?1)",
|
|
|
|
params![message.text],
|
|
|
|
) {
|
2021-03-10 04:06:17 +01:00
|
|
|
Ok(_) => {
|
2021-03-10 04:55:58 +01:00
|
|
|
let id = db_conn.last_insert_rowid(); // TODO: Is there a risk of the `execute()` above and this call not being sync?
|
2021-03-10 04:21:44 +01:00
|
|
|
message.server_id = Some(id);
|
|
|
|
return Ok(warp::reply::json(&message));
|
2021-03-10 04:06:17 +01:00
|
|
|
}
|
2021-03-10 03:08:34 +01:00
|
|
|
Err(e) => {
|
|
|
|
println!("Couldn't insert message due to error: {:?}.", e);
|
|
|
|
return Err(warp::reject::custom(storage::DatabaseError));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the last `options.limit` messages from the database.
|
|
|
|
pub async fn get_messages(options: models::QueryOptions, db_pool: storage::DatabaseConnectionPool) -> Result<impl warp::Reply, Rejection> {
|
|
|
|
// Get a database connection
|
|
|
|
let db_conn = storage::get_db_conn(&db_pool)?;
|
2021-03-10 04:06:17 +01:00
|
|
|
// Unwrap parameters
|
|
|
|
let from_server_id = options.from_server_id.unwrap_or(0);
|
2021-03-10 03:08:34 +01:00
|
|
|
let limit = options.limit.unwrap_or(256); // Never return more than 256 messages at once
|
2021-03-10 04:06:17 +01:00
|
|
|
// Query the database
|
|
|
|
let raw_query: &str;
|
|
|
|
if options.from_server_id.is_some() {
|
2021-03-10 04:21:44 +01:00
|
|
|
raw_query = "SELECT id, text FROM messages WHERE rowid > (?1) LIMIT (?2)";
|
2021-03-10 04:06:17 +01:00
|
|
|
} else {
|
2021-03-10 04:21:44 +01:00
|
|
|
raw_query = "SELECT id, text FROM messages ORDER BY rowid DESC LIMIT (?2)";
|
2021-03-10 04:06:17 +01:00
|
|
|
}
|
|
|
|
let mut query = match db_conn.prepare(&raw_query) {
|
2021-03-10 03:08:34 +01:00
|
|
|
Ok(query) => query,
|
|
|
|
Err(e) => {
|
|
|
|
println!("Couldn't create database query due to error: {:?}.", e);
|
|
|
|
return Err(warp::reject::custom(storage::DatabaseError));
|
|
|
|
}
|
|
|
|
};
|
2021-03-10 04:06:17 +01:00
|
|
|
let rows = match query.query_map(params![from_server_id, limit], |row| {
|
2021-03-10 04:21:44 +01:00
|
|
|
Ok(models::Message { server_id : row.get(0)?, text : row.get(1)? })
|
2021-03-10 03:08:34 +01:00
|
|
|
}) {
|
|
|
|
Ok(rows) => rows,
|
|
|
|
Err(e) => {
|
|
|
|
println!("Couldn't query database due to error: {:?}.", e);
|
|
|
|
return Err(warp::reject::custom(storage::DatabaseError));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
// FIXME: It'd be cleaner to do the below using `collect()`, but the compiler has trouble
|
|
|
|
// inferring the item type of `rows` in that case.
|
|
|
|
let mut messages: Vec<models::Message> = Vec::new();
|
|
|
|
for row in rows {
|
|
|
|
match row {
|
|
|
|
Ok(message) => messages.push(message),
|
|
|
|
Err(e) => {
|
|
|
|
println!("Excluding message from response due to database error: {:?}.", e);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Return the messages
|
|
|
|
return Ok(warp::reply::json(&messages));
|
2021-03-10 03:29:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Deletes the message with the given `row_id` from the database, if it's present.
|
2021-03-10 04:06:17 +01:00
|
|
|
pub async fn delete_message(row_id: i64, db_pool: storage::DatabaseConnectionPool) -> Result<impl warp::Reply, Rejection> {
|
2021-03-10 04:55:58 +01:00
|
|
|
// Get a database connection and open a transaction
|
2021-03-10 03:29:04 +01:00
|
|
|
let db_conn = storage::get_db_conn(&db_pool)?;
|
2021-03-10 04:55:58 +01:00
|
|
|
let tx = storage::get_tx(&db_conn)?;
|
2021-03-10 03:29:04 +01:00
|
|
|
// Delete the message if it's present
|
2021-03-10 04:55:58 +01:00
|
|
|
let changed_row_count = storage::execute("DELETE FROM messages WHERE rowid = (?1)", params![row_id], &db_conn)?;
|
|
|
|
// Update the deletions table if needed
|
|
|
|
if changed_row_count > 0 {
|
|
|
|
storage::execute("INSERT INTO deletions (id) VALUES (?1)", params![row_id], &db_conn);
|
2021-03-10 03:29:04 +01:00
|
|
|
}
|
2021-03-10 04:55:58 +01:00
|
|
|
// Commit
|
|
|
|
tx.commit();
|
|
|
|
// Return
|
|
|
|
return Ok(StatusCode::OK);
|
2021-03-10 03:08:34 +01:00
|
|
|
}
|