]> OzVa Git service - ozva-cloud/commitdiff
refactor: split css/js from index.html (#68)
authorsigoden <sigoden@gmail.com>
Tue, 21 Jun 2022 15:01:00 +0000 (23:01 +0800)
committerGitHub <noreply@github.com>
Tue, 21 Jun 2022 15:01:00 +0000 (23:01 +0800)
src/server.rs
tests/assets.rs [new file with mode: 0644]
tests/favicon.rs [deleted file]
tests/utils.rs

index 9417b434d9d2d6ea91404eb33fefedefab00833b..6c8f38404717fb4697c1641497d872d093f4c218 100644 (file)
@@ -44,11 +44,16 @@ const BUF_SIZE: usize = 65536;
 
 pub struct Server {
     args: Arc<Args>,
+    assets_prefix: String,
 }
 
 impl Server {
     pub fn new(args: Arc<Args>) -> Self {
-        Self { args }
+        let assets_prefix = format!("{}__dufs_v{}_", args.uri_prefix, env!("CARGO_PKG_VERSION"));
+        Self {
+            args,
+            assets_prefix,
+        }
     }
 
     pub async fn call(
@@ -58,12 +63,15 @@ impl Server {
     ) -> Result<Response, hyper::Error> {
         let method = req.method().clone();
         let uri = req.uri().clone();
+        let assets_prefix = self.assets_prefix.clone();
         let enable_cors = self.args.enable_cors;
 
         let mut res = match self.handle(req).await {
             Ok(res) => {
                 let status = res.status().as_u16();
-                info!(r#"{} "{} {}" - {}"#, addr.ip(), method, uri, status,);
+                if !uri.path().starts_with(&assets_prefix) {
+                    info!(r#"{} "{} {}" - {}"#, addr.ip(), method, uri, status,);
+                }
                 res
             }
             Err(err) => {
@@ -89,8 +97,7 @@ impl Server {
         let headers = req.headers();
         let method = req.method().clone();
 
-        if req_path == "/favicon.ico" && method == Method::GET {
-            self.handle_send_favicon(headers, &mut res).await?;
+        if method == Method::GET && self.handle_embed_assets(req_path, &mut res).await? {
             return Ok(res);
         }
 
@@ -418,23 +425,38 @@ impl Server {
         Ok(())
     }
 
-    async fn handle_send_favicon(
-        &self,
-        headers: &HeaderMap<HeaderValue>,
-        res: &mut Response,
-    ) -> BoxResult<()> {
-        let path = self.args.path.join("favicon.ico");
-        let meta = fs::metadata(&path).await.ok();
-        let is_file = meta.map(|v| v.is_file()).unwrap_or_default();
-        if is_file {
-            self.handle_send_file(path.as_path(), headers, false, res)
-                .await?;
+    async fn handle_embed_assets(&self, req_path: &str, res: &mut Response) -> BoxResult<bool> {
+        if let Some(name) = req_path.strip_prefix(&self.assets_prefix) {
+            match name {
+                "index.js" => {
+                    *res.body_mut() = Body::from(INDEX_JS);
+                    res.headers_mut().insert(
+                        "content-type",
+                        HeaderValue::from_static("application/javascript"),
+                    );
+                }
+                "index.css" => {
+                    *res.body_mut() = Body::from(INDEX_CSS);
+                    res.headers_mut()
+                        .insert("content-type", HeaderValue::from_static("text/css"));
+                }
+                "favicon.ico" => {
+                    *res.body_mut() = Body::from(FAVICON_ICO);
+                    res.headers_mut()
+                        .insert("content-type", HeaderValue::from_static("image/x-icon"));
+                }
+                _ => {
+                    return Ok(false);
+                }
+            }
+            res.headers_mut().insert(
+                "cache-control",
+                HeaderValue::from_static("max-age=2592000, public"),
+            );
+            Ok(true)
         } else {
-            *res.body_mut() = Body::from(FAVICON_ICO);
-            res.headers_mut()
-                .insert("content-type", HeaderValue::from_static("image/x-icon"));
+            Ok(false)
         }
-        Ok(())
     }
 
     async fn handle_send_file(
@@ -701,17 +723,21 @@ impl Server {
             dir_exists: exist,
         };
         let data = serde_json::to_string(&data).unwrap();
+        let asset_js = format!("{}index.js", self.assets_prefix);
+        let asset_css = format!("{}index.css", self.assets_prefix);
+        let asset_ico = format!("{}favicon.ico", self.assets_prefix);
         let output = INDEX_HTML.replace(
             "__SLOT__",
             &format!(
                 r#"
-<style>{}</style>
+<link rel="icon" type="image/x-icon" href="{}">
+<link rel="stylesheet" href="{}">
 <script>
-const DATA = 
-{}
-{}</script>
+DATA = {}
+</script>
+<script src="{}"></script>
 "#,
-                INDEX_CSS, data, INDEX_JS
+                asset_ico, asset_css, data, asset_js
             ),
         );
         res.headers_mut()
diff --git a/tests/assets.rs b/tests/assets.rs
new file mode 100644 (file)
index 0000000..b5a1e95
--- /dev/null
@@ -0,0 +1,61 @@
+mod fixtures;
+mod utils;
+
+use fixtures::{server, Error, TestServer};
+use rstest::rstest;
+
+#[rstest]
+fn assets(server: TestServer) -> Result<(), Error> {
+    let ver = env!("CARGO_PKG_VERSION");
+    let resp = reqwest::blocking::get(server.url())?;
+    let index_js = format!("/__dufs_v{}_index.js", ver);
+    let index_css = format!("/__dufs_v{}_index.css", ver);
+    let favicon_ico = format!("/__dufs_v{}_favicon.ico", ver);
+    let text = resp.text()?;
+    assert!(text.contains(&format!(r#"href="{}""#, index_css)));
+    assert!(text.contains(&format!(r#"href="{}""#, favicon_ico)));
+    assert!(text.contains(&format!(r#"src="{}""#, index_js)));
+    Ok(())
+}
+
+#[rstest]
+fn asset_js(server: TestServer) -> Result<(), Error> {
+    let url = format!(
+        "{}__dufs_v{}_index.js",
+        server.url(),
+        env!("CARGO_PKG_VERSION")
+    );
+    let resp = reqwest::blocking::get(url)?;
+    assert_eq!(resp.status(), 200);
+    assert_eq!(
+        resp.headers().get("content-type").unwrap(),
+        "application/javascript"
+    );
+    Ok(())
+}
+
+#[rstest]
+fn asset_css(server: TestServer) -> Result<(), Error> {
+    let url = format!(
+        "{}__dufs_v{}_index.css",
+        server.url(),
+        env!("CARGO_PKG_VERSION")
+    );
+    let resp = reqwest::blocking::get(url)?;
+    assert_eq!(resp.status(), 200);
+    assert_eq!(resp.headers().get("content-type").unwrap(), "text/css");
+    Ok(())
+}
+
+#[rstest]
+fn asset_ico(server: TestServer) -> Result<(), Error> {
+    let url = format!(
+        "{}__dufs_v{}_favicon.ico",
+        server.url(),
+        env!("CARGO_PKG_VERSION")
+    );
+    let resp = reqwest::blocking::get(url)?;
+    assert_eq!(resp.status(), 200);
+    assert_eq!(resp.headers().get("content-type").unwrap(), "image/x-icon");
+    Ok(())
+}
diff --git a/tests/favicon.rs b/tests/favicon.rs
deleted file mode 100644 (file)
index 12feb47..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-mod fixtures;
-mod utils;
-
-use fixtures::{server, Error, TestServer};
-use rstest::rstest;
-
-#[rstest]
-fn default_favicon(server: TestServer) -> Result<(), Error> {
-    let resp = reqwest::blocking::get(format!("{}favicon.ico", server.url()))?;
-    assert_eq!(resp.status(), 200);
-    assert_eq!(resp.headers().get("content-type").unwrap(), "image/x-icon");
-    Ok(())
-}
-
-#[rstest]
-fn exist_favicon(#[with(&["-A"])] server: TestServer) -> Result<(), Error> {
-    let url = format!("{}favicon.ico", server.url());
-    let data = b"abc";
-    let resp = fetch!(b"PUT", &url).body(data.to_vec()).send()?;
-    assert_eq!(resp.status(), 201);
-    let resp = reqwest::blocking::get(url)?;
-    assert_eq!(resp.status(), 200);
-    assert_eq!(resp.bytes()?, data.to_vec());
-    Ok(())
-}
index a0f7eda5723da02e032f955065d2eacd42fc4795..d33a4731ce6fc0be8ecf9028535946210813ef96 100644 (file)
@@ -37,12 +37,8 @@ pub fn encode_uri(v: &str) -> String {
 
 fn retrive_index_paths_impl(index: &str) -> Option<HashSet<String>> {
     let lines: Vec<&str> = index.lines().collect();
-    let (i, _) = lines
-        .iter()
-        .enumerate()
-        .find(|(_, v)| v.contains("const DATA"))?;
-    let line = lines.get(i + 1)?;
-    let value: Value = line.parse().ok()?;
+    let line = lines.iter().find(|v| v.contains("DATA ="))?;
+    let value: Value = line[7..].parse().ok()?;
     let paths = value
         .get("paths")?
         .as_array()?