Make search request
parent
ac4682e20a
commit
dc66951808
|
@ -385,6 +385,15 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono-humanize"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "799627e6b4d27827a814e837b9d8a504832086081806d45b1afa34dc982b023b"
|
||||||
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "config"
|
name = "config"
|
||||||
version = "0.13.3"
|
version = "0.13.3"
|
||||||
|
@ -753,9 +762,11 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum",
|
"axum",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"chrono-humanize",
|
||||||
"config",
|
"config",
|
||||||
"dirs",
|
"dirs",
|
||||||
"ramhorns",
|
"ramhorns",
|
||||||
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
|
|
@ -20,6 +20,7 @@ scraper = "0.17.1"
|
||||||
axum = { version = "0.6.19", features = [ "http2", "tracing" ] }
|
axum = { version = "0.6.19", features = [ "http2", "tracing" ] }
|
||||||
tracing-subscriber = "0.3.17"
|
tracing-subscriber = "0.3.17"
|
||||||
tracing = "0.1.37"
|
tracing = "0.1.37"
|
||||||
|
reqwest = { version = "0.11", default-features = false, features = [ "rustls-tls", "gzip", "brotli", "deflate", "json" ] }
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
strip = true
|
strip = true
|
||||||
|
|
|
@ -16,7 +16,7 @@ env_logger.workspace = true
|
||||||
chrono.workspace = true
|
chrono.workspace = true
|
||||||
sqlx.workspace = true
|
sqlx.workspace = true
|
||||||
scraper.workspace = true
|
scraper.workspace = true
|
||||||
|
reqwest.workspace = true
|
||||||
serde = { version = "1.0.175", features = [ "derive" ] }
|
serde = { version = "1.0.175", features = [ "derive" ] }
|
||||||
reqwest = { version = "0.11", default-features = false, features = [ "rustls-tls", "gzip", "brotli", "deflate" ] }
|
|
||||||
cacache = { version = "11.6.0", default-features = false, features = ["tokio-runtime", "mmap"] }
|
cacache = { version = "11.6.0", default-features = false, features = ["tokio-runtime", "mmap"] }
|
||||||
bincode = "1.3.3"
|
bincode = "1.3.3"
|
||||||
|
|
|
@ -15,5 +15,7 @@ axum.workspace = true
|
||||||
url.workspace = true
|
url.workspace = true
|
||||||
tracing.workspace = true
|
tracing.workspace = true
|
||||||
tracing-subscriber.workspace = true
|
tracing-subscriber.workspace = true
|
||||||
|
reqwest.workspace = true
|
||||||
ramhorns = "0.14.0"
|
ramhorns = "0.14.0"
|
||||||
serde = "1.0.175"
|
serde = "1.0.175"
|
||||||
|
chrono-humanize = "0.2.3"
|
||||||
|
|
|
@ -8,8 +8,11 @@ use axum::{
|
||||||
Json, Router,
|
Json, Router,
|
||||||
};
|
};
|
||||||
use chrono::{DateTime, NaiveDateTime, Utc};
|
use chrono::{DateTime, NaiveDateTime, Utc};
|
||||||
|
use chrono_humanize::HumanTime;
|
||||||
use ramhorns::{Content, Template};
|
use ramhorns::{Content, Template};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
@ -31,7 +34,7 @@ async fn main() {
|
||||||
.route("/search", post(search))
|
.route("/search", post(search))
|
||||||
.route("/style.css", get(stylesheet));
|
.route("/style.css", get(stylesheet));
|
||||||
|
|
||||||
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
let addr = SocketAddr::from(([127, 0, 0, 1], 3001));
|
||||||
tracing::debug!("listening on {}", addr);
|
tracing::debug!("listening on {}", addr);
|
||||||
|
|
||||||
axum::Server::bind(&addr)
|
axum::Server::bind(&addr)
|
||||||
|
@ -72,7 +75,7 @@ struct SearchForm {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Content)]
|
#[derive(Content)]
|
||||||
struct SearchResult {
|
struct RenderSearchResult {
|
||||||
url: String,
|
url: String,
|
||||||
size: i64,
|
size: i64,
|
||||||
title: String,
|
title: String,
|
||||||
|
@ -80,12 +83,21 @@ struct SearchResult {
|
||||||
last_updated: String,
|
last_updated: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct SearchResult {
|
||||||
|
url: Url,
|
||||||
|
size: i64,
|
||||||
|
title: String,
|
||||||
|
summary: String,
|
||||||
|
last_updated: DateTime<Utc>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Content)]
|
#[derive(Content)]
|
||||||
struct SearchResults {
|
struct SearchResults {
|
||||||
title: String,
|
title: String,
|
||||||
description: String,
|
description: String,
|
||||||
query: String,
|
query: String,
|
||||||
results: Vec<SearchResult>,
|
results: Vec<RenderSearchResult>,
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn search(Form(search): Form<SearchForm>) -> Html<String> {
|
async fn search(Form(search): Form<SearchForm>) -> Html<String> {
|
||||||
|
@ -93,28 +105,41 @@ async fn search(Form(search): Form<SearchForm>) -> Html<String> {
|
||||||
let mut contents = String::new();
|
let mut contents = String::new();
|
||||||
source.read_to_string(&mut contents).unwrap();
|
source.read_to_string(&mut contents).unwrap();
|
||||||
|
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
map.insert("language", "eng");
|
||||||
|
map.insert("include", &search.query);
|
||||||
|
map.insert("option", "Fuzzy");
|
||||||
|
|
||||||
|
let client = reqwest::Client::new();
|
||||||
|
let res = client
|
||||||
|
.get("http://127.0.0.1:3000/api/search")
|
||||||
|
.json(&map)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.json::<BTreeMap<i64, SearchResult>>()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
tracing::info!("{:#?}", res);
|
||||||
|
|
||||||
|
let mut results = Vec::new();
|
||||||
|
for (i, r) in res.iter().rev() {
|
||||||
|
results.push(RenderSearchResult {
|
||||||
|
url: r.url.as_str().to_string(),
|
||||||
|
size: r.size,
|
||||||
|
title: r.title.clone(),
|
||||||
|
summary: r.summary.clone(),
|
||||||
|
last_updated: HumanTime::from(r.last_updated).to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let tpl = Template::new(contents).unwrap();
|
let tpl = Template::new(contents).unwrap();
|
||||||
let rendered = tpl.render(&SearchResults {
|
let rendered = tpl.render(&SearchResults {
|
||||||
title: "Ferret".to_string(),
|
title: "Ferret".to_string(),
|
||||||
description: "A small independent search engine".to_string(),
|
description: "A small independent search engine".to_string(),
|
||||||
query: search.query,
|
query: search.query,
|
||||||
results: vec![
|
results,
|
||||||
SearchResult {
|
|
||||||
url: "https://example.com/".to_string(),
|
|
||||||
size: 0,
|
|
||||||
title: "Example Domain".to_string(),
|
|
||||||
summary: "This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.".to_string(),
|
|
||||||
last_updated: "one week ago".to_string(),
|
|
||||||
},
|
|
||||||
SearchResult {
|
|
||||||
url: "https://example.com/".to_string(),
|
|
||||||
size: 0,
|
|
||||||
title: "Example Domain".to_string(),
|
|
||||||
summary: "This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.".to_string(),
|
|
||||||
last_updated: "one week ago".to_string(),
|
|
||||||
}
|
|
||||||
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
Html(rendered)
|
Html(rendered)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue