refactor: split css/js from index.html (#68)
parent
7f062b6705
commit
e29cf4c752
|
@ -44,11 +44,16 @@ const BUF_SIZE: usize = 65536;
|
||||||
|
|
||||||
pub struct Server {
|
pub struct Server {
|
||||||
args: Arc<Args>,
|
args: Arc<Args>,
|
||||||
|
assets_prefix: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Server {
|
impl Server {
|
||||||
pub fn new(args: Arc<Args>) -> Self {
|
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(
|
pub async fn call(
|
||||||
|
@ -58,12 +63,15 @@ impl Server {
|
||||||
) -> Result<Response, hyper::Error> {
|
) -> Result<Response, hyper::Error> {
|
||||||
let method = req.method().clone();
|
let method = req.method().clone();
|
||||||
let uri = req.uri().clone();
|
let uri = req.uri().clone();
|
||||||
|
let assets_prefix = self.assets_prefix.clone();
|
||||||
let enable_cors = self.args.enable_cors;
|
let enable_cors = self.args.enable_cors;
|
||||||
|
|
||||||
let mut res = match self.handle(req).await {
|
let mut res = match self.handle(req).await {
|
||||||
Ok(res) => {
|
Ok(res) => {
|
||||||
let status = res.status().as_u16();
|
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
|
res
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
@ -89,8 +97,7 @@ impl Server {
|
||||||
let headers = req.headers();
|
let headers = req.headers();
|
||||||
let method = req.method().clone();
|
let method = req.method().clone();
|
||||||
|
|
||||||
if req_path == "/favicon.ico" && method == Method::GET {
|
if method == Method::GET && self.handle_embed_assets(req_path, &mut res).await? {
|
||||||
self.handle_send_favicon(headers, &mut res).await?;
|
|
||||||
return Ok(res);
|
return Ok(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -418,23 +425,38 @@ impl Server {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_send_favicon(
|
async fn handle_embed_assets(&self, req_path: &str, res: &mut Response) -> BoxResult<bool> {
|
||||||
&self,
|
if let Some(name) = req_path.strip_prefix(&self.assets_prefix) {
|
||||||
headers: &HeaderMap<HeaderValue>,
|
match name {
|
||||||
res: &mut Response,
|
"index.js" => {
|
||||||
) -> BoxResult<()> {
|
*res.body_mut() = Body::from(INDEX_JS);
|
||||||
let path = self.args.path.join("favicon.ico");
|
res.headers_mut().insert(
|
||||||
let meta = fs::metadata(&path).await.ok();
|
"content-type",
|
||||||
let is_file = meta.map(|v| v.is_file()).unwrap_or_default();
|
HeaderValue::from_static("application/javascript"),
|
||||||
if is_file {
|
);
|
||||||
self.handle_send_file(path.as_path(), headers, false, res)
|
}
|
||||||
.await?;
|
"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 {
|
} else {
|
||||||
*res.body_mut() = Body::from(FAVICON_ICO);
|
Ok(false)
|
||||||
res.headers_mut()
|
|
||||||
.insert("content-type", HeaderValue::from_static("image/x-icon"));
|
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_send_file(
|
async fn handle_send_file(
|
||||||
|
@ -701,17 +723,21 @@ impl Server {
|
||||||
dir_exists: exist,
|
dir_exists: exist,
|
||||||
};
|
};
|
||||||
let data = serde_json::to_string(&data).unwrap();
|
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(
|
let output = INDEX_HTML.replace(
|
||||||
"__SLOT__",
|
"__SLOT__",
|
||||||
&format!(
|
&format!(
|
||||||
r#"
|
r#"
|
||||||
<style>{}</style>
|
<link rel="icon" type="image/x-icon" href="{}">
|
||||||
|
<link rel="stylesheet" href="{}">
|
||||||
<script>
|
<script>
|
||||||
const DATA =
|
DATA = {}
|
||||||
{}
|
</script>
|
||||||
{}</script>
|
<script src="{}"></script>
|
||||||
"#,
|
"#,
|
||||||
INDEX_CSS, data, INDEX_JS
|
asset_ico, asset_css, data, asset_js
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
res.headers_mut()
|
res.headers_mut()
|
||||||
|
|
|
@ -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>> {
|
fn retrive_index_paths_impl(index: &str) -> Option<HashSet<String>> {
|
||||||
let lines: Vec<&str> = index.lines().collect();
|
let lines: Vec<&str> = index.lines().collect();
|
||||||
let (i, _) = lines
|
let line = lines.iter().find(|v| v.contains("DATA ="))?;
|
||||||
.iter()
|
let value: Value = line[7..].parse().ok()?;
|
||||||
.enumerate()
|
|
||||||
.find(|(_, v)| v.contains("const DATA"))?;
|
|
||||||
let line = lines.get(i + 1)?;
|
|
||||||
let value: Value = line.parse().ok()?;
|
|
||||||
let paths = value
|
let paths = value
|
||||||
.get("paths")?
|
.get("paths")?
|
||||||
.as_array()?
|
.as_array()?
|
||||||
|
|
Loading…
Reference in New Issue