diff --git a/Cargo.lock b/Cargo.lock index 0aea85f..31c030e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -420,25 +420,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crossbeam-channel" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] - [[package]] name = "crypto-common" version = "0.1.6" @@ -846,6 +827,15 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "nanoid" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ffa00dec017b5b1a8b7cf5e2c008bfda1aa7e0697ac1508b491fdf2622fb4d8" +dependencies = [ + "rand", +] + [[package]] name = "num_cpus" version = "1.16.0" @@ -948,6 +938,28 @@ 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_pool" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c211b97022a76440bd16521bba1abf82398218ade33d96813c5776bf8baf9722" +dependencies = [ + "nanoid", + "r2d2", + "rusqlite", +] + [[package]] name = "rand" version = "0.8.5" @@ -1064,6 +1076,15 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +[[package]] +name = "scheduled-thread-pool" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" +dependencies = [ + "parking_lot", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -1265,17 +1286,6 @@ dependencies = [ "syn 2.0.27", ] -[[package]] -name = "tokio-rusqlite" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aa66395f5ff117faee90c9458232c936405f9227ad902038000b74b3bc1feac" -dependencies = [ - "crossbeam-channel", - "rusqlite", - "tokio", -] - [[package]] name = "tokio-util" version = "0.7.8" @@ -1298,12 +1308,13 @@ dependencies = [ "actix-web", "anyhow", "env_logger", + "r2d2", + "r2d2_sqlite_pool", "rusqlite", "serde", "serde_derive", "serde_json", "tokio", - "tokio-rusqlite", "uuid", ] diff --git a/Cargo.toml b/Cargo.toml index 48ea3c0..bd0e449 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,9 +15,10 @@ serde_derive = "1.0.163" anyhow = "1.0.71" -tokio-rusqlite = "0.4.0" tokio = { version = "1.28.1", features = ["full"] } uuid = { version = "1.4.1", features = ["v4", "fast-rng"] } +r2d2_sqlite_pool = "0.1.1" +r2d2 = "0.8.10" [dependencies.rusqlite] version = "0.29.0" features = ["bundled"] diff --git a/src/main.rs b/src/main.rs index 6015f89..336ebb3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,22 +13,29 @@ use actix_web::{ HttpServer, }; use anyhow::{anyhow, Result}; +use r2d2::{Pool, PooledConnection}; +use r2d2_sqlite_pool::SqliteConnectionManager; use rusqlite::params; -use std::{cmp, env, io, ops::Deref, path::Path}; +use std::{cmp, env, io, ops::Deref}; use tokio::sync::Mutex; -use tokio_rusqlite::Connection; use uuid::Uuid; const DEFAULT_SIZE: usize = 25; +type Conn = PooledConnection; + struct MyAppData { etag: String, + pool: Pool, } #[actix_web::main] async fn main() -> io::Result<()> { + let manager = SqliteConnectionManager::file(torrents_db_file()); + let pool = r2d2::Pool::new(manager).unwrap(); let my_app_data = Data::new(Mutex::new(MyAppData { etag: Uuid::new_v4().to_string(), + pool, })); println!("Access me at {}", endpoint()); std::env::set_var("RUST_LOG", "actix_web=debug"); @@ -68,11 +75,8 @@ async fn search( ) -> Result { let my_app_data = data.lock().await; let etag = my_app_data.etag.clone(); - let conn = Connection::open(Path::new(&torrents_db_file())) - .await - .map_err(actix_web::error::ErrorBadRequest)?; + let conn = my_app_data.pool.get().unwrap(); let res = search_query(query, conn) - .await .map(|body| { HttpResponse::Ok() .append_header(("Access-Control-Allow-Origin", "*")) @@ -84,7 +88,7 @@ async fn search( Ok(res) } -async fn search_query(query: web::Query, conn: Connection) -> Result> { +fn search_query(query: web::Query, conn: Conn) -> Result> { let q = query.q.trim(); if q.is_empty() || q.len() < 3 || q == "2020" { return Err(anyhow!("{{\"error\": \"{}\"}}", "Empty query".to_string())); @@ -97,7 +101,7 @@ async fn search_query(query: web::Query, conn: Connection) -> Resul println!("query = {q}, type = {type_}, page = {page}, size = {size}"); - torrent_search(conn, q, size, offset).await + torrent_search(conn, q, size, offset) } #[derive(Debug, Serialize, Deserialize)] @@ -112,39 +116,27 @@ struct Torrent { scraped_date: u32, } -async fn torrent_search( - conn: Connection, - query: &str, - size: usize, - offset: usize, -) -> Result> { +fn torrent_search(conn: Conn, query: &str, size: usize, offset: usize) -> Result> { let q = query.to_owned(); - let res = conn - .call(move |conn| { - let stmt_str = "select * from torrent where name like '%' || ?1 || '%' 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) + let stmt_str = "select * from torrent where name like '%' || ?1 || '%' 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(torrents) }