+ Adding proper file upload support
! Requirements for variable message fetching not yet met ! /message/get?id=<id> needs a way of passing back file contents ! The file upload is sketchy at best and not necessarily guaranteed to sync the database with the file system
This commit is contained in:
@@ -10,4 +10,4 @@ edition = "2018"
|
||||
mysql_async = "0.23.1"
|
||||
|
||||
serde = { version = "1.0.117", features = [ "derive" ] }
|
||||
|
||||
tokio = { version = "1", features = ["fs", "io-util"] }
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
use mysql_async::{params, Pool};
|
||||
use tokio::fs;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
|
||||
use mysql_async::params;
|
||||
use mysql_async::{Pool, Conn};
|
||||
use mysql_async::prelude::Queryable;
|
||||
use mysql_async::error::Error as SqlError;
|
||||
use mysql_async::QueryResult;
|
||||
use mysql_async::BinaryProtocol;
|
||||
|
||||
|
||||
use crate::{Response, sql_err};
|
||||
@@ -13,27 +19,7 @@ const MAX_MESSAGES: u64 = 1000;
|
||||
|
||||
|
||||
impl Message {
|
||||
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_failure Err(SqlErr)
|
||||
|
||||
let conn = p.get_conn().await?;
|
||||
let q = "INSERT INTO messages
|
||||
(time, content, content_type, author_id, channel_id)
|
||||
VALUES (:time, :content, :ctype, :author, :channel)";
|
||||
|
||||
let now: i64 = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("System time `NOW` failed")
|
||||
.as_millis() as i64;
|
||||
|
||||
let res = conn.prep_exec(q, params!{
|
||||
"time" => now,
|
||||
"content" => content,
|
||||
"ctype" => content_type,
|
||||
"author" => uid,
|
||||
"channel" => cid
|
||||
}).await;
|
||||
fn send_verify_error(res: Result<QueryResult<Conn, BinaryProtocol>, SqlError> ) -> Result<Response<Self>, SqlError> {
|
||||
if let Err(e) = res {
|
||||
return match e {
|
||||
SqlError::Server(err) => {
|
||||
@@ -52,6 +38,76 @@ impl Message {
|
||||
else {
|
||||
return Ok(Response::Empty);
|
||||
}
|
||||
}
|
||||
|
||||
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_failure Err(SqlErr)
|
||||
|
||||
let conn = p.get_conn().await?;
|
||||
let q = "INSERT INTO messages
|
||||
(time, content, content_type, author_id, channel_id)
|
||||
VALUES (:time, :content, :ctype, :author, :channel)";
|
||||
|
||||
let now: i64 = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("System time `NOW` failed")
|
||||
.as_millis() as i64;
|
||||
|
||||
match content_type {
|
||||
"text/plain" => {
|
||||
if content.len() > 4_000 {
|
||||
Ok(Response::RestrictedInput("Large text not allowed".into()))
|
||||
} else {
|
||||
let res = conn.prep_exec(q, params!{
|
||||
"time" => now,
|
||||
"content" => content,
|
||||
"ctype" => content_type,
|
||||
"author" => uid,
|
||||
"channel" => cid
|
||||
}).await;
|
||||
Self::send_verify_error(res)
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
if content.len() > 10_000_000 {
|
||||
Ok(Response::RestrictedInput("Large data not allowed".into()))
|
||||
} else {
|
||||
let extension = match content_type {
|
||||
"image/png" => "png",
|
||||
"image/jpeg" | "image/jpg" => "jpg",
|
||||
"application/webm" => "webm",
|
||||
"application/mp4" => "mp4",
|
||||
"application/mp3" => "mp3",
|
||||
_ => panic!("Bad file type sent to db layer {}", content_type)
|
||||
};
|
||||
let content_ref = format!("{cid}-{time}.{ext}", cid=cid, time=now, ext=extension);
|
||||
|
||||
let res = conn.prep_exec(q, params!{
|
||||
"time" => now,
|
||||
"content" => &content_ref, // store a ref to a file instead of the actual payload
|
||||
"ctype" => content_type,
|
||||
"author" => uid,
|
||||
"channel" => cid
|
||||
}).await;
|
||||
if let Ok(ret) = Self::send_verify_error(res) {
|
||||
// now save the data to disk
|
||||
match fs::File::create(content_ref).await {
|
||||
Ok(mut file) => {
|
||||
file.write_all(content.as_bytes()).await.expect("Failed to write, but the ref is saved");
|
||||
Ok(ret)
|
||||
},
|
||||
Err(_) => {
|
||||
Ok(Response::Other("Saved ref but couldn't save file data".into()))
|
||||
},
|
||||
}
|
||||
} else {
|
||||
Ok(Response::Success)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user