From 11c3ccbbe05f017ca1e6adc03c64594fa375421f Mon Sep 17 00:00:00 2001 From: hubertshelley Date: Sat, 6 May 2023 17:30:39 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E9=9D=99=E6=80=81?= =?UTF-8?q?=E8=B5=84=E6=BA=90=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + silent/src/handler/handler_wrapper_static.rs | 143 +++++++++++++++++++ silent/src/handler/mod.rs | 2 + silent/src/lib.rs | 8 +- 4 files changed, 151 insertions(+), 3 deletions(-) create mode 100644 silent/src/handler/handler_wrapper_static.rs diff --git a/.gitignore b/.gitignore index 91b8835..23ab2a3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target /Cargo.lock .idea/ +static/ diff --git a/silent/src/handler/handler_wrapper_static.rs b/silent/src/handler/handler_wrapper_static.rs new file mode 100644 index 0000000..b9eff01 --- /dev/null +++ b/silent/src/handler/handler_wrapper_static.rs @@ -0,0 +1,143 @@ +use crate::prelude::PathParam; +use crate::{Handler, Request, Response, SilentError, StatusCode}; +use async_trait::async_trait; + +struct HandlerWrapperStatic { + path: String, +} + +impl Default for HandlerWrapperStatic { + fn default() -> Self { + Self::new(".") + } +} + +impl HandlerWrapperStatic { + fn new(path: &str) -> Self { + let mut path = path; + if path.ends_with('/') { + path = &path[..path.len() - 1]; + } + if !std::path::Path::new(path).is_dir() { + panic!("Path not exists: {}", path); + } + Self { + path: path.to_string(), + } + } +} + +#[async_trait] +impl Handler for HandlerWrapperStatic { + async fn call(&self, req: Request) -> Result { + if let PathParam::Path(file_path) = req.get_path_params("path").unwrap() { + let mut path = format!("{}/{}", self.path, file_path); + if path.ends_with('/') { + path.push_str("index.html"); + } + if let Ok(contents) = tokio::fs::read(path).await { + return Ok(contents.into()); + } + }; + Err(SilentError::BusinessError { + code: StatusCode::NOT_FOUND, + msg: "Not Found".to_string(), + }) + } +} + +pub fn static_handler(path: &str) -> impl Handler { + HandlerWrapperStatic::new(path) +} + +#[cfg(test)] +mod tests { + use super::HandlerWrapperStatic; + use crate::prelude::*; + use crate::Handler; + use crate::Request; + use crate::SilentError; + use crate::StatusCode; + use bytes::Bytes; + use http_body_util::BodyExt; + + static CONTENT: &str = r#" + + + + Silent + + + +

我的第一个标题

+ +

我的第一个段落。

