From d02084a22c40e81b77a4d527a47115e6b59a57d2 Mon Sep 17 00:00:00 2001 From: shockrah Date: Tue, 23 Mar 2021 17:16:05 -0700 Subject: [PATCH] + Adding proper file upload support ! Requirements for variable message fetching not yet met ! /message/get?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 --- json-api/Cargo.lock | 52 +++++++++++-------- json-api/db/Cargo.toml | 2 +- json-api/db/src/messages.rs | 100 ++++++++++++++++++++++++++++-------- 3 files changed, 111 insertions(+), 43 deletions(-) diff --git a/json-api/Cargo.lock b/json-api/Cargo.lock index a09230e..14c20db 100644 --- a/json-api/Cargo.lock +++ b/json-api/Cargo.lock @@ -354,6 +354,7 @@ version = "0.1.0" dependencies = [ "mysql_async", "serde", + "tokio 1.4.0", ] [[package]] @@ -584,7 +585,7 @@ dependencies = [ "http", "indexmap", "slab", - "tokio", + "tokio 0.2.25", "tokio-util 0.3.1", "tracing", "tracing-futures", @@ -656,7 +657,7 @@ dependencies = [ "itoa", "pin-project 1.0.5", "socket2", - "tokio", + "tokio 0.2.25", "tower-service", "tracing", "want", @@ -724,7 +725,7 @@ dependencies = [ "rand 0.7.3", "serde", "serde_json", - "tokio", + "tokio 0.2.25", "tokio-test", ] @@ -783,9 +784,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4aede83fc3617411dc6993bc8c70919750c1c257c6ca6a502aed6e0e2394ae" +checksum = "8916b1f6ca17130ec6568feccee27c156ad12037880833a3b842a823236502e7" [[package]] name = "libz-sys" @@ -871,7 +872,7 @@ checksum = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656" dependencies = [ "log", "mio", - "miow 0.3.6", + "miow 0.3.7", "winapi 0.3.9", ] @@ -900,11 +901,10 @@ dependencies = [ [[package]] name = "miow" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" dependencies = [ - "socket2", "winapi 0.3.9", ] @@ -928,7 +928,7 @@ dependencies = [ "serde", "serde_json", "thiserror", - "tokio", + "tokio 0.2.25", "tokio-tls", "tokio-util 0.2.0", "twox-hash", @@ -1449,18 +1449,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.124" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd761ff957cb2a45fbb9ab3da6512de9de55872866160b23c25f1a841e99d29f" +checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.124" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1800f7693e94e186f5e25a28291ae1570da908aff7d97a095dec1e56ff99069b" +checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" dependencies = [ "proc-macro2", "quote", @@ -1541,9 +1541,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "standback" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "decebb311175fdaf1bf8a14583716e93163c566db2ead1c1d608c3e1e4313cb8" +checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" dependencies = [ "version_check", ] @@ -1770,6 +1770,18 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "tokio" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134af885d758d645f0f0505c9a8b3f9bf8a348fd822e112ab5248138348f1722" +dependencies = [ + "autocfg", + "bytes 1.0.1", + "memchr", + "pin-project-lite 0.2.6", +] + [[package]] name = "tokio-macros" version = "0.2.6" @@ -1789,7 +1801,7 @@ checksum = "ed0049c119b6d505c4447f5c64873636c7af6c75ab0d45fd9f618d82acb8016d" dependencies = [ "bytes 0.5.6", "futures-core", - "tokio", + "tokio 0.2.25", ] [[package]] @@ -1799,7 +1811,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a70f4fcd7b3b24fb194f837560168208f669ca8cb70d0c4b862944452396343" dependencies = [ "native-tls", - "tokio", + "tokio 0.2.25", ] [[package]] @@ -1813,7 +1825,7 @@ dependencies = [ "futures-sink", "log", "pin-project-lite 0.1.12", - "tokio", + "tokio 0.2.25", ] [[package]] @@ -1827,7 +1839,7 @@ dependencies = [ "futures-sink", "log", "pin-project-lite 0.1.12", - "tokio", + "tokio 0.2.25", ] [[package]] diff --git a/json-api/db/Cargo.toml b/json-api/db/Cargo.toml index 97bbf4b..7b2e498 100644 --- a/json-api/db/Cargo.toml +++ b/json-api/db/Cargo.toml @@ -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"] } diff --git a/json-api/db/src/messages.rs b/json-api/db/src/messages.rs index ebb0ed1..5b7151e 100644 --- a/json-api/db/src/messages.rs +++ b/json-api/db/src/messages.rs @@ -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, 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, SqlError> ) -> Result, 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, 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) + } + } + } + + } }