From b501e0503d5e138eb81de051d159dae20b8637fd Mon Sep 17 00:00:00 2001 From: Heretic Date: Mon, 30 Jan 2023 18:10:19 -0500 Subject: [PATCH] Adding rusqlite async. Fixes #2 --- Cargo.lock | 190 +++++++++++++++++++++++++++------------------------- Cargo.toml | 6 +- src/main.rs | 140 +++++++++++++++++--------------------- 3 files changed, 165 insertions(+), 171 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 375da69..c2d3f6a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,9 +44,9 @@ dependencies = [ [[package]] name = "actix-http" -version = "3.2.2" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c83abf9903e1f0ad9973cc4f7b9767fd5a03a583f51a5b7a339e07987cd2724" +checksum = "0070905b2c4a98d184c4e81025253cb192aa8a73827553f38e9410801ceb35bb" dependencies = [ "actix-codec", "actix-rt", @@ -75,6 +75,8 @@ dependencies = [ "rand", "sha1", "smallvec", + "tokio", + "tokio-util", "tracing", "zstd", ] @@ -104,9 +106,9 @@ dependencies = [ [[package]] name = "actix-rt" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ea16c295198e958ef31930a6ef37d0fb64e9ca3b6116e6b93a8bdae96ee1000" +checksum = "15265b6b8e2347670eb363c47fc8c75208b4a4994b27192f345fcbe707804f3e" dependencies = [ "futures-core", "tokio", @@ -114,9 +116,9 @@ dependencies = [ [[package]] name = "actix-server" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0da34f8e659ea1b077bb4637948b815cd3768ad5a188fdcd74ff4d84240cd824" +checksum = "3e8613a75dd50cc45f473cee3c34d59ed677c0f7b44480ce3b8247d7dc519327" dependencies = [ "actix-rt", "actix-service", @@ -153,9 +155,9 @@ dependencies = [ [[package]] name = "actix-web" -version = "4.2.1" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d48f7b6534e06c7bfc72ee91db7917d4af6afe23e7d223b51e68fffbb21e96b9" +checksum = "464e0fddc668ede5f26ec1f9557a8d44eda948732f40c6b0ad79126930eb775f" dependencies = [ "actix-codec", "actix-http", @@ -265,9 +267,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "base64" -version = "0.13.1" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" [[package]] name = "bitflags" @@ -297,9 +299,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "2.3.2" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ad2d4653bf5ca36ae797b1f4bb4dbddb60ce49ca4aed8a2ce4829f60425b80" +checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -320,17 +322,11 @@ dependencies = [ "bytes", ] -[[package]] -name = "cargo-husky" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b02b629252fe8ef6460461409564e2c21d0c8e77e0944f3d189ff06c4e932ad" - [[package]] name = "cc" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" dependencies = [ "jobserver", ] @@ -376,6 +372,25 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" +dependencies = [ + "cfg-if", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -491,27 +506,27 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" +checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" [[package]] name = "futures-sink" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" +checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" [[package]] name = "futures-task" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" +checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" [[package]] name = "futures-util" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" dependencies = [ "futures-core", "futures-task", @@ -643,9 +658,9 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c" +checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e" dependencies = [ "libc", "windows-sys", @@ -864,9 +879,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.49" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" +checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" dependencies = [ "unicode-ident", ] @@ -880,27 +895,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "r2d2" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" -dependencies = [ - "log", - "parking_lot", - "scheduled-thread-pool", -] - -[[package]] -name = "r2d2_sqlite" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4f5d0337e99cd5cacd91ffc326c6cc9d8078def459df560c4f9bf9ba4a51034" -dependencies = [ - "r2d2", - "rusqlite", -] - [[package]] name = "rand" version = "0.8.5" @@ -982,9 +976,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.36.6" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4feacf7db682c6c329c4ede12649cd36ecab0f3be5b7d74e6a20304725db4549" +checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03" dependencies = [ "bitflags", "errno", @@ -1000,15 +994,6 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" -[[package]] -name = "scheduled-thread-pool" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "977a7519bff143a44f842fd07e80ad1329295bd71686457f18e496736f4bf9bf" -dependencies = [ - "parking_lot", -] - [[package]] name = "scopeguard" version = "1.1.0" @@ -1119,9 +1104,9 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.1.3" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" dependencies = [ "winapi-util", ] @@ -1170,22 +1155,46 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.24.1" +version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d9f76183f91ecfb55e1d7d5602bd1d979e38a3a522fe900241cf195624d67ae" +checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af" dependencies = [ "autocfg", "bytes", "libc", "memchr", "mio", + "num_cpus", "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", + "tokio-macros", "windows-sys", ] +[[package]] +name = "tokio-macros" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-rusqlite" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31dfc8c4778d61428ef6b5d0eba26a5953314f307f10fb278f9839d0a1baae5" +dependencies = [ + "crossbeam-channel", + "rusqlite", + "tokio", +] + [[package]] name = "tokio-util" version = "0.7.4" @@ -1207,14 +1216,13 @@ dependencies = [ "actix-files", "actix-web", "anyhow", - "cargo-husky", "env_logger", - "r2d2", - "r2d2_sqlite", "rusqlite", "serde", "serde_derive", "serde_json", + "tokio", + "tokio-rusqlite", ] [[package]] @@ -1255,9 +1263,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" +checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58" [[package]] name = "unicode-ident" @@ -1351,60 +1359,60 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" +checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" [[package]] name = "windows_aarch64_msvc" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" +checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" [[package]] name = "windows_i686_gnu" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" +checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" [[package]] name = "windows_i686_msvc" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" +checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" [[package]] name = "windows_x86_64_gnu" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" +checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" +checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" [[package]] name = "windows_x86_64_msvc" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" +checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" [[package]] name = "zstd" -version = "0.11.2+zstd.1.5.2" +version = "0.12.2+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +checksum = "e9262a83dc741c0b0ffec209881b45dbc232c21b02a2b9cb1adb93266e41303d" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "5.0.2+zstd.1.5.2" +version = "6.0.2+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +checksum = "a6cf39f730b440bab43da8fb5faf5f254574462f73f260f85f7987f32154ff17" dependencies = [ "libc", "zstd-sys", diff --git a/Cargo.toml b/Cargo.toml index e9a5579..00de3aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Heretic "] edition = "2018" [dependencies] -actix-web = "4.2.1" +actix-web = "4.3.0" actix-files = "0.6.2" env_logger = "0.10.0" @@ -15,8 +15,8 @@ serde_derive = "1.0.152" anyhow = "1.0.68" -r2d2 = "0.8.10" -r2d2_sqlite = "0.21.0" +tokio-rusqlite = "0.3.0" +tokio = { version = "1.25.0", features = ["full"] } [dependencies.rusqlite] version = "0.28.0" diff --git a/src/main.rs b/src/main.rs index 7d616b2..42a0eae 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,17 +4,15 @@ extern crate serde; extern crate serde_json; #[macro_use] extern crate serde_derive; -extern crate r2d2; -extern crate r2d2_sqlite; extern crate rusqlite; use actix_files as fs; use actix_files::NamedFile; -use actix_web::{middleware, web, web::Data, App, HttpResponse, HttpServer}; -use anyhow::{anyhow, Error}; -use r2d2_sqlite::SqliteConnectionManager; +use actix_web::{middleware, web, App, HttpResponse, HttpServer}; +use anyhow::{anyhow, Result}; use rusqlite::params; -use std::{cmp, env, io, ops::Deref}; +use std::{cmp, env, io, ops::Deref, path::Path}; +use tokio_rusqlite::Connection; const DEFAULT_SIZE: usize = 25; @@ -24,12 +22,8 @@ async fn main() -> io::Result<()> { std::env::set_var("RUST_LOG", "actix_web=debug"); env_logger::init(); - let manager = SqliteConnectionManager::file(torrents_db_file()); - let pool = r2d2::Pool::builder().max_size(15).build(manager).unwrap(); - HttpServer::new(move || { App::new() - .app_data(Data::new(pool.clone())) .wrap(middleware::Logger::default()) .service(fs::Files::new("/static", front_end_dir())) .route("/", web::get().to(index)) @@ -65,30 +59,22 @@ struct SearchQuery { type_: Option, } -async fn search( - db: web::Data>, - query: web::Query, -) -> Result { - let res = web::block(move || { - let conn = db.get().unwrap(); - - // TODO can't get errors to propagate correctly - search_query(query, conn).unwrap() - }) - .await - .map(|body| { - HttpResponse::Ok() - .append_header(("Access-Control-Allow-Origin", "*")) - .json(body) - }) - .map_err(actix_web::error::ErrorBadRequest)?; +async fn search(query: web::Query) -> Result { + let conn = Connection::open(Path::new(&torrents_db_file())) + .await + .map_err(actix_web::error::ErrorBadRequest)?; + let res = search_query(query, conn) + .await + .map(|body| { + HttpResponse::Ok() + .append_header(("Access-Control-Allow-Origin", "*")) + .json(body) + }) + .map_err(actix_web::error::ErrorBadRequest)?; Ok(res) } -fn search_query( - query: web::Query, - conn: r2d2::PooledConnection, -) -> Result, Error> { +async fn search_query(query: web::Query, conn: Connection) -> Result> { let q = query.q.trim(); if q.is_empty() || q.len() < 3 || q == "2020" { return Err(anyhow!("{{\"error\": \"{}\"}}", "Empty query".to_string())); @@ -99,12 +85,9 @@ fn search_query( let type_ = query.type_.as_ref().map_or("torrent", String::deref); let offset = size * (page - 1); - println!( - "query = {}, type = {}, page = {}, size = {}", - q, type_, page, size - ); + println!("query = {q}, type = {type_}, page = {page}, size = {size}"); - torrent_search(conn, q, size, offset) + torrent_search(conn, q, size, offset).await } #[derive(Debug, Serialize, Deserialize)] @@ -119,53 +102,56 @@ struct Torrent { scraped_date: u32, } -fn torrent_search( - conn: r2d2::PooledConnection, +async fn torrent_search( + conn: Connection, query: &str, size: usize, offset: usize, -) -> Result, Error> { - let stmt_str = - "select * from torrent where name like '%' || ?1 || '%' order by seeders desc limit ?2, ?3"; - let mut stmt = conn.prepare(stmt_str)?; - let torrent_iter = stmt.query_map( - params![ - query.replace(' ', "%"), - offset.to_string(), - size.to_string(), - ], - |row| { - Ok(Torrent { - infohash: row.get(0)?, - name: row.get(1)?, - size_bytes: row.get(2)?, - created_unix: row.get(3)?, - seeders: row.get(4)?, - leechers: row.get(5)?, - completed: row.get(6)?, - scraped_date: row.get(7)?, - }) - }, - )?; - - let mut torrents = Vec::new(); - for torrent in torrent_iter { - torrents.push(torrent?); - } - Ok(torrents) +) -> Result> { + let q = query.to_owned(); + let res = conn + .call(move |conn| { + let stmt_str = + "select * from torrent where name like '%' || ?1 || '%' order by seeders desc limit ?2, ?3"; + + let mut stmt = conn.prepare(stmt_str)?; + let torrents = stmt + .query_map( + params![q.replace(' ', "%"), offset.to_string(), size.to_string(),], + |row| { + Ok(Torrent { + infohash: row.get(0)?, + name: row.get(1)?, + size_bytes: row.get(2)?, + created_unix: row.get(3)?, + seeders: row.get(4)?, + leechers: row.get(5)?, + completed: row.get(6)?, + scraped_date: row.get(7)?, + }) + }, + )? + .collect::, rusqlite::Error>>()?; + + Ok::<_, rusqlite::Error>(torrents) + }) + .await?; + + Ok(res) } #[cfg(test)] mod tests { - use r2d2_sqlite::SqliteConnectionManager; - - #[test] - fn test() { - let manager = SqliteConnectionManager::file(super::torrents_db_file()); - let pool = r2d2::Pool::builder().max_size(15).build(manager).unwrap(); - let conn = pool.get().unwrap(); - let results = super::torrent_search(conn, "sherlock", 10, 0); - assert!(results.unwrap().len() > 2); - // println!("Query took {:?} seconds.", end - start); + use crate::{torrent_search, torrents_db_file}; + use std::path::Path; + use tokio_rusqlite::Connection; + + #[tokio::test] + async fn test() { + let conn = Connection::open(Path::new(&torrents_db_file())) + .await + .unwrap(); + let results = torrent_search(conn, "sherlock", 10, 0).await.unwrap(); + assert!(results.len() > 2); } }