diff --git a/Cargo.lock b/Cargo.lock index 37b542808..d5d55fca8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,30 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "actix" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1be241f88f3b1e7e9a3fbe3b5a8a0f6915b5a1d7ee0d9a248d3376d01068cc60" +dependencies = [ + "actix-rt", + "actix_derive", + "bitflags", + "bytes", + "crossbeam-channel", + "derive_more", + "futures-channel", + "futures-util", + "log", + "once_cell", + "parking_lot", + "pin-project", + "smallvec", + "tokio", + "tokio-util", + "trust-dns-proto", + "trust-dns-resolver", +] + [[package]] name = "actix-codec" version = "0.3.0" @@ -73,6 +98,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05dd80ba8f27c4a34357c07e338c8f5c38f8520e6d626ca1727d8fecc41b0cab" dependencies = [ + "actix", "actix-codec", "actix-connect", "actix-rt", @@ -142,6 +168,20 @@ dependencies = [ "twoway", ] +[[package]] +name = "actix-ratelimit" +version = "0.2.1" +source = "git+https://github.com/TerminalWitchcraft/actix-ratelimit?rev=870822067dfeae7cc0304352d81c4cb79ee27f5a#870822067dfeae7cc0304352d81c4cb79ee27f5a" +dependencies = [ + "actix", + "actix-http", + "actix-web", + "dashmap", + "failure", + "futures", + "log", +] + [[package]] name = "actix-router" version = "0.2.5" @@ -311,6 +351,17 @@ dependencies = [ "syn", ] +[[package]] +name = "actix_derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b95aceadaf327f18f0df5962fedc1bde2f870566a0b9f65c89508a3b1f79334c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "addr2line" version = "0.13.0" @@ -331,6 +382,9 @@ name = "ahash" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217" +dependencies = [ + "const-random", +] [[package]] name = "ahash" @@ -765,6 +819,26 @@ dependencies = [ "cache-padded", ] +[[package]] +name = "const-random" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02dc82c12dc2ee6e1ded861cf7d582b46f66f796d1b6c93fa28b911ead95da02" +dependencies = [ + "const-random-macro", + "proc-macro-hack", +] + +[[package]] +name = "const-random-macro" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc757bbb9544aa296c2ae00c679e81f886b37e28e59097defe0cf524306f6685" +dependencies = [ + "getrandom 0.2.0", + "proc-macro-hack", +] + [[package]] name = "const_fn" version = "0.4.2" @@ -876,6 +950,17 @@ dependencies = [ "subtle", ] +[[package]] +name = "dashmap" +version = "3.11.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f260e2fc850179ef410018660006951c1b55b79e8087e87111a2c388994b9b5" +dependencies = [ + "ahash 0.3.8", + "cfg-if 0.1.10", + "num_cpus", +] + [[package]] name = "derive_more" version = "0.99.11" @@ -992,6 +1077,28 @@ version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59" +[[package]] +name = "failure" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" +dependencies = [ + "backtrace", + "failure_derive", +] + +[[package]] +name = "failure_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + [[package]] name = "fastrand" version = "1.4.0" @@ -1500,6 +1607,7 @@ dependencies = [ "actix-cors", "actix-files", "actix-multipart", + "actix-ratelimit", "actix-rt", "actix-web", "async-trait", @@ -2543,6 +2651,18 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "synstructure" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + [[package]] name = "tempfile" version = "3.1.0" @@ -2736,6 +2856,7 @@ checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499" dependencies = [ "bytes", "futures-core", + "futures-io", "futures-sink", "log", "pin-project-lite", diff --git a/Cargo.toml b/Cargo.toml index b33eac78d..f031cc617 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,3 +50,8 @@ git = "https://github.com/launchbadge/sqlx/" branch = "master" default-features = false features = ["runtime-actix", "postgres", "chrono", "offline"] + +[dependencies.actix-ratelimit] +# Temp until actix-ratelimit bumps version on cargo +git = "https://github.com/TerminalWitchcraft/actix-ratelimit" +rev = "870822067dfeae7cc0304352d81c4cb79ee27f5a" diff --git a/sqlx-data.json b/sqlx-data.json index ca8fe2897..099a40018 100644 --- a/sqlx-data.json +++ b/sqlx-data.json @@ -672,6 +672,18 @@ ] } }, + "5d7425cfa91e332bf7cc14aa5c300b997e941c49757606f6b906cb5e060d3179": { + "query": "\n UPDATE mods\n SET updated = NOW()\n WHERE id = $1\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [] + } + }, "6562c876826ad3091a14eb50fa1f961a971c1d1bb158fc3dcb55d469a73facc6": { "query": "\n SELECT v.mod_id, v.author_id, v.name, v.version_number,\n v.changelog_url, v.date_published, v.downloads,\n v.release_channel\n FROM versions v\n WHERE v.id = $1\n ", "describe": { diff --git a/src/database/models/version_item.rs b/src/database/models/version_item.rs index f526ff3b8..090dad9ea 100644 --- a/src/database/models/version_item.rs +++ b/src/database/models/version_item.rs @@ -84,6 +84,17 @@ impl VersionBuilder { version.insert(&mut *transaction).await?; + sqlx::query!( + " + UPDATE mods + SET updated = NOW() + WHERE id = $1 + ", + self.mod_id as ModId, + ) + .execute(&mut *transaction) + .await?; + for file in self.files { file.insert(self.version_id, transaction).await?; } diff --git a/src/main.rs b/src/main.rs index 213283243..4c7881d1c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ use crate::file_hosting::S3Host; use actix_cors::Cors; +use actix_ratelimit::{MemoryStore, MemoryStoreActor, RateLimiter}; use actix_web::middleware::Logger; use actix_web::{http, web, App, HttpServer}; use env_logger::Env; @@ -205,6 +206,8 @@ async fn main() -> std::io::Result<()> { .and_then(|s| serde_json::from_str::>(&s).ok()) .unwrap_or_else(|| vec![String::from("http://localhost")]); + let store = MemoryStore::new(); + info!("Starting Actix HTTP server!"); // Init App @@ -222,6 +225,11 @@ async fn main() -> std::io::Result<()> { .wrap(cors.finish()) .wrap(Logger::default()) .wrap(Logger::new("%a %{User-Agent}i")) + .wrap( + RateLimiter::new(MemoryStoreActor::from(store.clone()).start()) + .with_interval(std::time::Duration::from_secs(60)) + .with_max_requests(100), + ) .data(pool.clone()) .data(file_host.clone()) .data(indexing_queue.clone()) diff --git a/src/routes/mod.rs b/src/routes/mod.rs index 1dc07eea7..4f992cfd5 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -32,10 +32,10 @@ pub fn mods_config(cfg: &mut web::ServiceConfig) { pub fn versions_config(cfg: &mut web::ServiceConfig) { cfg.service(versions::versions_get); + cfg.service(version_creation::version_create); cfg.service( web::scope("version") .service(versions::version_get) - .service(version_creation::version_create) .service(versions::version_delete) .service(version_creation::upload_file_to_version), ); diff --git a/src/routes/version_creation.rs b/src/routes/version_creation.rs index 62f804284..fdf7d9d93 100644 --- a/src/routes/version_creation.rs +++ b/src/routes/version_creation.rs @@ -70,7 +70,7 @@ pub fn check_version(version: &InitialVersionData) -> Result<(), CreateError> { Ok(()) } -// under `/api/v1/mod/{mod_id}` +// under `/api/v1/version` #[post("version")] pub async fn version_create( req: HttpRequest, @@ -107,7 +107,6 @@ pub async fn version_create( result } -/// TODO: Update mod timestamp when new version is created async fn version_create_inner( req: HttpRequest, mut payload: Multipart, @@ -339,7 +338,7 @@ async fn version_create_inner( // TODO: file deletion, listing, etc -// under /api/v1/mod/{mod_id}/version/{version_id} +// under /api/v1/version/{version_id} #[post("{version_id}/file")] pub async fn upload_file_to_version( req: HttpRequest,