Spaces:
Running
Running
ddotthomas
commited on
Commit
·
7d762b3
1
Parent(s):
dde117e
refactor: moved settings parsing out of results
Browse files- src/models/server_models.rs +19 -4
- src/server/routes/search.rs +50 -102
src/models/server_models.rs
CHANGED
@@ -2,6 +2,8 @@
|
|
2 |
//! engine website.
|
3 |
use serde::Deserialize;
|
4 |
|
|
|
|
|
5 |
/// A named struct which deserializes all the user provided search parameters and stores them.
|
6 |
#[derive(Deserialize)]
|
7 |
pub struct SearchParams {
|
@@ -19,13 +21,26 @@ pub struct SearchParams {
|
|
19 |
/// A named struct which is used to deserialize the cookies fetched from the client side.
|
20 |
#[allow(dead_code)]
|
21 |
#[derive(Deserialize)]
|
22 |
-
pub struct Cookie
|
23 |
/// It stores the theme name used in the website.
|
24 |
-
pub theme:
|
25 |
/// It stores the colorscheme name used for the website theme.
|
26 |
-
pub colorscheme:
|
27 |
/// It stores the user selected upstream search engines selected from the UI.
|
28 |
-
pub engines: Vec
|
29 |
/// It stores the user selected safe search level from the UI.
|
30 |
pub safe_search_level: u8,
|
31 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
//! engine website.
|
3 |
use serde::Deserialize;
|
4 |
|
5 |
+
use super::parser_models::Style;
|
6 |
+
|
7 |
/// A named struct which deserializes all the user provided search parameters and stores them.
|
8 |
#[derive(Deserialize)]
|
9 |
pub struct SearchParams {
|
|
|
21 |
/// A named struct which is used to deserialize the cookies fetched from the client side.
|
22 |
#[allow(dead_code)]
|
23 |
#[derive(Deserialize)]
|
24 |
+
pub struct Cookie {
|
25 |
/// It stores the theme name used in the website.
|
26 |
+
pub theme: String,
|
27 |
/// It stores the colorscheme name used for the website theme.
|
28 |
+
pub colorscheme: String,
|
29 |
/// It stores the user selected upstream search engines selected from the UI.
|
30 |
+
pub engines: Vec<String>,
|
31 |
/// It stores the user selected safe search level from the UI.
|
32 |
pub safe_search_level: u8,
|
33 |
}
|
34 |
+
|
35 |
+
impl Cookie {
|
36 |
+
/// server_models::Cookie contructor function
|
37 |
+
pub fn build(style: &Style, mut engines: Vec<String>, safe_search_level: u8) -> Self {
|
38 |
+
engines.sort();
|
39 |
+
Self {
|
40 |
+
theme: style.theme.clone(),
|
41 |
+
colorscheme: style.colorscheme.clone(),
|
42 |
+
engines,
|
43 |
+
safe_search_level,
|
44 |
+
}
|
45 |
+
}
|
46 |
+
}
|
src/server/routes/search.rs
CHANGED
@@ -7,7 +7,7 @@ use crate::{
|
|
7 |
models::{
|
8 |
aggregation_models::SearchResults,
|
9 |
engine_models::EngineHandler,
|
10 |
-
server_models::{
|
11 |
},
|
12 |
results::aggregator::aggregate,
|
13 |
};
|
@@ -48,17 +48,37 @@ pub async fn search(
|
|
48 |
.finish());
|
49 |
}
|
50 |
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
&
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
|
|
|
|
|
|
59 |
)
|
60 |
};
|
61 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
62 |
// .max(1) makes sure that the page >= 0.
|
63 |
let page = params.page.unwrap_or(1).max(1) - 1;
|
64 |
|
@@ -105,50 +125,21 @@ async fn results(
|
|
105 |
cache: &web::Data<SharedCache>,
|
106 |
query: &str,
|
107 |
page: u32,
|
108 |
-
|
109 |
-
safe_search: &Option<u8>,
|
110 |
) -> Result<SearchResults, Box<dyn std::error::Error>> {
|
111 |
// eagerly parse cookie value to evaluate safe search level
|
112 |
-
let
|
113 |
-
|
114 |
-
let
|
115 |
-
|
116 |
-
.
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
);
|
123 |
-
|
124 |
-
let mut cache_key = format!(
|
125 |
-
"http://{}:{}/search?q={}&page={}&safesearch={}",
|
126 |
-
config.binding_ip, config.port, query, page, safe_search_level
|
127 |
);
|
128 |
|
129 |
-
let mut cookie_engines: Vec<String> = vec![];
|
130 |
-
let mut config_engines: Vec<String> = config
|
131 |
-
.upstream_search_engines
|
132 |
-
.iter()
|
133 |
-
.filter_map(|(engine, enabled)| enabled.then_some(engine.clone()))
|
134 |
-
.collect();
|
135 |
-
config_engines.sort();
|
136 |
-
|
137 |
-
// Modify the cache key adding each enabled search engine to the string
|
138 |
-
if let Some(cookie_value) = &cookie_value {
|
139 |
-
cookie_engines = cookie_value
|
140 |
-
.engines
|
141 |
-
.iter()
|
142 |
-
.map(|s| String::from(*s))
|
143 |
-
.collect::<Vec<String>>();
|
144 |
-
|
145 |
-
// We sort the list of engine so the cache keys will match between users. The cookie's list of engines is unordered.
|
146 |
-
cookie_engines.sort();
|
147 |
-
cache_key = format!("{cache_key}&engines={}", cookie_engines.join(","));
|
148 |
-
} else {
|
149 |
-
cache_key = format!("{cache_key}&engines={}", config_engines.join(","));
|
150 |
-
}
|
151 |
-
|
152 |
// fetch the cached results json.
|
153 |
let cached_results = cache.cached_results(&cache_key).await;
|
154 |
// check if fetched cache results was indeed fetched or it was an error and if so
|
@@ -174,43 +165,16 @@ async fn results(
|
|
174 |
// default selected upstream search engines from the config file otherwise
|
175 |
// parse the non-empty cookie and grab the user selected engines from the
|
176 |
// UI and use that.
|
177 |
-
let mut results: SearchResults = match
|
178 |
-
|
179 |
-
Some(_) => {
|
180 |
-
// Use the cookie_engines Strings from before to create the EngineHandlers
|
181 |
-
let engines: Vec<EngineHandler> = cookie_engines
|
182 |
-
.iter()
|
183 |
-
.filter_map(|name| EngineHandler::new(name).ok())
|
184 |
-
.collect();
|
185 |
-
|
186 |
-
match engines.is_empty() {
|
187 |
-
false => {
|
188 |
-
aggregate(
|
189 |
-
query,
|
190 |
-
page,
|
191 |
-
config.aggregator.random_delay,
|
192 |
-
config.debug,
|
193 |
-
&engines,
|
194 |
-
config.request_timeout,
|
195 |
-
safe_search_level,
|
196 |
-
)
|
197 |
-
.await?
|
198 |
-
}
|
199 |
-
true => {
|
200 |
-
let mut search_results = SearchResults::default();
|
201 |
-
search_results.set_no_engines_selected();
|
202 |
-
search_results
|
203 |
-
}
|
204 |
-
}
|
205 |
-
}
|
206 |
-
// Otherwise, use the config_engines to create the EngineHandlers
|
207 |
-
None => {
|
208 |
aggregate(
|
209 |
query,
|
210 |
page,
|
211 |
config.aggregator.random_delay,
|
212 |
config.debug,
|
213 |
-
&
|
|
|
|
|
214 |
.into_iter()
|
215 |
.filter_map(|engine| EngineHandler::new(&engine).ok())
|
216 |
.collect::<Vec<EngineHandler>>(),
|
@@ -219,6 +183,11 @@ async fn results(
|
|
219 |
)
|
220 |
.await?
|
221 |
}
|
|
|
|
|
|
|
|
|
|
|
222 |
};
|
223 |
if results.engine_errors_info().is_empty()
|
224 |
&& results.results().is_empty()
|
@@ -259,24 +228,3 @@ fn is_match_from_filter_list(
|
|
259 |
|
260 |
Ok(false)
|
261 |
}
|
262 |
-
|
263 |
-
/// A helper function which returns the safe search level based on the url params
|
264 |
-
/// and cookie value.
|
265 |
-
///
|
266 |
-
/// # Argurments
|
267 |
-
///
|
268 |
-
/// * `safe_search` - Safe search level from the url.
|
269 |
-
/// * `cookie` - User's cookie
|
270 |
-
/// * `default` - Safe search level to fall back to
|
271 |
-
fn get_safesearch_level(safe_search: &Option<u8>, cookie: &Option<u8>, default: u8) -> u8 {
|
272 |
-
match safe_search {
|
273 |
-
Some(ss) => {
|
274 |
-
if *ss >= 3 {
|
275 |
-
default
|
276 |
-
} else {
|
277 |
-
*ss
|
278 |
-
}
|
279 |
-
}
|
280 |
-
None => cookie.unwrap_or(default),
|
281 |
-
}
|
282 |
-
}
|
|
|
7 |
models::{
|
8 |
aggregation_models::SearchResults,
|
9 |
engine_models::EngineHandler,
|
10 |
+
server_models::{self, SearchParams},
|
11 |
},
|
12 |
results::aggregator::aggregate,
|
13 |
};
|
|
|
48 |
.finish());
|
49 |
}
|
50 |
|
51 |
+
// Closure to build a server_models::Cookie capturing local references
|
52 |
+
let build_cookie = || {
|
53 |
+
server_models::Cookie::build(
|
54 |
+
&config.style,
|
55 |
+
config
|
56 |
+
.upstream_search_engines
|
57 |
+
.clone()
|
58 |
+
.into_iter()
|
59 |
+
.filter_map(|engine_map| engine_map.1.then_some(engine_map.0))
|
60 |
+
.collect(),
|
61 |
+
config.safe_search,
|
62 |
)
|
63 |
};
|
64 |
|
65 |
+
// Get search settings using the user's cookie or from the server's config
|
66 |
+
let search_settings: server_models::Cookie = match req.cookie("appCookie") {
|
67 |
+
Some(cookie_value) => {
|
68 |
+
if let Ok(cookie) = serde_json::from_str(cookie_value.value()) {
|
69 |
+
cookie
|
70 |
+
// If there's an issue parsing the cookie's value, default to the config
|
71 |
+
} else {
|
72 |
+
build_cookie()
|
73 |
+
}
|
74 |
+
}
|
75 |
+
// If there's no cookie saved, use the server's config
|
76 |
+
None => build_cookie(),
|
77 |
+
};
|
78 |
+
|
79 |
+
// Closure wrapping the results function capturing local references
|
80 |
+
let get_results = |page| results(&config, &cache, query, page, &search_settings);
|
81 |
+
|
82 |
// .max(1) makes sure that the page >= 0.
|
83 |
let page = params.page.unwrap_or(1).max(1) - 1;
|
84 |
|
|
|
125 |
cache: &web::Data<SharedCache>,
|
126 |
query: &str,
|
127 |
page: u32,
|
128 |
+
user_settings: &server_models::Cookie,
|
|
|
129 |
) -> Result<SearchResults, Box<dyn std::error::Error>> {
|
130 |
// eagerly parse cookie value to evaluate safe search level
|
131 |
+
let safe_search_level = user_settings.safe_search_level;
|
132 |
+
|
133 |
+
let cache_key = format!(
|
134 |
+
"http://{}:{}/search?q={}&page={}&safesearch={}&engines={}",
|
135 |
+
config.binding_ip,
|
136 |
+
config.port,
|
137 |
+
query,
|
138 |
+
page,
|
139 |
+
safe_search_level,
|
140 |
+
user_settings.engines.join(",")
|
|
|
|
|
|
|
|
|
|
|
141 |
);
|
142 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
143 |
// fetch the cached results json.
|
144 |
let cached_results = cache.cached_results(&cache_key).await;
|
145 |
// check if fetched cache results was indeed fetched or it was an error and if so
|
|
|
165 |
// default selected upstream search engines from the config file otherwise
|
166 |
// parse the non-empty cookie and grab the user selected engines from the
|
167 |
// UI and use that.
|
168 |
+
let mut results: SearchResults = match user_settings.engines.is_empty() {
|
169 |
+
false => {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
170 |
aggregate(
|
171 |
query,
|
172 |
page,
|
173 |
config.aggregator.random_delay,
|
174 |
config.debug,
|
175 |
+
&user_settings
|
176 |
+
.engines
|
177 |
+
.clone()
|
178 |
.into_iter()
|
179 |
.filter_map(|engine| EngineHandler::new(&engine).ok())
|
180 |
.collect::<Vec<EngineHandler>>(),
|
|
|
183 |
)
|
184 |
.await?
|
185 |
}
|
186 |
+
true => {
|
187 |
+
let mut search_results = SearchResults::default();
|
188 |
+
search_results.set_no_engines_selected();
|
189 |
+
search_results
|
190 |
+
}
|
191 |
};
|
192 |
if results.engine_errors_info().is_empty()
|
193 |
&& results.results().is_empty()
|
|
|
228 |
|
229 |
Ok(false)
|
230 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|