From 877ecd1feea34cb8f67ab0c95664db69ae9a2f27 Mon Sep 17 00:00:00 2001 From: Myzel394 <50424412+Myzel394@users.noreply.github.com> Date: Thu, 22 Feb 2024 16:48:35 +0100 Subject: [PATCH] fix: Improvements; --- Cargo.lock | 18 +++ Cargo.toml | 3 + src/engines/bing.rs | 2 +- src/engines/engine_base.rs | 20 ++- src/html/beginning.html | 20 --- src/main.rs | 87 +++++++++--- src/public/css/finished.css | 10 ++ src/public/css/style.css | 180 +++++++++++++++++++++++++ src/public/html/beginning.html | 239 +++++++++++++++++++++++++++++++++ src/{ => public}/html/end.html | 1 + src/static_files.rs | 29 ++++ src/utils.rs | 11 ++ 12 files changed, 575 insertions(+), 45 deletions(-) delete mode 100644 src/html/beginning.html create mode 100644 src/public/css/finished.css create mode 100644 src/public/css/style.css create mode 100644 src/public/html/beginning.html rename src/{ => public}/html/end.html (98%) diff --git a/Cargo.lock b/Cargo.lock index 73d4b2a..87076ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -557,6 +557,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "html-escape" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1ad449764d627e22bfd7cd5e8868264fc9236e07c752972b4080cd351cb476" +dependencies = [ + "utf8-width", +] + [[package]] name = "http" version = "0.2.11" @@ -1631,12 +1640,15 @@ dependencies = [ "async-trait", "bytes", "futures", + "html-escape", "lazy-regex", "lazy_static", + "log", "mio", "regex", "reqwest", "rocket", + "rustc-hash", "rustls", "rustls-pemfile", "tokio", @@ -1952,6 +1964,12 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" +[[package]] +name = "utf8-width" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" + [[package]] name = "valuable" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index a6f4370..44825fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,12 +9,15 @@ edition = "2021" async-trait = "0.1.77" bytes = "1.5.0" futures = "0.3.30" +html-escape = "0.2.13" lazy-regex = "3.1.0" lazy_static = "1.4.0" +log = "0.4.20" mio = { version = "0.8.10", features = ["net", "os-poll", ] } regex = "1.10.3" reqwest = { version = "0.11.23", features = ["stream"] } rocket = "0.5.0" +rustc-hash = "1.1.0" rustls = { path = "../rustls/rustls", features = ["logging"] } rustls-pemfile = "2" tokio = {version = "1.35.1", features = ["full"]} diff --git a/src/engines/bing.rs b/src/engines/bing.rs index 7f73f23..ade3009 100644 --- a/src/engines/bing.rs +++ b/src/engines/bing.rs @@ -14,7 +14,7 @@ pub mod bing { lazy_static! { static ref RESULTS_START: Regex = Regex::new(r#"id="b_results""#).unwrap(); - static ref SINGLE_RESULT: Regex = Regex::new(r#"
  • (?P.+?)</a></h2>.*?((<div class="b_caption.*?<p.*?)|(<p class="b_lineclamp3.*?))><span.*?</span>(?P<description>.*?)</p>.*?</li>"#).unwrap(); + static ref SINGLE_RESULT: Regex = Regex::new(r#"<li class="b_algo".*?<h2.*?><a href="(?P<url>.+?)".*?>(?P<title>.+?)</a></h2>.*?((<div class="b_caption.*?<p.*?)|(<p class="b_lineclamp.*?))><span.*?</span>(?P<description>.*?)</p>.*?</li>"#).unwrap(); } #[derive(Clone, Debug)] diff --git a/src/engines/engine_base.rs b/src/engines/engine_base.rs index 133729f..7412646 100644 --- a/src/engines/engine_base.rs +++ b/src/engines/engine_base.rs @@ -1,14 +1,16 @@ pub mod engine_base { - use std::{fmt::Display, sync::Arc}; + use core::fmt; + use std::{fmt::Debug, fmt::Display, sync::Arc}; use futures::{lock::Mutex, Future, StreamExt}; use lazy_static::lazy_static; use regex::Regex; use reqwest::{Error, Response}; + use rustc_hash::FxHashMap; use tokio::sync::mpsc::Sender; use urlencoding::decode; - use crate::utils::utils::decode_html_text; + use crate::utils::utils::{decode_html_text, hash_string}; lazy_static! { static ref STRIP: Regex = Regex::new(r"[\s\n]+").unwrap(); @@ -41,6 +43,16 @@ pub mod engine_base { pub engine: SearchEngine, } + impl SearchResult { + pub fn get_html_id(&self) -> String { + format!( + "html-id-{}-{}", + hash_string(&self.url), + self.url[self.url.len() - 5..].to_string(), + ) + } + } + pub trait EngineBase { fn parse_next<'a>(&mut self) -> Option<SearchResult>; @@ -61,7 +73,9 @@ pub mod engine_base { request: impl Future<Output = Result<Response, Error>>, tx: Sender<SearchResult>, ) -> Result<(), ()> { - let mut stream = request.await.unwrap().bytes_stream(); + let req = request.await.unwrap(); + let url = req.url().clone(); + let mut stream = req.bytes_stream(); while let Some(chunk) = stream.next().await { let buffer = chunk.unwrap(); diff --git a/src/html/beginning.html b/src/html/beginning.html deleted file mode 100644 index 41cbb64..0000000 --- a/src/html/beginning.html +++ /dev/null @@ -1,20 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> - -<head> - <title>tifsep - - - - - - -
    - -
    -
    -
      - - - - diff --git a/src/main.rs b/src/main.rs index f2a6fe1..e19d236 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,15 @@ use std::str; -use std::sync::Arc; use engines::bing::bing::Bing; use engines::brave::brave::Brave; use engines::duckduckgo::duckduckgo::DuckDuckGo; use engines::engine_base::engine_base::SearchResult; -use futures::lock::Mutex; use lazy_static::lazy_static; +use regex::Regex; use rocket::response::content::{RawCss, RawHtml}; use rocket::response::stream::TextStream; use rocket::time::Instant; +use static_files::static_files::{render_beginning_html, render_finished_css}; use tokio::sync::mpsc; use crate::static_files::static_files::read_file_contents; @@ -25,13 +25,16 @@ pub mod utils; extern crate rocket; lazy_static! { - static ref HTML_BEGINNING: String = read_file_contents("./src/html/beginning.html").unwrap(); - static ref HTML_END: String = read_file_contents("./src/html/end.html").unwrap(); - static ref TAILWIND_CSS: String = read_file_contents("./tailwindcss/output.css").unwrap(); + static ref HTML_BEGINNING: String = + read_file_contents("./src/public/html/beginning.html").unwrap(); + static ref SET_VALUE_REPLACE: Regex = Regex::new(r#"\{\% search_value \%\}"#).unwrap(); + static ref HTML_END: String = read_file_contents("./src/public/html/end.html").unwrap(); + static ref TAILWIND_CSS: String = read_file_contents("./src/public/css/style.css").unwrap(); + static ref FINISHED_CSS: String = read_file_contents("./src/public/css/finished.css").unwrap(); + static ref FINISHED_NAME_REPLACE: Regex = Regex::new(r#"(__engine__)"#).unwrap(); + static ref FINISHED_TIME_REPLACE: Regex = Regex::new(r#"{% time %}"#).unwrap(); } -const USER_AGENT: &str = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.3"; - #[get("/search")] fn search_get() -> &'static str { " @@ -44,7 +47,7 @@ fn search_get() -> &'static str { " } -#[get("/tailwind.css")] +#[get("/style.css")] fn get_tailwindcss() -> RawCss<&'static str> { RawCss(&TAILWIND_CSS) } @@ -63,41 +66,83 @@ async fn hello<'a>(query: &str) -> RawHtml { let tx_duckduckgo = tx.clone(); let tx_bing = tx.clone(); - tokio::spawn(async move { + let mut bing_finished_informed = false; + let mut brave_finished_informed = false; + let mut duckduckgo_finished_informed = false; + + let now = Instant::now(); + + let brave_task = tokio::spawn(async move { let mut brave = Brave::new(); brave.search(&query_brave, tx_brave).await; }); - tokio::spawn(async move { + let duckduckgo_task = tokio::spawn(async move { let mut duckduckgo = DuckDuckGo::new(); duckduckgo.search(&query_duckduckgo, tx_duckduckgo).await; }); - tokio::spawn(async move { + let bing_task = tokio::spawn(async move { let mut bing = Bing::new(); bing.search(&query_bing, tx_bing).await; }); + let beginning_html = render_beginning_html(&query); + RawHtml(TextStream! { - yield HTML_BEGINNING.to_string(); + yield beginning_html; - while let Some(result) = rx.recv().await { - if !first_result_yielded { - let diff = first_result_start.elapsed().whole_milliseconds(); - first_result_yielded = true; + while !brave_task.is_finished() || !duckduckgo_task.is_finished() || !bing_task.is_finished() { + while let Some(result) = rx.recv().await { + if !first_result_yielded { + let diff = first_result_start.elapsed().whole_milliseconds(); + first_result_yielded = true; - yield format!("Time taken: {}ms", diff); + yield format!("Time taken: {}ms", diff); + yield "".to_string(); + } + + if !bing_finished_informed && bing_task.is_finished() { + bing_finished_informed = true; + + yield render_finished_css("bing", now.elapsed().whole_milliseconds()); + } + + if !brave_finished_informed && brave_task.is_finished() { + brave_finished_informed = true; + + yield render_finished_css("brave", now.elapsed().whole_milliseconds()); + } + + if !duckduckgo_finished_informed && duckduckgo_task.is_finished() { + duckduckgo_finished_informed = true; + + yield render_finished_css("duckduckgo", now.elapsed().whole_milliseconds()); + } + + let text = format!("
    • {}

      {}

      {}
    • ", &result.title, &result.description, &result.engine.to_string()); + + yield text.to_string(); } - - let text = format!("
    • {}

      {}

      {}
    • ", &result.title, &result.description, &result.engine.to_string()); - - yield text.to_string(); } let diff = first_result_start.elapsed().whole_milliseconds(); + + if !bing_finished_informed { + yield render_finished_css("bing", now.elapsed().whole_milliseconds()); + } + + if !brave_finished_informed { + yield render_finished_css("brave", now.elapsed().whole_milliseconds()); + } + + if !duckduckgo_finished_informed { + yield render_finished_css("duckduckgo", now.elapsed().whole_milliseconds()); + } + yield format!("End taken: {}ms", diff); yield HTML_END.to_string(); }) diff --git a/src/public/css/finished.css b/src/public/css/finished.css new file mode 100644 index 0000000..e8f85b2 --- /dev/null +++ b/src/public/css/finished.css @@ -0,0 +1,10 @@ +#search-status-__engine__::after { + content: "{% time %}ms"; + animation: fadeIn 0.5s; +} + +#search-status-__engine__ svg { + filter: grayscale(50%); + transform: translateY(-100%); + animation: none !important; +} diff --git a/src/public/css/style.css b/src/public/css/style.css new file mode 100644 index 0000000..d60513e --- /dev/null +++ b/src/public/css/style.css @@ -0,0 +1,180 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + background: #2d2d2d; + font-family: Roboto, Helvetica, Arial, sans-serif; + max-width: 1200px; + margin: 0 auto; + color: #aaa; +} + +main { + min-height: 100dvh; + display: grid; + grid-template-columns: 70% 30%; + gap: 2em; + margin: 2em 0; +} + +header { + display: flex; + justify-content: space-between; + align-items: center; + margin: 2em 0; +} + +#search-input { + display: flex; + align-items: center; + gap: 1em; +} + +#search { + min-width: 10em; + font-size: 1rem; + padding: 0.5em 1.2em; + border: none; + border-radius: 10em; + background: #555; + color: #fff; +} + +#search-status { + display: flex; + justify-content: center; + align-items: center; + gap: 4em; +} + +#search-status>div { + position: relative; +} + +#search-status>div>svg { + animation: shimmer 0.5s infinite linear; + transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1); + width: 1.4em; + height: 1.4em; +} + +@keyframes shimmer { + + 0%, + 100% { + filter: brightness(0.4); + } + + 50% { + filter: brightness(1); + } +} + +#search-status-bing::after { + content: ""; + font-size: 0.8rem; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} + +#search-status-duckduckgo::after { + content: ""; + font-size: 0.8rem; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} + +#search-status-brave::after { + content: ""; + font-size: 0.8rem; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} + +#back-button { + background: #555; + fill: #fff; + + width: 2em; + height: 2em; + padding: 0.5em; + border-radius: 50%; +} + +li { + list-style: none; + background: #222; + padding: 1em; + margin: 1em 0; + border-radius: 0.5em; + animation: moveIn 0.5s; +} + +li h1 { + color: #fff; + text-decoration: none; + font-size: 1.2rem; +} + +li p { + color: #aaa; + line-height: 1.5; + font-size: 0.9rem; +} + +li.fake { + height: 6em; + animation: fakeShimmer 0.8s infinite linear; +} + +li.fake.big { + height: 12em; +} + +li.fake.small { + height: 3em; +} + +@keyframes fakeShimmer { + + 0%, + 100% { + filter: brightness(1.3) + } + + 50% { + filter: brightness(1) + } +} + +@keyframes moveIn { + from { + opacity: 0; + transform: translateY(1em); + } + + to { + opacity: 1; + transform: translateY(0); + } +} + + +@keyframes fadeIn { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} diff --git a/src/public/html/beginning.html b/src/public/html/beginning.html new file mode 100644 index 0000000..bb78c25 --- /dev/null +++ b/src/public/html/beginning.html @@ -0,0 +1,239 @@ + + + + + tifsep + + + + + + +
      +
      + + + + +
      +
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      +
      + + + + + + Logotypes/bat/logo-dark@1x + Created with Sketch. + + + + + + + + + + + + + + +
      +
      +
      +
      +
      +
        +
      • +
      • +
      • +
      • +
      • +
      • +
      • + + + + + diff --git a/src/html/end.html b/src/public/html/end.html similarity index 98% rename from src/html/end.html rename to src/public/html/end.html index a4f2f7b..2ce21c6 100644 --- a/src/html/end.html +++ b/src/public/html/end.html @@ -15,6 +15,7 @@
      +
      diff --git a/src/static_files.rs b/src/static_files.rs index 59f3e9e..5b71e6a 100644 --- a/src/static_files.rs +++ b/src/static_files.rs @@ -1,4 +1,5 @@ pub mod static_files { + use lazy_static::lazy_static; use std::{ fs::File, io::{Error, Read}, @@ -13,4 +14,32 @@ pub mod static_files { Ok(contents) } + + lazy_static! { + static ref HTML_BEGINNING: String = + read_file_contents("./src/public/html/beginning.html").unwrap(); + } + + const HTML_BEGINNING_QUERY_REPLACE: &str = r#"{% search_value %}"#; + + pub fn render_beginning_html(query: &str) -> String { + HTML_BEGINNING.replace( + &HTML_BEGINNING_QUERY_REPLACE, + &html_escape::encode_quoted_attribute(query), + ) + } + + lazy_static! { + static ref FINISHED_CSS: String = + read_file_contents("./src/public/css/finished.css").unwrap(); + } + + pub fn render_finished_css(engine: &str, time: i128) -> String { + format!( + "", + FINISHED_CSS + .replace("__engine__", engine) + .replace("{% time %}", &format!("{}ms", &time.to_string())) + ) + } } diff --git a/src/utils.rs b/src/utils.rs index d4af4e0..2ddd435 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -329,4 +329,15 @@ pub mod utils { YieldRequired(T), Completed(T), } + + /// A very fast string hasher + pub fn hash_string(input: &str) -> u64 { + let mut value: u64 = 5381; + + for c in input.chars() { + value = (value << 5).wrapping_add(value).wrapping_add(c as u64); + } + + value + } }