extern crate actix_web; extern crate serde; #[macro_use] extern crate serde_derive; extern crate grep; extern crate time; use actix_web::{fs, http, server, App, HttpResponse, Query}; use std::error::Error; use grep::regex::RegexMatcher; use grep::searcher::sinks::Lossy; use grep::searcher::{BinaryDetection, SearcherBuilder}; use std::fs::File; fn main() { server::new(|| { App::new() .route("/service/search", http::Method::GET, search) .handler( "/", fs::StaticFiles::new("../ui/dist/") .unwrap() .index_file("index.html"), ) .finish() }).bind("127.0.0.1:8080") .unwrap() .run(); } #[derive(Deserialize)] struct SearchQuery { q: String, page: Option, size: Option, } fn search(query: Query) -> HttpResponse { HttpResponse::Ok() .header("Access-Control-Allow-Origin", "*") .content_type("text/csv") .body(ripgrep(query)) } fn ripgrep(query: Query) -> String { let page = query.page.unwrap_or(1); let size = query.size.unwrap_or(10); let offset = size * (page - 1) + 1; let csv_file = File::open("../../torrents.csv"); println!( "query = {} , page = {}, size = {}, offset = {}", query.q, page, size, offset ); let results = search_file(csv_file.unwrap(), &query.q).unwrap(); results[offset - 1..offset + size].join("") } fn search_file(file: File, query: &str) -> Result, Box> { let pattern = query.replace(" ", ".*"); let matcher = RegexMatcher::new_line_matcher(&pattern)?; let mut matches: Vec = vec![]; let mut searcher = SearcherBuilder::new() .binary_detection(BinaryDetection::quit(b'\x00')) // .line_number(false) .build(); searcher.search_file( &matcher, &file, Lossy(|_lnum, line| { matches.push(line.to_string()); Ok(true) }), )?; Ok(matches) } #[cfg(test)] mod tests { use std::fs::File; use time::PreciseTime; #[test] fn test() { let start = PreciseTime::now(); let results = super::search_file(File::open("../../torrents.csv").unwrap(), "sherlock").unwrap(); assert!(results.len() > 2); let end = PreciseTime::now(); println!("Query took {} seconds.", start.to(end)); } }