+ + +"#; + + fn create_static(path: &str) { + if !std::path::Path::new(path).is_dir() { + std::fs::create_dir(path).unwrap(); + std::fs::write(format!("./{}/index.html", path), CONTENT).unwrap(); + } + } + + fn clean_static(path: &str) { + if std::path::Path::new(path).is_dir() { + std::fs::remove_file(format!("./{}/index.html", path)).unwrap(); + std::fs::remove_dir(path).unwrap(); + } + } + + #[tokio::test] + async fn test_static() { + let path = "test_static"; + create_static(path); + let handler = HandlerWrapperStatic::new(path); + let mut req = Request::default(); + req.set_path_params("path".to_owned(), PathParam::Path("index.html".to_string())); + let mut res = handler.call(req).await.unwrap(); + clean_static(path); + assert_eq!(res.status(), StatusCode::OK); + assert_eq!( + res.frame().await.unwrap().unwrap().data_ref().unwrap(), + &Bytes::from(CONTENT) + ); + } + + #[tokio::test] + async fn test_static_default() { + let path = "test_static_default"; + create_static(path); + let handler = HandlerWrapperStatic::new(path); + let mut req = Request::default(); + req.set_path_params("path".to_owned(), PathParam::Path("".to_string())); + let mut res = handler.call(req).await.unwrap(); + clean_static(path); + assert_eq!(res.status(), StatusCode::OK); + assert_eq!( + res.frame().await.unwrap().unwrap().data_ref().unwrap(), + &Bytes::from(CONTENT) + ); + } + + #[tokio::test] + async fn test_static_not_found() { + let path = "test_static_not_found"; + create_static(path); + let handler = HandlerWrapperStatic::new(path); + let mut req = Request::default(); + req.set_path_params( + "path".to_owned(), + PathParam::Path("not_found.html".to_string()), + ); + let res = handler.call(req).await.unwrap_err(); + clean_static(path); + if let SilentError::BusinessError { code, .. } = res { + assert_eq!(code, StatusCode::NOT_FOUND); + } else { + panic!(); + } + } +} diff --git a/silent/src/handler/mod.rs b/silent/src/handler/mod.rs index 7a369c5..76bb56f 100644 --- a/silent/src/handler/mod.rs +++ b/silent/src/handler/mod.rs @@ -2,7 +2,9 @@ mod handler_trait; mod handler_wrapper; mod handler_wrapper_html; +mod handler_wrapper_static; pub use handler_trait::Handler; pub(crate) use handler_wrapper::HandlerWrapper; pub(crate) use handler_wrapper_html::HandlerWrapperHtml; +pub use handler_wrapper_static::static_handler; diff --git a/silent/src/lib.rs b/silent/src/lib.rs index 4e201c9..084fd76 100644 --- a/silent/src/lib.rs +++ b/silent/src/lib.rs @@ -16,11 +16,13 @@ pub(crate) use handler::HandlerWrapper; pub use hyper::{header, Method, StatusCode}; pub mod prelude { - pub use crate::core::{path_param::PathParam, request::Request, response::Response}; + pub use crate::core::{ + path_param::PathParam, request::Request, res_body::full, response::Response, + }; pub use crate::error::SilentError; - pub use crate::handler::Handler; + pub use crate::handler::{static_handler, Handler}; pub use crate::log::{logger, Level}; - pub use crate::route::handler_append::{HandlerAppend, HtmlHandlerAppend}; + pub use crate::route::handler_append::{HandlerAppend, HandlerGetter, HtmlHandlerAppend}; pub use crate::route::Route; pub use crate::service::Server; pub use hyper::{header, Method, StatusCode}; From 6de38b3eaf252cac1af03feeb18b63d0dbb9c1c2 Mon Sep 17 00:00:00 2001 From: hubertshelley Date: Sat, 6 May 2023 17:32:38 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E9=9D=99=E6=80=81?= =?UTF-8?q?=E8=B5=84=E6=BA=90=E5=A4=84=E7=90=86=E5=AE=9E=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/file_server/Cargo.toml | 11 +++++++++++ examples/file_server/src/main.rs | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 examples/file_server/Cargo.toml create mode 100644 examples/file_server/src/main.rs diff --git a/examples/file_server/Cargo.toml b/examples/file_server/Cargo.toml new file mode 100644 index 0000000..6e1a46f --- /dev/null +++ b/examples/file_server/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "file_server" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +silent = { path = "../../silent" } +async-trait = "0.1.68" +tokio = { version = "1", features = ["full"] } diff --git a/examples/file_server/src/main.rs b/examples/file_server/src/main.rs new file mode 100644 index 0000000..0c3c93c --- /dev/null +++ b/examples/file_server/src/main.rs @@ -0,0 +1,32 @@ +use silent::prelude::*; +use std::sync::Arc; + +fn main() { + logger::fmt().init(); + if !std::path::Path::new("static").is_dir() { + std::fs::create_dir("static").unwrap(); + std::fs::write( + "./static/index.html", + r#" + + + + Silent + + + +

我的第一个标题

+ +

我的第一个段落。

+ + +"#, + ) + .unwrap(); + } + let mut route = Route::new(""); + route + .get_handler_mut() + .insert(Method::GET, Arc::new(static_handler("static"))); + Server::new().bind_route(route).run(); +} From 6d20749fc4fcdd47cb4feff6b8fc7daf586b0eb6 Mon Sep 17 00:00:00 2001 From: hubertshelley Date: Sat, 6 May 2023 18:46:50 +0800 Subject: [PATCH 3/3] =?UTF-8?q?public=200.3.0=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E9=9D=99=E6=80=81=E6=96=87=E4=BB=B6=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- readme.md | 2 +- silent/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 49db905..26be2ca 100644 --- a/readme.md +++ b/readme.md @@ -8,7 +8,7 @@ Silent 是一个简单的基于Hyper的Web框架,它的目标是提供一个 - [x] 路由 - [ ] 中间件 -- [ ] 静态文件 +- [x] 静态文件 - [ ] 模板 - [ ] 数据库 - [x] 日志 (使用了tracing) diff --git a/silent/Cargo.toml b/silent/Cargo.toml index 3720622..55ad9b3 100644 --- a/silent/Cargo.toml +++ b/silent/Cargo.toml @@ -12,7 +12,7 @@ keywords = ["web", "web-framework"] license = "Apache-2.0" readme = "../readme.md" repository = "https://github.com/hubertshelley/silent" -version = "0.2.1" +version = "0.3.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies]