mirror of
https://github.com/ivabus/urouter
synced 2024-11-22 00:15:11 +03:00
0.5.2: beautify everything
- Use serde_json::from_reader in alias list initialization - Compile all regexes in initialization, not while recieving first triggering request - Count regex compilation time - Specify version in Server responce header Signed-off-by: Ivan Bushchik <ivabus@ivabus.dev>
This commit is contained in:
parent
0815b295b2
commit
886c4cf2fa
4 changed files with 43 additions and 31 deletions
|
@ -1,10 +1,10 @@
|
||||||
[package]
|
[package]
|
||||||
name = "urouter"
|
name = "urouter"
|
||||||
version = "0.5.1"
|
version = "0.5.2"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://github.com/ivabus/urouter"
|
repository = "https://github.com/ivabus/urouter"
|
||||||
description = "Small router for (kinda) short domains (fork of ivabus/aliurl without REST API)"
|
description = "Small HTTP router"
|
||||||
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
|
@ -20,8 +20,8 @@ Each set contains 2 necessary elements and 1 optional.
|
||||||
- `uri` (string) - of url after host (e.g., `/`, `some/cool/path`, should not start with `/` (only for root))
|
- `uri` (string) - of url after host (e.g., `/`, `some/cool/path`, should not start with `/` (only for root))
|
||||||
- `alias` (set) - set of one field
|
- `alias` (set) - set of one field
|
||||||
- `url` (string) - redirect to url with HTTP 303 See Other
|
- `url` (string) - redirect to url with HTTP 303 See Other
|
||||||
- `file` (string) - read file from path `--dir/file` where `--dir` is option (default: `.`, see `--help`) and respond with HTTP 200 OK `content-type: text/plain; charset=utf-8`
|
- `file` (string) - read file from path `--dir/file` where `--dir` is option (default: `.`, see `--help`) and respond with HTTP 200 OK with `content-type: text/plain`
|
||||||
- `text` (string) - plain text
|
- `text` (string) - plain text HTTP 200 OK with `content-type: text/plain`
|
||||||
- Optional
|
- Optional
|
||||||
- `agent` (set) - set of one necessary field and one optional
|
- `agent` (set) - set of one necessary field and one optional
|
||||||
- `regex` (string) - regular expression to match user-agent HTTP header
|
- `regex` (string) - regular expression to match user-agent HTTP header
|
||||||
|
|
64
src/main.rs
64
src/main.rs
|
@ -31,7 +31,9 @@ extern crate rocket;
|
||||||
use rocket::http::Status;
|
use rocket::http::Status;
|
||||||
use std::cell::{OnceCell, RefCell};
|
use std::cell::{OnceCell, RefCell};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::hint::unreachable_unchecked;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
use rocket::response::content::RawText;
|
use rocket::response::content::RawText;
|
||||||
use rocket::response::Redirect;
|
use rocket::response::Redirect;
|
||||||
|
@ -46,14 +48,14 @@ static mut COMPILED_REGEXES: RefCell<Option<HashMap<String, Regex>>> = RefCell::
|
||||||
fn get_return(alias: &Alias) -> Response {
|
fn get_return(alias: &Alias) -> Response {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
let mut dir = args.dir.clone();
|
let mut dir = args.dir.clone();
|
||||||
return match &alias.alias {
|
match &alias.alias {
|
||||||
AliasType::Url(url) => Response::Redirect(Redirect::to(url.clone())),
|
AliasType::Url(url) => Response::Redirect(Box::from(Redirect::to(url.clone()))),
|
||||||
AliasType::File(path) => {
|
AliasType::File(path) => {
|
||||||
dir.push(&PathBuf::from(&path));
|
dir.push(&PathBuf::from(&path));
|
||||||
Response::Text(RawText(smurf::io::read_file_str(&dir).unwrap()))
|
Response::Text(RawText(smurf::io::read_file_str(&dir).unwrap()))
|
||||||
}
|
}
|
||||||
AliasType::Text(text) => Response::Text(RawText(text.clone())),
|
AliasType::Text(text) => Response::Text(RawText(text.clone())),
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/<page>")]
|
#[get("/<page>")]
|
||||||
|
@ -64,37 +66,30 @@ fn get_page(page: &str, user_agent: UserAgent) -> Response {
|
||||||
let mut pages = Vec::new();
|
let mut pages = Vec::new();
|
||||||
for i in alias {
|
for i in alias {
|
||||||
if i.uri == decoded_page {
|
if i.uri == decoded_page {
|
||||||
match &i.agent {
|
if let Some(agent) = &i.agent {
|
||||||
Some(agent) => unsafe {
|
unsafe {
|
||||||
let re = if let Some(regexes) = COMPILED_REGEXES.get_mut() {
|
let regexes = COMPILED_REGEXES.get_mut();
|
||||||
match regexes.get(&agent.regex) {
|
let re = if let Some(r) = regexes {
|
||||||
Some(re) => re.clone(),
|
// Unwrapping safely, guaranteed to be generated during initialization
|
||||||
None => {
|
r.get(&agent.regex).unwrap()
|
||||||
let re = Regex::new(&agent.regex).unwrap();
|
|
||||||
regexes.insert(agent.regex.clone(), re.clone());
|
|
||||||
re.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// guaranteed to be initialized at the beginning
|
unreachable_unchecked()
|
||||||
unreachable!()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if re.is_match(&user_agent.0) {
|
if re.is_match(&user_agent.0) {
|
||||||
return get_return(&i);
|
return get_return(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(true) = agent.only_matching {
|
if let Some(true) = agent.only_matching {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
pages.push(i);
|
pages.push(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Returning normal page (if found) to curl users.
|
// Returning normal page (if found) to curl users.
|
||||||
if pages.len() != 0 {
|
if !pages.is_empty() {
|
||||||
return get_return(pages[0]);
|
return get_return(pages[0]);
|
||||||
}
|
}
|
||||||
Response::Status(Status::NotFound)
|
Response::Status(Status::NotFound)
|
||||||
|
@ -108,20 +103,37 @@ async fn index(user_agent: UserAgent) -> Response {
|
||||||
#[rocket::main]
|
#[rocket::main]
|
||||||
async fn main() -> Result<(), rocket::Error> {
|
async fn main() -> Result<(), rocket::Error> {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
|
let file = std::fs::File::open(args.alias_file).unwrap();
|
||||||
let alias: Vec<Alias> = if args.alias_file_is_set_not_a_list {
|
let alias: Vec<Alias> = if args.alias_file_is_set_not_a_list {
|
||||||
let set: NixJson =
|
serde_json::from_reader::<std::fs::File, NixJson>(file).unwrap().alias
|
||||||
serde_json::from_str(&smurf::io::read_file_str(&args.alias_file).unwrap()).unwrap();
|
|
||||||
set.alias
|
|
||||||
} else {
|
} else {
|
||||||
serde_json::from_str(&smurf::io::read_file_str(&args.alias_file).unwrap()).unwrap()
|
serde_json::from_reader::<std::fs::File, Vec<Alias>>(file).unwrap()
|
||||||
};
|
};
|
||||||
unsafe {
|
unsafe {
|
||||||
ALIAS.set(alias).unwrap();
|
ALIAS.set(alias).unwrap();
|
||||||
*COMPILED_REGEXES.get_mut() = Some(HashMap::new());
|
|
||||||
|
let compilation_start = Instant::now();
|
||||||
|
let mut regexes_len = 0;
|
||||||
|
// Precompile all regexes
|
||||||
|
let mut compiled_regexes: HashMap<String, Regex> = HashMap::new();
|
||||||
|
for i in ALIAS.get().unwrap() {
|
||||||
|
if let Some(agent) = &i.agent {
|
||||||
|
compiled_regexes.insert(agent.regex.clone(), Regex::new(&agent.regex).unwrap());
|
||||||
|
regexes_len += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if regexes_len != 0 {
|
||||||
|
println!(
|
||||||
|
"Compiled {} regexes in {} ms",
|
||||||
|
regexes_len,
|
||||||
|
(Instant::now() - compilation_start).as_secs_f64() * 1000.0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
*COMPILED_REGEXES.get_mut() = Some(compiled_regexes);
|
||||||
}
|
}
|
||||||
|
|
||||||
let figment = Figment::from(rocket::Config::default())
|
let figment = Figment::from(rocket::Config::default())
|
||||||
.merge(("ident", "urouter"))
|
.merge(("ident", format!("urouter/{}", env!("CARGO_PKG_VERSION"))))
|
||||||
.merge(("port", args.port))
|
.merge(("port", args.port))
|
||||||
.merge(("address", args.address));
|
.merge(("address", args.address));
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ pub struct Agent {
|
||||||
#[derive(Responder)]
|
#[derive(Responder)]
|
||||||
pub enum Response {
|
pub enum Response {
|
||||||
Text(RawText<String>),
|
Text(RawText<String>),
|
||||||
Redirect(Redirect),
|
Redirect(Box<Redirect>),
|
||||||
Status(Status),
|
Status(Status),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue