diff options
| author | Fuwn <[email protected]> | 2022-04-19 23:31:53 -0700 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2022-04-19 23:31:53 -0700 |
| commit | 3eef79af97dffc814f034e78674921b4f398b9f9 (patch) | |
| tree | d82542439015be0399072b198af633c1ee3fc0db /src | |
| parent | refactor(modules): move sitemap to modules module (diff) | |
| download | locus-3eef79af97dffc814f034e78674921b4f398b9f9.tar.xz locus-3eef79af97dffc814f034e78674921b4f398b9f9.zip | |
refactor(modules): move search to modules module
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.rs | 103 | ||||
| -rw-r--r-- | src/modules/mod.rs | 1 | ||||
| -rw-r--r-- | src/modules/search.rs | 122 |
3 files changed, 124 insertions, 102 deletions
diff --git a/src/main.rs b/src/main.rs index c625b2e..accffe9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -41,7 +41,6 @@ use std::{collections::HashMap, lazy::SyncLazy, sync::Mutex}; use pickledb::PickleDb; use route::track_mount; -use search::{INDEX, SCHEMA}; use tokio::time::Instant; use windmark::{Response, Router}; use yarte::Template; @@ -156,107 +155,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { ); router.attach_stateless(modules::sitemap::module); - - track_mount( - &mut router, - "/search", - "A search engine for this Gemini capsule", - Box::new(|context| { - let mut response = - String::from("# SEARCH\n\n=> /search?action=go Search!"); - - if let Some(query) = context.url.query_pairs().next() { - if query.0 == "action" && query.1 == "go" { - return Response::Input( - "What would you like to search for?".to_string(), - ); - } - - { - let path = (*SCHEMA.lock().unwrap()).get_field("path").unwrap(); - let description = - (*SCHEMA.lock().unwrap()).get_field("description").unwrap(); - let content = (*SCHEMA.lock().unwrap()).get_field("content").unwrap(); - let mut results = String::new(); - - let searcher = (*INDEX.lock().unwrap()) - .reader_builder() - .reload_policy(tantivy::ReloadPolicy::OnCommit) - .try_into() - .unwrap() - .searcher(); - let top_docs = searcher - .search( - &tantivy::query::QueryParser::for_index( - &(*INDEX.lock().unwrap()), - vec![path, description, content], - ) - .parse_query(&query.0.to_string()) - .unwrap(), - &tantivy::collector::TopDocs::with_limit(SEARCH_SIZE), - ) - .unwrap(); - - for (_score, document_address) in top_docs { - let retrieved_document = searcher.doc(document_address).unwrap(); - - macro_rules! text { - ($field:ident) => {{ - retrieved_document - .get_first($field) - .unwrap() - .as_text() - .unwrap() - }}; - ($document:ident, $field:ident) => {{ - $document.get_first($field).unwrap().as_text().unwrap() - }}; - } - - results += - &format!("=> {} {}{}\n", text!(path), text!(description), { - let mut lines = retrieved_document - .get_first(content) - .unwrap() - .as_text() - .unwrap() - .lines() - .skip(2); - - lines.next().map_or_else( - || "".to_string(), - |first_line| { - format!( - "\n> ... {}\n> {}\n> {} ...", - first_line, - lines.next().unwrap_or(""), - lines.next().unwrap_or("") - ) - }, - ) - }); - } - - response += &format!( - "\n\nYou searched for \"{}\"!\n\n## RESULTS\n\n{}\n\nIn need of \ - more results? This search engine populates its index with route \ - paths and route descriptions on startup. However, route content \ - isn't populated until the route is first visited. After a \ - route's first visit, it is updated after every five minutes, at \ - time of visit.", - query.0, - if results.is_empty() { - "There are no results for your query...".to_string() - } else { - results.trim_end().to_string() - }, - ); - } - } - - success!(response, context) - }), - ); + router.attach_stateless(modules::search::module); track_mount( &mut router, diff --git a/src/modules/mod.rs b/src/modules/mod.rs index b24e0ab..d59d62c 100644 --- a/src/modules/mod.rs +++ b/src/modules/mod.rs @@ -17,4 +17,5 @@ // SPDX-License-Identifier: GPL-3.0-only pub mod multi_blog; +pub mod search; pub mod sitemap; diff --git a/src/modules/search.rs b/src/modules/search.rs new file mode 100644 index 0000000..9ea235f --- /dev/null +++ b/src/modules/search.rs @@ -0,0 +1,122 @@ +// This file is part of Locus <https://github.com/gemrest/locus>. +// Copyright (C) 2022-2022 Fuwn <[email protected]> +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 3. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// Copyright (C) 2022-2022 Fuwn <[email protected]> +// SPDX-License-Identifier: GPL-3.0-only + +use crate::search::{INDEX, SCHEMA}; + +pub fn module(router: &mut windmark::Router) { + crate::track_mount( + router, + "/search", + "A search engine for this Gemini capsule", + Box::new(|context| { + let mut response = + String::from("# SEARCH\n\n=> /search?action=go Search!"); + + if let Some(query) = context.url.query_pairs().next() { + if query.0 == "action" && query.1 == "go" { + return windmark::Response::Input( + "What would you like to search for?".to_string(), + ); + } + + { + let path = (*SCHEMA.lock().unwrap()).get_field("path").unwrap(); + let description = + (*SCHEMA.lock().unwrap()).get_field("description").unwrap(); + let content = (*SCHEMA.lock().unwrap()).get_field("content").unwrap(); + let mut results = String::new(); + + let searcher = (*INDEX.lock().unwrap()) + .reader_builder() + .reload_policy(tantivy::ReloadPolicy::OnCommit) + .try_into() + .unwrap() + .searcher(); + let top_docs = searcher + .search( + &tantivy::query::QueryParser::for_index( + &(*INDEX.lock().unwrap()), + vec![path, description, content], + ) + .parse_query(&query.0.to_string()) + .unwrap(), + &tantivy::collector::TopDocs::with_limit(crate::SEARCH_SIZE), + ) + .unwrap(); + + for (_score, document_address) in top_docs { + let retrieved_document = searcher.doc(document_address).unwrap(); + + macro_rules! text { + ($field:ident) => {{ + retrieved_document + .get_first($field) + .unwrap() + .as_text() + .unwrap() + }}; + ($document:ident, $field:ident) => {{ + $document.get_first($field).unwrap().as_text().unwrap() + }}; + } + + results += + &format!("=> {} {}{}\n", text!(path), text!(description), { + let mut lines = retrieved_document + .get_first(content) + .unwrap() + .as_text() + .unwrap() + .lines() + .skip(2); + + lines.next().map_or_else( + || "".to_string(), + |first_line| { + format!( + "\n> ... {}\n> {}\n> {} ...", + first_line, + lines.next().unwrap_or(""), + lines.next().unwrap_or("") + ) + }, + ) + }); + } + + response += &format!( + "\n\nYou searched for \"{}\"!\n\n## RESULTS\n\n{}\n\nIn need of \ + more results? This search engine populates its index with route \ + paths and route descriptions on startup. However, route content \ + isn't populated until the route is first visited. After a \ + route's first visit, it is updated after every five minutes, at \ + time of visit.", + query.0, + if results.is_empty() { + "There are no results for your query...".to_string() + } else { + results.trim_end().to_string() + }, + ); + } + } + + crate::success!(response, context) + }), + ); +} |