about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVika <vika@fireburn.ru>2022-10-25 22:47:35 +0300
committerVika <vika@fireburn.ru>2022-11-06 17:38:03 +0300
commit8c523414f007d54e0145ad9335a8932043a19f16 (patch)
treefe5cc306820740b330d1e1150549d077e52bbe61
parent4b917f257a41e6bdfd32e91d7a38bdc975c8f678 (diff)
kittybox-frontend-renderer: gzip static assets
-rw-r--r--kittybox-rs/Cargo.lock54
-rw-r--r--kittybox-rs/templates/Cargo.toml4
-rw-r--r--kittybox-rs/templates/build.rs88
-rw-r--r--kittybox-rs/templates/src/lib.rs21
4 files changed, 149 insertions, 18 deletions
diff --git a/kittybox-rs/Cargo.lock b/kittybox-rs/Cargo.lock
index e8e0bf3..9e7cba9 100644
--- a/kittybox-rs/Cargo.lock
+++ b/kittybox-rs/Cargo.lock
@@ -9,6 +9,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 
 [[package]]
+name = "adler32"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
+
+[[package]]
 name = "aho-corasick"
 version = "0.7.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1297,10 +1303,12 @@ dependencies = [
  "include_dir",
  "kittybox-indieauth",
  "kittybox-util",
+ "libflate",
  "markup",
  "microformats",
  "rand 0.8.5",
  "serde_json",
+ "walkdir",
 ]
 
 [[package]]
@@ -1355,6 +1363,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b"
 
 [[package]]
+name = "libflate"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05605ab2bce11bcfc0e9c635ff29ef8b2ea83f29be257ee7d730cac3ee373093"
+dependencies = [
+ "adler32",
+ "crc32fast",
+ "libflate_lz77",
+]
+
+[[package]]
+name = "libflate_lz77"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39a734c0493409afcd49deee13c006a04e3586b9761a03543c6272c9c51f2f5a"
+dependencies = [
+ "rle-decode-fast",
+]
+
+[[package]]
 name = "listenfd"
 version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2427,6 +2455,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "rle-decode-fast"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422"
