diff --git a/src/server/mod.rs b/src/server/mod.rs index a0a2255..071b840 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -1,4 +1,8 @@ +/// Routes +pub mod route; /// Services pub mod service; /// Traits pub mod traits; +/// Version +pub mod version; diff --git a/src/server/route.rs b/src/server/route.rs new file mode 100644 index 0000000..05dd1fc --- /dev/null +++ b/src/server/route.rs @@ -0,0 +1,29 @@ +use super::traits::MatchRoute; +use super::traits::ResponseFor; +use super::version::VersionRoute; +use hyper::Body; +use hyper::Request; + +pub type RouteType = dyn MatchRoute + Send + Sync; +pub type ResponseForType = dyn ResponseFor + Send + Sync; + +pub struct ServerRoutes { + routes: Vec>, +} + +impl ServerRoutes { + pub fn new() -> Self { + let mut routes: Vec> = Vec::new(); + routes.push(Box::new(VersionRoute::new())); + Self { routes } + } + + pub fn match_route(&self, req: &Request) -> Option> { + for i in self.routes.iter() { + if i.match_route(req) { + return Some(i.get_route()); + } + } + None + } +} diff --git a/src/server/service.rs b/src/server/service.rs index ed5b86c..09362b3 100644 --- a/src/server/service.rs +++ b/src/server/service.rs @@ -1,3 +1,4 @@ +use super::route::ServerRoutes; use hyper::server::conn::AddrIncoming; use hyper::server::Server; use hyper::service::Service; @@ -7,16 +8,17 @@ use hyper::Response; use std::future::Future; use std::net::SocketAddr; use std::pin::Pin; +use std::sync::Arc; use std::task::Context; use std::task::Poll; pub struct PixivDownloaderSvc { - _unused: [u8; 0], + routes: Arc, } impl PixivDownloaderSvc { - pub fn new() -> Self { - Self { _unused: [] } + pub fn new(routes: Arc) -> Self { + Self { routes } } } @@ -30,17 +32,35 @@ impl Service> for PixivDownloaderSvc { } fn call(&mut self, req: Request) -> Self::Future { - Box::pin(async { Ok(Response::builder().body(Body::from("hello world")).unwrap()) }) + match self.routes.match_route(&req) { + Some(route) => Box::pin(async move { + match route.response(req) { + Ok(data) => Ok(data), + Err(e) => { + println!("{}", e); + Ok(Response::builder() + .status(500) + .body(Body::from("Internal server error")) + .unwrap()) + } + } + }), + None => { + Box::pin(async { Ok(Response::builder().body(Body::from("hello world")).unwrap()) }) + } + } } } pub struct PixivDownloaderMakeSvc { - _unused: [u8; 0], + routes: Arc, } impl PixivDownloaderMakeSvc { pub fn new() -> Self { - Self { _unused: [] } + Self { + routes: Arc::new(ServerRoutes::new()), + } } } @@ -54,7 +74,8 @@ impl Service for PixivDownloaderMakeSvc { } fn call(&mut self, _: T) -> Self::Future { - let fut = async move { Ok(PixivDownloaderSvc::new()) }; + let routes = Arc::clone(&self.routes); + let fut = async move { Ok(PixivDownloaderSvc::new(routes)) }; Box::pin(fut) } } diff --git a/src/server/traits.rs b/src/server/traits.rs index 734d2c9..e5d368d 100644 --- a/src/server/traits.rs +++ b/src/server/traits.rs @@ -4,20 +4,25 @@ use hyper::Request; use hyper::Response; use json::JsonValue; +pub trait MatchRoute { + fn get_route(&self) -> Box + Send + Sync>; + fn match_route(&self, req: &Request) -> bool; +} + pub trait ResponseFor { - fn response(&self, res: Request) -> Result, PixivDownloaderError>; + fn response(&self, req: Request) -> Result, PixivDownloaderError>; } pub trait ResponseJsonFor { - fn response_json(&self, res: Request) -> Result; + fn response_json(&self, req: Request) -> Result; } -impl ResponseFor for T +impl ResponseFor for U where - T: ResponseJsonFor, + U: ResponseJsonFor, { - fn response(&self, res: Request) -> Result, PixivDownloaderError> { - let re = self.response_json(res)?; + fn response(&self, req: Request) -> Result, PixivDownloaderError> { + let re = self.response_json(req)?; Ok(Response::new(Body::from(re.to_string()))) } } diff --git a/src/server/version.rs b/src/server/version.rs new file mode 100644 index 0000000..9422c4f --- /dev/null +++ b/src/server/version.rs @@ -0,0 +1,46 @@ +use super::route::ResponseForType; +use super::traits::MatchRoute; +use super::traits::ResponseJsonFor; +use crate::error::PixivDownloaderError; +use hyper::Body; +use hyper::Request; +use json::JsonValue; +use regex::Regex; + +pub struct VersionContext { + _unused: [u8; 0], +} + +impl VersionContext { + pub fn new() -> Self { + Self { _unused: [] } + } +} + +impl ResponseJsonFor for VersionContext { + fn response_json(&self, _req: Request) -> Result { + Ok(json::object! {"version": [0, 0, 1, 0]}) + } +} + +pub struct VersionRoute { + regex: Regex, +} + +impl VersionRoute { + pub fn new() -> Self { + Self { + regex: Regex::new(r"^(/api)?/version(/.*)?$").unwrap(), + } + } +} + +impl MatchRoute for VersionRoute { + fn get_route(&self) -> Box { + Box::new(VersionContext::new()) + } + + fn match_route(&self, req: &http::Request) -> bool { + self.regex.is_match(req.uri().path()) + } +}