Skip to content

Commit

Permalink
📦 Simplify crate layout
Browse files Browse the repository at this point in the history
  • Loading branch information
KimlikDAO-bot committed Sep 3, 2024
1 parent bd746bb commit 174aee9
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 131 deletions.
4 changes: 1 addition & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,9 @@ name = "crate_server"
path = "rust/crate_server/main.rs"

[dependencies]
arrayvec = "0.7.6"
hyper = { version = "0.14.12", features = ["http1", "server", "tcp"] }
lazy_static = "1.5.0"
phf = { version = "0.11.2", features = ["macros"] }
serde = { version = "1.0", features = ["derive"] }
serde_yaml = "0.9"
tokio = { version = "1", features = ["full"] }

[profile.release]
Expand Down
198 changes: 71 additions & 127 deletions rust/crate_server/crates.rs
Original file line number Diff line number Diff line change
@@ -1,113 +1,64 @@
use arrayvec::ArrayString;
use hyper::header::{
ACCEPT_ENCODING, ACCEPT_LANGUAGE, CACHE_CONTROL, CDN_CACHE_CONTROL, CONTENT_ENCODING,
CONTENT_TYPE, COOKIE, EXPIRES, LOCATION, VARY,
};
use hyper::{Body, Request, Response, StatusCode};
use lazy_static::lazy_static;
use serde::Deserialize;
use std::collections::HashMap;
use std::convert::Infallible;
use std::fs;
use std::fs::File;

#[derive(Debug, Deserialize)]
struct CrateRecipe {
dizin: String,
sayfalar: Vec<Sayfa>,
}

#[derive(Debug, Deserialize)]
struct Sayfa {
tr: String,
en: String,
}

fn load(path: &str) -> HashMap<String, &'static [u8]> {
fn load(path: &str) -> HashMap<ArrayString<16>, &'static [u8]> {
let mut files = HashMap::new();
for entry in fs::read_dir(path).unwrap() {
let entry = entry.unwrap();
let path = entry.path();
if path.is_file() {
let filename = path.file_name().unwrap().to_string_lossy().to_string();
let content: &'static [u8] = Box::leak(fs::read(&path).unwrap().into_boxed_slice());
files.insert(filename, content);
}
}
let file = File::open("./crate/crate.yaml").unwrap();
let recipe: CrateRecipe = serde_yaml::from_reader(file).unwrap();

let mut insert_alias = |alias: &str, key_base: &str, lang: &str, ext: &str| {
if let Some(&content) = files.get(&format!("{}-{}.html{}", key_base, lang, ext)) {
files.insert(format!("{}{}", alias, ext), content);
let filename = path.file_name().unwrap().to_string_lossy();
if let Ok(array_key) = ArrayString::<16>::from(&filename[..]) {
let content: &'static [u8] = Box::leak(fs::read(&path).unwrap().into_boxed_slice());
files.insert(array_key, content);
} else {
eprintln!("Filename '{}' is too long for ArrayString<16>", filename);
}
}
};

insert_alias("?en", &recipe.dizin, "en", "");
insert_alias("?en", &recipe.dizin, "en", ".br");
insert_alias("?en", &recipe.dizin, "en", ".gz");
insert_alias("?tr", &recipe.dizin, "tr", "");
insert_alias("?tr", &recipe.dizin, "tr", ".br");
insert_alias("?tr", &recipe.dizin, "tr", ".gz");

for sayfa in &recipe.sayfalar {
insert_alias(&sayfa.en, &sayfa.tr, "en", "");
insert_alias(&sayfa.tr, &sayfa.tr, "tr", "");
insert_alias(&sayfa.en, &sayfa.tr, "en", ".br");
insert_alias(&sayfa.tr, &sayfa.tr, "tr", ".br");
insert_alias(&sayfa.en, &sayfa.tr, "en", ".gz");
insert_alias(&sayfa.tr, &sayfa.tr, "tr", ".gz");
}

files
}

lazy_static! {
static ref FILES: HashMap<String, &'static [u8]> = load("./crate");
static ref FILES: HashMap<ArrayString<16>, &'static [u8]> = load("./crate");
}

static STATIC_CACHE_CONTROL: &'static str = "max-age=29030400,public,immutable";

