diff --git a/src/models/server_models.rs b/src/models/server_models.rs index 4772b98..a13a7dd 100644 --- a/src/models/server_models.rs +++ b/src/models/server_models.rs @@ -2,6 +2,8 @@ //! engine website. use serde::Deserialize; +use super::parser_models::Style; + /// A named struct which deserializes all the user provided search parameters and stores them. #[derive(Deserialize)] pub struct SearchParams { @@ -19,13 +21,26 @@ pub struct SearchParams { /// A named struct which is used to deserialize the cookies fetched from the client side. #[allow(dead_code)] #[derive(Deserialize)] -pub struct Cookie<'a> { +pub struct Cookie { /// It stores the theme name used in the website. - pub theme: &'a str, + pub theme: String, /// It stores the colorscheme name used for the website theme. - pub colorscheme: &'a str, + pub colorscheme: String, /// It stores the user selected upstream search engines selected from the UI. - pub engines: Vec<&'a str>, + pub engines: Vec, /// It stores the user selected safe search level from the UI. pub safe_search_level: u8, } + +impl Cookie { + /// server_models::Cookie contructor function + pub fn build(style: &Style, mut engines: Vec, safe_search_level: u8) -> Self { + engines.sort(); + Self { + theme: style.theme.clone(), + colorscheme: style.colorscheme.clone(), + engines, + safe_search_level, + } + } +} diff --git a/src/server/routes/search.rs b/src/server/routes/search.rs index 3f880f5..edf8e1b 100644 --- a/src/server/routes/search.rs +++ b/src/server/routes/search.rs @@ -7,7 +7,7 @@ use crate::{ models::{ aggregation_models::SearchResults, engine_models::EngineHandler, - server_models::{Cookie, SearchParams}, + server_models::{self, SearchParams}, }, results::aggregator::aggregate, }; @@ -48,17 +48,37 @@ pub async fn search( .finish()); } - let get_results = |page| { - results( - &config, - &cache, - query, - page, - req.clone(), - ¶ms.safesearch, + // Closure to build a server_models::Cookie capturing local references + let build_cookie = || { + server_models::Cookie::build( + &config.style, + config + .upstream_search_engines + .clone() + .into_iter() + .filter_map(|engine_map| engine_map.1.then_some(engine_map.0)) + .collect(), + config.safe_search, ) }; + // Get search settings using the user's cookie or from the server's config + let search_settings: server_models::Cookie = match req.cookie("appCookie") { + Some(cookie_value) => { + if let Ok(cookie) = serde_json::from_str(cookie_value.value()) { + cookie + // If there's an issue parsing the cookie's value, default to the config + } else { + build_cookie() + } + } + // If there's no cookie saved, use the server's config + None => build_cookie(), + }; + + // Closure wrapping the results function capturing local references + let get_results = |page| results(&config, &cache, query, page, &search_settings); + // .max(1) makes sure that the page >= 0. let page = params.page.unwrap_or(1).max(1) - 1; @@ -105,50 +125,21 @@ async fn results( cache: &web::Data, query: &str, page: u32, - req: HttpRequest, - safe_search: &Option, + user_settings: &server_models::Cookie, ) -> Result> { // eagerly parse cookie value to evaluate safe search level - let cookie_value = req.cookie("appCookie"); + let safe_search_level = user_settings.safe_search_level; - let cookie_value: Option> = cookie_value - .as_ref() - .and_then(|cv| serde_json::from_str(cv.name_value().1).ok()); - - let safe_search_level = get_safesearch_level( - safe_search, - &cookie_value.as_ref().map(|cv| cv.safe_search_level), - config.safe_search, + let cache_key = format!( + "http://{}:{}/search?q={}&page={}&safesearch={}&engines={}", + config.binding_ip, + config.port, + query, + page, + safe_search_level, + user_settings.engines.join(",") ); - let mut cache_key = format!( - "http://{}:{}/search?q={}&page={}&safesearch={}", - config.binding_ip, config.port, query, page, safe_search_level - ); - - let mut cookie_engines: Vec = vec![]; - let mut config_engines: Vec = config - .upstream_search_engines - .iter() - .filter_map(|(engine, enabled)| enabled.then_some(engine.clone())) - .collect(); - config_engines.sort(); - - // Modify the cache key adding each enabled search engine to the string - if let Some(cookie_value) = &cookie_value { - cookie_engines = cookie_value - .engines - .iter() - .map(|s| String::from(*s)) - .collect::>(); - - // We sort the list of engine so the cache keys will match between users. The cookie's list of engines is unordered. - cookie_engines.sort(); - cache_key = format!("{cache_key}&engines={}", cookie_engines.join(",")); - } else { - cache_key = format!("{cache_key}&engines={}", config_engines.join(",")); - } - // fetch the cached results json. let cached_results = cache.cached_results(&cache_key).await; // check if fetched cache results was indeed fetched or it was an error and if so @@ -174,43 +165,16 @@ async fn results( // default selected upstream search engines from the config file otherwise // parse the non-empty cookie and grab the user selected engines from the // UI and use that. - let mut results: SearchResults = match cookie_value { - // If the cookie was used before - Some(_) => { - // Use the cookie_engines Strings from before to create the EngineHandlers - let engines: Vec = cookie_engines - .iter() - .filter_map(|name| EngineHandler::new(name).ok()) - .collect(); - - match engines.is_empty() { - false => { - aggregate( - query, - page, - config.aggregator.random_delay, - config.debug, - &engines, - config.request_timeout, - safe_search_level, - ) - .await? - } - true => { - let mut search_results = SearchResults::default(); - search_results.set_no_engines_selected(); - search_results - } - } - } - // Otherwise, use the config_engines to create the EngineHandlers - None => { + let mut results: SearchResults = match user_settings.engines.is_empty() { + false => { aggregate( query, page, config.aggregator.random_delay, config.debug, - &config_engines + &user_settings + .engines + .clone() .into_iter() .filter_map(|engine| EngineHandler::new(&engine).ok()) .collect::>(), @@ -219,6 +183,11 @@ async fn results( ) .await? } + true => { + let mut search_results = SearchResults::default(); + search_results.set_no_engines_selected(); + search_results + } }; if results.engine_errors_info().is_empty() && results.results().is_empty() @@ -259,24 +228,3 @@ fn is_match_from_filter_list( Ok(false) } - -/// A helper function which returns the safe search level based on the url params -/// and cookie value. -/// -/// # Argurments -/// -/// * `safe_search` - Safe search level from the url. -/// * `cookie` - User's cookie -/// * `default` - Safe search level to fall back to -fn get_safesearch_level(safe_search: &Option, cookie: &Option, default: u8) -> u8 { - match safe_search { - Some(ss) => { - if *ss >= 3 { - default - } else { - *ss - } - } - None => cookie.unwrap_or(default), - } -}