+
+[[package]]
 name = "rustc_version"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2472,6 +2506,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
 
 [[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
 name = "schannel"
 version = "0.1.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3342,6 +3385,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
 
 [[package]]
+name = "walkdir"
+version = "2.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
+dependencies = [
+ "same-file",
+ "winapi",
+ "winapi-util",
+]
+
+[[package]]
 name = "want"
 version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/kittybox-rs/templates/Cargo.toml b/kittybox-rs/templates/Cargo.toml
index ffdfc25..7090046 100644
--- a/kittybox-rs/templates/Cargo.toml
+++ b/kittybox-rs/templates/Cargo.toml
@@ -5,6 +5,10 @@ edition = "2021"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
+[build-dependencies]
+libflate = "^1.2.0"
+walkdir = "^2.3.2"
+
 [dev-dependencies]
 faker_rand = "^0.1.1"
 rand = "^0.8.5"
diff --git a/kittybox-rs/templates/build.rs b/kittybox-rs/templates/build.rs
index 1140060..ccd5b19 100644
--- a/kittybox-rs/templates/build.rs
+++ b/kittybox-rs/templates/build.rs
@@ -1,26 +1,90 @@
-fn main() {
+use std::ffi::OsStr;
+
+use libflate::gzip::Encoder;
+use walkdir::WalkDir;
+
+fn main() -> Result<(), std::io::Error> {
     use std::env;
     let out_dir = std::path::PathBuf::from(env::var("OUT_DIR").unwrap());
-    println!("cargo:rerun-if-changed=assets/");
-    let assets = std::fs::read_dir("assets").unwrap();
-    for file in assets.map(|a| a.unwrap()) {
-        std::fs::copy(
-            file.path(),
-            out_dir.join(file.file_name())
-        )
-            .unwrap();
-    }
+
     println!("cargo::rerun-if-changed=javascript/");
     if let Ok(exit) = std::process::Command::new("tsc")
         .arg("--outDir")
         .arg(&out_dir)
         .current_dir("javascript")
-        .spawn()
-        .unwrap()
+        .spawn()?
         .wait()
     {
         if !exit.success() {
             std::process::exit(exit.code().unwrap_or(1))
         }
     }
+
+    println!("cargo:rerun-if-changed=assets/");
+    let assets_path = std::path::Path::new("assets");
+    let mut assets = WalkDir::new(&assets_path)
+        .into_iter();
+    while let Some(Ok(entry)) = assets.next() {
+        if entry.file_type().is_dir() {
+            if let Err(err) = std::fs::create_dir(&out_dir.join(entry.path())) {
+                if err.kind() != std::io::ErrorKind::AlreadyExists {
+                    return Err(err)
+                }
+            }
+        } else {
+            std::fs::copy(entry.path(), &out_dir.join(entry.path().strip_prefix(assets_path).unwrap()))?;
+        }
+    }
+
+    let walker = WalkDir::new(&out_dir)
+        .into_iter()
+        .map(Result::unwrap)
+        .filter(|e| {
+            e.file_type().is_file() && e.path().extension().unwrap() != "gz"
+        });
+    for entry in walker {
+        let normal_path = entry.path();
+        let gzip_path = normal_path.with_extension({
+            let mut extension = normal_path
+                .extension()
+                .unwrap()
+                .to_owned();
+            extension.push(OsStr::new(".gz"));
+            extension
+        });
+        eprintln!(
+            "{} -> {}",
+            normal_path.strip_prefix(&out_dir).unwrap().display(),
+            gzip_path.strip_prefix(&out_dir).unwrap().display()
+        );
+        {
+            let mut out_file = std::fs::OpenOptions::new()
+                .create(true)
+                .truncate(true)
+                .write(true)
+                .open(&gzip_path)?;
+
+            let mut in_file = std::fs::File::open(&normal_path)?;
+
+            let mut encoder = Encoder::new(&mut out_file)?;
+            std::io::copy(&mut in_file, &mut encoder)?;
+            encoder.finish().into_result()?;
+        }
+
+        let normal_len: f64 = std::fs::metadata(&normal_path).unwrap().len() as f64;
+        let gzipped_len: f64 = std::fs::metadata(&gzip_path).unwrap().len() as f64;
+        let ratio = gzipped_len / normal_len;
+        eprintln!("Ratio: {}", ratio);
+        if ratio <= 0.9 {
+            std::fs::remove_file(&normal_path)?
+        } else {
+            println!(
+                "cargo:warning={} compression ratio is {} (> 0.9), leaving as is",
+                entry.path().display(),
+                ratio
+            );
+            std::fs::remove_file(&gzip_path)?
+        }
+    }
+    Ok(())
 }
diff --git a/kittybox-rs/templates/src/lib.rs b/kittybox-rs/templates/src/lib.rs
index 5b3a8df..8d5d5fa 100644
--- a/kittybox-rs/templates/src/lib.rs
+++ b/kittybox-rs/templates/src/lib.rs
@@ -13,13 +13,15 @@ pub mod assets {
     use axum::response::{IntoResponse, Response};
     use axum::extract::Path;
     use axum::http::StatusCode;
-    use axum::http::header::{CONTENT_TYPE, CACHE_CONTROL};
+    use axum::http::header::{CONTENT_TYPE, CONTENT_ENCODING, CACHE_CONTROL};
 
-    const ASSETS: include_dir::Dir<'static> = include_dir::include_dir!("$OUT_DIR");
+    const ASSETS: include_dir::Dir<'static> = include_dir::include_dir!("$OUT_DIR/");
     const CACHE_FOR_A_DAY: &str = "max-age=86400";
+    const GZIP: &str = "gzip";
 
-    pub async fn statics(Path(path): Path<String>) -> Response {
-
+    pub async fn statics(
+        Path(path): Path<String>
+    ) -> Response {
         let content_type: &'static str = if path.ends_with(".js") {
             "application/javascript"
         } else if path.ends_with(".css") {
@@ -30,12 +32,19 @@ pub mod assets {
             "application/octet-stream"
         };
 
-        match ASSETS.get_file(path) {
+        match ASSETS.get_file(path.clone() + ".gz") {
             Some(file) => (StatusCode::OK,
                            [(CONTENT_TYPE, content_type),
+                            (CONTENT_ENCODING, GZIP),
                             (CACHE_CONTROL, CACHE_FOR_A_DAY)],
                            file.contents()).into_response(),
-            None => StatusCode::NOT_FOUND.into_response()
+            None => match ASSETS.get_file(path) {
+                Some(file) => (StatusCode::OK,
+                               [(CONTENT_TYPE, content_type),
+                                (CACHE_CONTROL, CACHE_FOR_A_DAY)],
+                               file.contents()).into_response(),
+                None => StatusCode::NOT_FOUND.into_response()
+            }
         }
     }
 }