fn get_crate_key(req: &Request<Body>) -> String {
let trimmed_path = req.uri().path().trim_matches('/');

if !trimmed_path.is_empty() {
return trimmed_path.to_string();
fn get_crate_key(req: &Request<Body>) -> &str {
let key = req.uri().path().trim_matches('/');
if !key.is_empty() {
return key;
}

let trimmed_path = req
.uri()
.path_and_query()
.unwrap()
.as_str()
.trim_matches('/');
if trimmed_path.len() == 3 {
return trimmed_path.to_string();
if let Some(cookie_header) = req.headers().get(COOKIE) {
if let Ok(cookie_str) = cookie_header.to_str() {
if let Some(leq) = cookie_str.find("l=") {
return &cookie_str[leq + 2..leq + 4];
}
}
}

let cookies_str = req
.headers()
.get(COOKIE)
.and_then(|v| v.to_str().ok())
.unwrap_or("");
if cookies_str.contains("l=tr") {
"?tr".to_string()
} else if cookies_str.contains("l=en") {
"?en".to_string()
} else if req
.headers()
.get(ACCEPT_LANGUAGE)
.and_then(|v| v.to_str().ok())
.unwrap_or("")
.contains("tr")
{
"?tr".to_string()
} else {
"?en".to_string()
if let Some(lang) = req.headers().get(ACCEPT_LANGUAGE) {
if let Ok(lang) = lang.to_str() {
if lang.contains("tr") {
return "tr";
}
}
}
"en"
}

pub async fn serve_file(req: Request<Body>) -> Result<Response<Body>, Infallible> {
let mut key = get_crate_key(&req);
let mut key = ArrayString::<16>::new();
key.push_str(get_crate_key(&req));
let accept_encoding = req
.headers()
.get(ACCEPT_ENCODING)
Expand All @@ -129,7 +80,7 @@ pub async fn serve_file(req: Request<Body>) -> Result<Response<Body>, Infallible
None
};
if let Some(compression) = maybe_compression {
key += &compression[..3];
key.push_str(&compression[..3]);
}
match FILES.get(&key) {
Some(&content) => {
Expand Down Expand Up @@ -157,69 +108,62 @@ pub async fn serve_file(req: Request<Body>) -> Result<Response<Body>, Infallible
#[cfg(test)]
mod tests {
use super::*;
use hyper::header::HeaderValue;
use hyper::{Body, Request, Uri};
use hyper::{
header::{ACCEPT_LANGUAGE, COOKIE},
Body, Request,
};

fn mock_request(
uri: &'static str,
cookies: Option<&str>,
accept_language: Option<&str>,
) -> Request<Body> {
let mut request = Request::builder()
.uri(Uri::from_static(uri))
#[test]
fn test_get_crate_key_with_path() {
// Case 1: Request with a non-empty path
let req = Request::builder()
.uri("/somepath")
.body(Body::empty())
.unwrap();

let headers = request.headers_mut();
if let Some(cookie) = cookies {
headers.insert("cookie", HeaderValue::from_str(cookie).unwrap());
}
if let Some(lang) = accept_language {
headers.insert("accept-language", HeaderValue::from_str(lang).unwrap());
}

request
}

#[test]
fn test_get_crate_key_with_non_empty_path() {
let req = mock_request("/test", None, None);
assert_eq!(get_crate_key(&req), "test".to_string());
}

#[test]
fn test_get_crate_key_with_empty_path_and_short_query() {
let req = mock_request("/", None, None);
assert_eq!(get_crate_key(&req), "?en".to_string());
assert_eq!(get_crate_key(&req), "somepath");
}

#[test]
fn test_get_crate_key_with_empty_path_and_ltr_cookie() {
let req = mock_request("/", Some("l=tr"), None);
assert_eq!(get_crate_key(&req), "?tr".to_string());
fn test_get_crate_key_with_cookie_language() {
// Case 2: Request with a cookie containing 'l='
let req = Request::builder()
.header(COOKIE, "session=abc; l=tr; other=data")
.body(Body::empty())
.unwrap();
assert_eq!(get_crate_key(&req), "tr");
}

#[test]
fn test_get_crate_key_with_empty_path_and_len_cookie() {
let req = mock_request("/", Some("l=en"), None);
assert_eq!(get_crate_key(&req), "?en".to_string());
}
fn test_get_crate_key_with_accept_language_header() {
// Case 3: Request with 'Accept-Language' header containing 'tr'
let req = Request::builder()
.header(ACCEPT_LANGUAGE, "tr, en;q=0.8")
.body(Body::empty())
.unwrap();
assert_eq!(get_crate_key(&req), "tr");

#[test]
fn test_get_crate_key_with_empty_path_and_accept_language_tr() {
let req = mock_request("/", None, Some("tr"));
assert_eq!(get_crate_key(&req), "?tr".to_string());
// Case 4: Request with 'Accept-Language' header not containing 'tr'
let req = Request::builder()
.header(ACCEPT_LANGUAGE, "en, fr;q=0.8")
.body(Body::empty())
.unwrap();
assert_eq!(get_crate_key(&req), "en");
}

#[test]
fn test_get_crate_key_with_empty_path_and_accept_language_en() {
let req = mock_request("/", None, Some("en"));
assert_eq!(get_crate_key(&req), "?en".to_string());
fn test_get_crate_key_with_no_headers() {
// Case 5: Request with no relevant headers and no path
let req = Request::builder().uri("/").body(Body::empty()).unwrap();
assert_eq!(get_crate_key(&req), "en");
}

#[test]
fn test_get_crate_key_with_empty_path_no_cookies_or_headers() {
let req = mock_request("/", None, None);
assert_eq!(get_crate_key(&req), "?en".to_string());
fn test_get_crate_key_empty_cookie_header() {
// Case 6: Request with empty cookie header
let req = Request::builder()
.header(COOKIE, "")
.body(Body::empty())
.unwrap();
assert_eq!(get_crate_key(&req), "en");
}
}
2 changes: 1 addition & 1 deletion rust/crate_server/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ async fn main() {
Ok::<_, Infallible>(service_fn(move |req| crates::serve_file(req)))
});

let addr = SocketAddr::from(([127, 0, 0, 1], 8787)); // Running server on localhost:3000
let addr = SocketAddr::from(([0, 0, 0, 0, 0, 0, 0, 0], 80));
let server = Server::bind(&addr).serve(make_svc);

println!("Listening on http://{}", addr);
Expand Down

0 comments on commit 174aee9

Please sign in to comment.