torrents.csv/server/service/src/main.rs

179 lines
4.2 KiB
Rust
Raw Normal View History

2018-10-11 21:59:30 +00:00
extern crate actix_web;
extern crate serde;
extern crate serde_json;
2018-10-11 21:59:30 +00:00
#[macro_use]
extern crate serde_derive;
extern crate rusqlite;
2018-10-22 18:55:47 +00:00
extern crate time;
2018-10-11 21:59:30 +00:00
use actix_web::{fs, fs::NamedFile, http, server, App, HttpRequest, HttpResponse, Query};
use std::env;
use std::ops::Deref;
2018-10-11 21:59:30 +00:00
use rusqlite::{Connection, NO_PARAMS};
fn main() {
2018-10-22 18:55:47 +00:00
server::new(|| {
App::new()
.route("/service/search", http::Method::GET, search)
.resource("/", |r| r.f(index))
2018-10-22 18:55:47 +00:00
.handler(
"/static",
fs::StaticFiles::new(front_end_dir())
2018-10-22 18:55:47 +00:00
.unwrap()
// .index_file("index.html"),
2018-10-22 18:55:47 +00:00
)
.finish()
2018-12-01 00:14:02 +00:00
}).bind("0.0.0.0:8080")
2018-10-22 18:55:47 +00:00
.unwrap()
.run();
2018-10-11 21:59:30 +00:00
}
fn index(_req: &HttpRequest) -> Result<NamedFile, actix_web::error::Error> {
Ok(NamedFile::open(front_end_dir() + "/index.html")?)
}
fn front_end_dir() -> String {
env::var("TORRENTS_CSV_FRONT_END_DIR").unwrap_or("../ui/dist".to_string())
}
fn torrents_db_file() -> String {
env::var("TORRENTS_CSV_DB_FILE").unwrap_or("../../torrents.db".to_string())
}
2018-10-11 21:59:30 +00:00
#[derive(Deserialize)]
struct SearchQuery {
2018-10-22 18:55:47 +00:00
q: String,
page: Option<usize>,
size: Option<usize>,
type_: Option<String>
2018-10-11 21:59:30 +00:00
}
fn search(query: Query<SearchQuery>) -> HttpResponse {
2018-10-22 18:55:47 +00:00
HttpResponse::Ok()
.header("Access-Control-Allow-Origin", "*")
.content_type("application/json")
.body(search_query(query))
2018-10-11 21:59:30 +00:00
}
fn search_query(query: Query<SearchQuery>) -> String {
2018-10-22 18:55:47 +00:00
let page = query.page.unwrap_or(1);
let size = query.size.unwrap_or(10);
let type_ = query.type_.as_ref().map_or("torrent", String::deref);
let offset = size * (page - 1);
2018-10-22 18:55:47 +00:00
println!("query = {}, type = {}, page = {}, size = {}", query.q, type_, page, size);
2018-10-22 18:55:47 +00:00
if type_ == "file" {
let results = torrent_file_search(&query.q, size, offset);
serde_json::to_string(&results).unwrap()
} else {
let results = torrent_search(&query.q, size, offset);
serde_json::to_string(&results).unwrap()
}
2018-10-22 18:55:47 +00:00
}
#[derive(Debug, Serialize, Deserialize)]
struct Torrent {
infohash: String,
name: String,
size_bytes: isize,
created_unix: u32,
seeders: u32,
leechers: u32,
completed: Option<u32>,
scraped_date: u32,
}
2018-10-22 18:55:47 +00:00
fn torrent_search(query: &str, size: usize, offset: usize) -> Vec<Torrent> {
let stmt_str = format!(
"select * from torrents where name like '%{}%' limit {} offset {}",
query.replace(" ", "%").replace("\'","''"),
size,
offset
);
let conn = Connection::open(torrents_db_file()).unwrap();
let mut stmt = conn.prepare(&stmt_str).unwrap();
let torrent_iter = stmt
.query_map(NO_PARAMS, |row| 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),
})
.unwrap();
let mut torrents = Vec::new();
for torrent in torrent_iter {
torrents.push(torrent.unwrap());
}
torrents
2018-10-22 18:55:47 +00:00
}
#[derive(Debug, Serialize, Deserialize)]
struct File {
infohash: String,
index_: u32,
path: String,
size_bytes: isize,
created_unix: u32,
seeders: u32,
leechers: u32,
completed: Option<u32>,
scraped_date: u32,
}
fn torrent_file_search(query: &str, size: usize, offset: usize) -> Vec<File> {
let stmt_str = format!(
"select * from files where path like '%{}%' limit {} offset {}",
query.replace(" ", "%").replace("\'","''"),
size,
offset
);
let conn = Connection::open(torrents_db_file()).unwrap();
let mut stmt = conn.prepare(&stmt_str).unwrap();
let file_iter = stmt
.query_map(NO_PARAMS, |row| File {
infohash: row.get(0),
index_: row.get(1),
path: row.get(2),
size_bytes: row.get(3),
created_unix: row.get(4),
seeders: row.get(5),
leechers: row.get(6),
completed: row.get(7),
scraped_date: row.get(8),
})
.unwrap();
let mut files = Vec::new();
for file in file_iter {
files.push(file.unwrap());
}
files
}
2018-10-22 18:55:47 +00:00
#[cfg(test)]
mod tests {
use time::PreciseTime;
#[test]
fn test() {
let start = PreciseTime::now();
let results =
super::torrent_search("sherlock", 10, 0);
2018-10-22 18:55:47 +00:00
assert!(results.len() > 2);
let end = PreciseTime::now();
println!("Query took {} seconds.", start.to(end));
}
2018-10-11 21:59:30 +00:00
}