mirror of
https://github.com/sigoden/dufs
synced 2024-09-05 23:03:32 +00:00
refactor: split css/js from index.html (#68)
This commit is contained in:
parent
7f062b6705
commit
e29cf4c752
|
@ -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();
|
||||
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?;
|
||||
} else {
|
||||
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"));
|
||||
}
|
||||
Ok(())
|
||||
_ => {
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
res.headers_mut().insert(
|
||||
"cache-control",
|
||||
HeaderValue::from_static("max-age=2592000, public"),
|
||||
);
|
||||
Ok(true)
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
|
|
61
tests/assets.rs
Normal file
61
tests/assets.rs
Normal file
|
@ -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(())
|
||||
}
|
|
@ -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(())
|
||||
}
|
|
@ -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()?
|
||||
|
|
Loading…
Reference in a new issue