replace commandline arguments with config.lua & add support for changing themes & coloschemes
This commit is contained in:
parent
fe8f5dee43
commit
137c62ed5f
17 changed files with 209 additions and 228 deletions
|
@ -3,50 +3,10 @@
|
|||
//! This module contains the main function which handles the logging of the application to the
|
||||
//! stdout and handles the command line arguments provided and launches the `websurfx` server.
|
||||
|
||||
use std::{ops::RangeInclusive, net::TcpListener};
|
||||
use std::net::TcpListener;
|
||||
|
||||
use clap::{command, Parser};
|
||||
use env_logger::Env;
|
||||
use websurfx::run;
|
||||
|
||||
/// A commandline arguments struct.
|
||||
#[derive(Parser, Debug, Default)]
|
||||
#[clap(author = "neon_arch", version, about = "Websurfx server application")]
|
||||
#[command(propagate_version = true)]
|
||||
struct CliArgs {
|
||||
#[clap(default_value_t = 8080, short, long,value_parser = is_port_in_range)]
|
||||
/// provide port number in range [1024-65536] to launch the server on.
|
||||
port: u16,
|
||||
}
|
||||
|
||||
const PORT_RANGE: RangeInclusive<usize> = 1024..=65535;
|
||||
|
||||
/// A function to check whether port is valid u32 number or is in range
|
||||
/// between [1024-65536] otherwise display an appropriate error message.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `s` - Takes a commandline argument port as a string.
|
||||
///
|
||||
/// # Error
|
||||
///
|
||||
/// Check whether the provided argument to `--port` commandline option is a valid
|
||||
/// u16 argument and returns it as a u16 value otherwise returns an error with an
|
||||
/// appropriate error message.
|
||||
fn is_port_in_range(s: &str) -> Result<u16, String> {
|
||||
let port: usize = s
|
||||
.parse()
|
||||
.map_err(|_| format!("`{s}` is not a valid port number"))?;
|
||||
if PORT_RANGE.contains(&port) {
|
||||
Ok(port as u16)
|
||||
} else {
|
||||
Err(format!(
|
||||
"port not found in range {}-{}",
|
||||
PORT_RANGE.start(),
|
||||
PORT_RANGE.end()
|
||||
))
|
||||
}
|
||||
}
|
||||
use websurfx::{config_parser::parser::Config, run};
|
||||
|
||||
/// The function that launches the main server and registers all the routes of the website.
|
||||
///
|
||||
|
@ -56,14 +16,15 @@ fn is_port_in_range(s: &str) -> Result<u16, String> {
|
|||
/// available for being used for other applications.
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
let args = CliArgs::parse();
|
||||
// Initialize the parsed config file.
|
||||
let config = Config::parse().unwrap();
|
||||
|
||||
// Initializing logging middleware with level set to default or info.
|
||||
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
|
||||
|
||||
log::info!("started server on port {}", args.port);
|
||||
log::info!("started server on port {}", config.port);
|
||||
|
||||
let listener = TcpListener::bind(("127.0.0.1", args.port))?;
|
||||
let listener = TcpListener::bind((config.binding_ip_addr.clone(), config.port))?;
|
||||
|
||||
run(listener)?.await
|
||||
run(listener, config)?.await
|
||||
}
|
||||
|
|
1
src/config_parser/mod.rs
Normal file
1
src/config_parser/mod.rs
Normal file
|
@ -0,0 +1 @@
|
|||
pub mod parser;
|
62
src/config_parser/parser.rs
Normal file
62
src/config_parser/parser.rs
Normal file
|
@ -0,0 +1,62 @@
|
|||
//! This module provides the functionality to parse the lua config and convert the config options
|
||||
//! into rust readable form.
|
||||
|
||||
use rlua::Lua;
|
||||
use serde::Serialize;
|
||||
use std::fs;
|
||||
|
||||
#[derive(Serialize, Clone)]
|
||||
pub struct Style {
|
||||
pub theme: String,
|
||||
pub colorscheme: String,
|
||||
}
|
||||
|
||||
impl Style {
|
||||
pub fn new(theme: String, colorscheme: String) -> Self {
|
||||
Style { theme, colorscheme }
|
||||
}
|
||||
}
|
||||
|
||||
/// A named struct which stores the parsed config file options.
|
||||
///
|
||||
/// # Fields
|
||||
//
|
||||
/// * `port` - It stores the parsed port number option on which the server should launch.
|
||||
/// * `binding_ip_addr` - It stores the parsed ip address option on which the server should launch
|
||||
#[derive(Clone)]
|
||||
pub struct Config {
|
||||
pub port: u16,
|
||||
pub binding_ip_addr: String,
|
||||
pub style: Style,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
/// A function which parses the config.lua file and puts all the parsed options in the newly
|
||||
/// contructed Config struct and returns it.
|
||||
///
|
||||
/// # Error
|
||||
///
|
||||
/// Returns a lua parse error if parsing of the config.lua file fails or has a syntax error
|
||||
/// or io error if the config.lua file doesn't exists otherwise it returns a newly contructed
|
||||
/// Config struct with all the parsed config options from the parsed config file.
|
||||
pub fn parse() -> Result<Self, Box<dyn std::error::Error>> {
|
||||
let lua = Lua::new();
|
||||
|
||||
lua.context(|context| {
|
||||
let globals = context.globals();
|
||||
|
||||
context
|
||||
.load(&fs::read_to_string("./websurfx/config.lua")?)
|
||||
.exec()?;
|
||||
|
||||
Ok(Config {
|
||||
port: globals.get::<_, u16>("port")?,
|
||||
binding_ip_addr: globals.get::<_, String>("binding_ip_addr")?,
|
||||
style: Style::new(
|
||||
globals.get::<_, String>("theme")?,
|
||||
globals.get::<_, String>("colorscheme")?,
|
||||
),
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
14
src/lib.rs
14
src/lib.rs
|
@ -1,21 +1,22 @@
|
|||
//! This main library module provides the functionality to provide and handle the Tcp server
|
||||
//! and register all the routes for the `websurfx` meta search engine website.
|
||||
|
||||
pub mod config_parser;
|
||||
pub mod engines;
|
||||
pub mod server;
|
||||
pub mod search_results_handler;
|
||||
pub mod server;
|
||||
|
||||
use std::net::TcpListener;
|
||||
|
||||
use crate::server::routes;
|
||||
|
||||
use actix_files as fs;
|
||||
use actix_web::{middleware::Logger, web, App, HttpServer, dev::Server};
|
||||
use actix_web::{dev::Server, middleware::Logger, web, App, HttpServer};
|
||||
use config_parser::parser::Config;
|
||||
use handlebars::Handlebars;
|
||||
|
||||
|
||||
/// Runs the web server on the provided TCP listener and returns a `Server` instance.
|
||||
///
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `listener` - A `TcpListener` instance representing the address and port to listen on.
|
||||
|
@ -25,7 +26,7 @@ use handlebars::Handlebars;
|
|||
/// Returns a `Result` containing a `Server` instance on success, or an `std::io::Error` on failure.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::net::TcpListener;
|
||||
/// use websurfx::run;
|
||||
|
@ -33,7 +34,7 @@ use handlebars::Handlebars;
|
|||
/// let listener = TcpListener::bind("127.0.0.1:8080").expect("Failed to bind address");
|
||||
/// let server = run(listener).expect("Failed to start server");
|
||||
/// ```
|
||||
pub fn run(listener: TcpListener) -> std::io::Result<Server> {
|
||||
pub fn run(listener: TcpListener, config: Config) -> std::io::Result<Server> {
|
||||
let mut handlebars: Handlebars = Handlebars::new();
|
||||
|
||||
handlebars
|
||||
|
@ -45,6 +46,7 @@ pub fn run(listener: TcpListener) -> std::io::Result<Server> {
|
|||
let server = HttpServer::new(move || {
|
||||
App::new()
|
||||
.app_data(handlebars_ref.clone())
|
||||
.app_data(web::Data::new(config.clone()))
|
||||
.wrap(Logger::default()) // added logging middleware for logging.
|
||||
// Serve images and static files (css and js files).
|
||||
.service(fs::Files::new("/static", "./public/static").show_files_listing())
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::config_parser::parser::Style;
|
||||
|
||||
/// A named struct to store and serialize the individual search result from all the scraped
|
||||
/// and aggregated search results from the upstream search engines.
|
||||
///
|
||||
|
@ -117,11 +119,12 @@ impl RawSearchResult {
|
|||
/// * `results` - Stores the individual serializable `SearchResult` struct into a vector of
|
||||
/// `SearchResult` structs.
|
||||
/// * `page_query` - Stores the current pages search query `q` provided in the search url.
|
||||
#[derive(Debug, Serialize)]
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SearchResults {
|
||||
pub results: Vec<SearchResult>,
|
||||
pub page_query: String,
|
||||
pub style: Style,
|
||||
}
|
||||
|
||||
impl SearchResults {
|
||||
|
@ -137,6 +140,11 @@ impl SearchResults {
|
|||
SearchResults {
|
||||
results,
|
||||
page_query,
|
||||
style: Style::new("".to_string(), "".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_style(&mut self, style: Style) {
|
||||
self.style = style;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
use std::fs::read_to_string;
|
||||
|
||||
use crate::search_results_handler::aggregator::aggregate;
|
||||
use crate::{config_parser::parser::Config, search_results_handler::aggregator::aggregate};
|
||||
use actix_web::{get, web, HttpRequest, HttpResponse};
|
||||
use handlebars::Handlebars;
|
||||
use serde::Deserialize;
|
||||
|
@ -27,8 +27,9 @@ struct SearchParams {
|
|||
#[get("/")]
|
||||
pub async fn index(
|
||||
hbs: web::Data<Handlebars<'_>>,
|
||||
config: web::Data<Config>,
|
||||
) -> Result<HttpResponse, Box<dyn std::error::Error>> {
|
||||
let page_content: String = hbs.render("index", &"").unwrap();
|
||||
let page_content: String = hbs.render("index", &config.style).unwrap();
|
||||
Ok(HttpResponse::Ok().body(page_content))
|
||||
}
|
||||
|
||||
|
@ -36,8 +37,9 @@ pub async fn index(
|
|||
/// website essentially the 404 error page.
|
||||
pub async fn not_found(
|
||||
hbs: web::Data<Handlebars<'_>>,
|
||||
config: web::Data<Config>,
|
||||
) -> Result<HttpResponse, Box<dyn std::error::Error>> {
|
||||
let page_content: String = hbs.render("404", &"")?;
|
||||
let page_content: String = hbs.render("404", &config.style)?;
|
||||
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type("text/html; charset=utf-8")
|
||||
|
@ -52,7 +54,7 @@ pub async fn not_found(
|
|||
/// ```bash
|
||||
/// curl "http://127.0.0.1:8080/search?q=sweden&page=1"
|
||||
/// ```
|
||||
///
|
||||
///
|
||||
/// Or
|
||||
///
|
||||
/// ```bash
|
||||
|
@ -62,6 +64,7 @@ pub async fn not_found(
|
|||
pub async fn search(
|
||||
hbs: web::Data<Handlebars<'_>>,
|
||||
req: HttpRequest,
|
||||
config: web::Data<Config>,
|
||||
) -> Result<HttpResponse, Box<dyn std::error::Error>> {
|
||||
let params = web::Query::<SearchParams>::from_query(req.query_string())?;
|
||||
match ¶ms.q {
|
||||
|
@ -71,8 +74,9 @@ pub async fn search(
|
|||
.insert_header(("location", "/"))
|
||||
.finish())
|
||||
} else {
|
||||
let results_json: crate::search_results_handler::aggregation_models::SearchResults =
|
||||
let mut results_json: crate::search_results_handler::aggregation_models::SearchResults =
|
||||
aggregate(query, params.page).await?;
|
||||
results_json.add_style(config.style.clone());
|
||||
let page_content: String = hbs.render("search", &results_json)?;
|
||||
Ok(HttpResponse::Ok().body(page_content))
|
||||
}
|
||||
|
@ -96,8 +100,9 @@ pub async fn robots_data(_req: HttpRequest) -> Result<HttpResponse, Box<dyn std:
|
|||
#[get("/about")]
|
||||
pub async fn about(
|
||||
hbs: web::Data<Handlebars<'_>>,
|
||||
config: web::Data<Config>,
|
||||
) -> Result<HttpResponse, Box<dyn std::error::Error>> {
|
||||
let page_content: String = hbs.render("about", &"")?;
|
||||
let page_content: String = hbs.render("about", &config.style)?;
|
||||
Ok(HttpResponse::Ok().body(page_content))
|
||||
}
|
||||
|
||||
|
@ -105,8 +110,9 @@ pub async fn about(
|
|||
#[get("/settings")]
|
||||
pub async fn settings(
|
||||
hbs: web::Data<Handlebars<'_>>,
|
||||
config: web::Data<Config>,
|
||||
) -> Result<HttpResponse, Box<dyn std::error::Error>> {
|
||||
let page_content: String = hbs.render("settings", &"")?;
|
||||
let page_content: String = hbs.render("settings", &config.style)?;
|
||||
Ok(HttpResponse::Ok().body(page_content))
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue