Removing passthrough for message send handler

This means we get more opaque errors for the clients but it also results in way less code to maintain
This commit is contained in:
shockrah 2021-03-30 21:39:44 -07:00
parent d88948385d
commit 15b56353b8

View File

@ -4,15 +4,12 @@ use tokio::fs;
use tokio::io::AsyncWriteExt; use tokio::io::AsyncWriteExt;
use mysql_async::params; use mysql_async::params;
use mysql_async::{Pool, Conn}; use mysql_async::Pool;
use mysql_async::prelude::Queryable; use mysql_async::prelude::Queryable;
use mysql_async::error::Error as SqlError; use mysql_async::Error as SqlError;
use mysql_async::QueryResult;
use mysql_async::BinaryProtocol;
use crate::Response;
use crate::{Response, sql_err}; use crate::{UBigInt, BigInt};
use crate::{UBigInt, BigInt, VarChar};
use crate::{Message, UserMessage}; use crate::{Message, UserMessage};
use rand::RngCore; use rand::RngCore;
@ -33,42 +30,12 @@ impl Message {
} }
} }
fn message_passthrough_no_err(res: Result<QueryResult<Conn, BinaryProtocol>, SqlError>, passthrough: Self)
-> Result<Response<Self>, SqlError> {
/* You shouldn't have cum here.webm
* Basically sending messages with mysql is kinda painful so we
* do some special error checking by hand to see if
* a message was sent to an existing channel.
* The whole point of this is to avoid sending back a 500 to user clients
* which may cause confusing error handling in userland. This means we have
* confusing error handling on the server side but one of the parties has to
* do this stupid check so fuck it at least its mostly pointers anyway
*/
if let Err(e) = res {
return match e {
SqlError::Server(err) => {
if err.code == 1452 {
return Ok(Response::RestrictedInput("Channel not found".into()))
}
else {
Ok(Response::Other(sql_err!("db::messages::send")))
}
},
_ => Ok(Response::Other(sql_err!("db::messages::send")))
}
}
// all good response
else {
return Ok(Response::Row(passthrough));
}
}
pub async fn send(p: &Pool, content: &str, content_type: &str, cid: UBigInt, uid: UBigInt) -> Result<Response<Self>, SqlError> { pub async fn send(p: &Pool, content: &str, content_type: &str, cid: UBigInt, uid: UBigInt) -> Result<Response<Self>, SqlError> {
//! @returns on_sucess -> empty //! @returns on_sucess -> empty
//! @returns on_failure Err(SqlErr) //! @returns on_failure Err(SqlErr)
let conn = p.get_conn().await?; let mut conn = p.get_conn().await?;
let q = "INSERT INTO messages let q = "INSERT INTO messages
(id, time, content, content_type, author_id, channel_id) (id, time, content, content_type, author_id, channel_id)
VALUES (id, :time, :content, :ctype, :author, :channel)"; VALUES (id, :time, :content, :ctype, :author, :channel)";
@ -84,7 +51,7 @@ impl Message {
if content.len() > 4_000 { if content.len() > 4_000 {
Ok(Response::RestrictedInput("Large text not allowed".into())) Ok(Response::RestrictedInput("Large text not allowed".into()))
} else { } else {
let res = conn.prep_exec(q, params!{ let res = conn.exec_drop(q, params!{
"id" => id, "id" => id,
"time" => now, "time" => now,
"content" => content, "content" => content,
@ -92,8 +59,13 @@ impl Message {
"author" => uid, "author" => uid,
"channel" => cid "channel" => cid
}).await; }).await;
match Ok(res) {
Ok(_) => {
let msg = Message::new(id, now, content, content_type, uid, cid); let msg = Message::new(id, now, content, content_type, uid, cid);
Self::message_passthrough_no_err(res, msg) Ok(Response::Row(msg))
},
Err(e) => Err(e)
}
} }
}, },
_ => { _ => {
@ -117,7 +89,7 @@ impl Message {
}; };
let content_ref = format!("{cid}-{time}.{ext}", cid=cid, time=now, ext=extension); let content_ref = format!("{cid}-{time}.{ext}", cid=cid, time=now, ext=extension);
let res = conn.prep_exec(q, params!{ let res = conn.exec_drop(q, params!{
"id" => id, "id" => id,
"time" => now, "time" => now,
"content" => &content_ref, // store a ref to a file instead of the actual payload "content" => &content_ref, // store a ref to a file instead of the actual payload
@ -125,13 +97,13 @@ impl Message {
"author" => uid, "author" => uid,
"channel" => cid "channel" => cid
}).await; }).await;
let msg = Message::new(id, now, content, content_type, uid, cid); if let Ok(ret) = res {
if let Ok(ret) = Self::message_passthrough_no_err(res, msg) {
// now save the data to disk // now save the data to disk
match fs::File::create(content_ref).await { match fs::File::create(content_ref).await {
Ok(mut file) => { Ok(mut file) => {
file.write_all(content.as_bytes()).await.expect("Failed to write, but the ref is saved"); file.write_all(content.as_bytes()).await.expect("Failed to write, but the ref is saved");
Ok(ret) let msg = Message::new(id, now, content, content_type, uid, cid);
Ok(Response::Row(msg))
}, },
Err(_) => { Err(_) => {
Ok(Response::Other("Saved ref but couldn't save file data".into())) Ok(Response::Other("Saved ref but couldn't save file data".into()))
@ -156,7 +128,7 @@ impl Message {
Ok(Response::RestrictedInput("Invalid start/end parameters".into())) Ok(Response::RestrictedInput("Invalid start/end parameters".into()))
} }
else { else {
let conn = p.get_conn().await?; let mut conn = p.get_conn().await?;
let limit = if let Some(limit) = limit { let limit = if let Some(limit) = limit {
match limit { match limit {
1 ..= MAX_MESSAGES => limit, 1 ..= MAX_MESSAGES => limit,
@ -172,17 +144,13 @@ impl Message {
WHERE channel_id = :channel AND time >= :start AND time < :end WHERE channel_id = :channel AND time >= :start AND time < :end
LIMIT :limit"; LIMIT :limit";
let select_result = conn.prep_exec( let params = params!{
q, params!{
"start" => start, "start" => start,
"end" => end, "end" => end,
"channel" => channel_id, "channel" => channel_id,
"limit" => limit "limit" => limit
}).await?; };
let messages = conn.exec_map(q, params, |(name, id, time, content, content_type, author_id)| {
let(_conn, messages) = select_result.map_and_drop(|row| {
type Tuple = (VarChar, UBigInt, BigInt, String, String, UBigInt);
let (name, id, time, content, content_type, author_id): Tuple = mysql_async::from_row(row);
UserMessage { UserMessage {
id, id,
time, time,
@ -202,7 +170,7 @@ impl Message {
//! @returns on success : Set(Vec<Messages>) //! @returns on success : Set(Vec<Messages>)
//! @returns on user failure : RestrictedInput(String) //! @returns on user failure : RestrictedInput(String)
//! @returns on failure : Err(SqlError) //! @returns on failure : Err(SqlError)
let conn = p.get_conn().await?; let mut conn = p.get_conn().await?;
let limit = if let Some(limit) = limit{ let limit = if let Some(limit) = limit{
match limit { match limit {
1 ..= MAX_MESSAGES => limit, 1 ..= MAX_MESSAGES => limit,
@ -221,11 +189,8 @@ impl Message {
"limit" => limit "limit" => limit
}; };
let select_result = conn.prep_exec(q, params).await?; let messages = conn.exec_map(q, params,
|(id, time, content, content_type, author_id)| {
let (_conn, messages) = select_result.map_and_drop(|row| {
type Tuple = (UBigInt, BigInt, VarChar, VarChar, UBigInt);
let (id, time, content, content_type, author_id): Tuple = mysql_async::from_row(row);
Self { Self {
id, id,
time, time,