-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
242 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,30 @@ | ||
fn main() {} | ||
use std::sync::Arc; | ||
|
||
use flareon::prelude::{ | ||
Body, Error, FlareonApp, FlareonProject, Request, RequestHandler, Response, Route, StatusCode, | ||
}; | ||
|
||
fn return_hello(_request: Request) -> Result<Response, Error> { | ||
Ok(Response::new_html( | ||
StatusCode::OK, | ||
Body::fixed("<h1>Hello Flareon!</h1>".as_bytes().to_vec()), | ||
)) | ||
} | ||
|
||
#[tokio::main] | ||
async fn main() { | ||
let app = FlareonApp::builder() | ||
.urls([Route::new("/", Arc::new(Box::new(return_hello)))]) | ||
.build() | ||
.unwrap(); | ||
|
||
let flareon_project = FlareonProject::builder() | ||
.apps([app]) | ||
.urls([Route::new("/", Arc::new(Box::new(return_hello)))]) | ||
.build() | ||
.unwrap(); | ||
|
||
flareon::run(flareon_project, "127.0.0.1:8000") | ||
.await | ||
.unwrap(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,199 @@ | ||
pub fn add(left: u64, right: u64) -> u64 { | ||
left + right | ||
pub mod prelude; | ||
|
||
use std::fmt::{Debug, Formatter}; | ||
use std::io::Read; | ||
use std::rc::Rc; | ||
use std::sync::Arc; | ||
|
||
use async_trait::async_trait; | ||
use axum::handler::HandlerWithoutStateExt; | ||
use derive_builder::Builder; | ||
use indexmap::IndexMap; | ||
use thiserror::Error; | ||
|
||
pub type StatusCode = axum::http::StatusCode; | ||
|
||
#[async_trait] | ||
pub trait RequestHandler { | ||
async fn handle(&self, request: Request) -> Result<Response, Error>; | ||
} | ||
|
||
#[derive(Clone, Debug)] | ||
pub struct Router { | ||
urls: Vec<Route>, | ||
} | ||
|
||
impl Router { | ||
#[must_use] | ||
pub fn with_urls<T: Into<Vec<Route>>>(urls: T) -> Self { | ||
Self { urls: urls.into() } | ||
} | ||
} | ||
|
||
#[async_trait] | ||
impl RequestHandler for Router { | ||
async fn handle(&self, request: Request) -> Result<Response, Error> { | ||
let path = request.uri().path(); | ||
|
||
for route in &self.urls { | ||
if path.starts_with(&route.url) { | ||
return route.view.handle(request).await; | ||
} | ||
} | ||
|
||
unimplemented!("404 handler is not implemented yet") | ||
} | ||
} | ||
|
||
#[async_trait] | ||
impl<T> RequestHandler for T | ||
where | ||
T: Fn(Request) -> Result<Response, Error> + Send + Sync, | ||
{ | ||
async fn handle(&self, request: Request) -> Result<Response, Error> { | ||
self(request) | ||
} | ||
} | ||
|
||
#[derive(Clone, Debug, Builder)] | ||
#[builder(setter(into))] | ||
pub struct FlareonApp { | ||
router: Router, | ||
} | ||
|
||
impl FlareonApp { | ||
#[must_use] | ||
pub fn builder() -> FlareonAppBuilder { | ||
FlareonAppBuilder::default() | ||
} | ||
} | ||
|
||
impl FlareonAppBuilder { | ||
#[allow(unused_mut)] | ||
pub fn urls<T: Into<Vec<Route>>>(&mut self, urls: T) -> &mut Self { | ||
let mut new = self; | ||
new.router = Some(Router::with_urls(urls.into())); | ||
new | ||
} | ||
} | ||
|
||
#[derive(Clone)] | ||
pub struct Route { | ||
url: String, | ||
view: Arc<Box<dyn RequestHandler + Send + Sync>>, | ||
} | ||
|
||
impl Debug for Route { | ||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { | ||
todo!() | ||
} | ||
} | ||
|
||
impl Route { | ||
#[must_use] | ||
pub fn new<T: Into<String>>(url: T, view: Arc<Box<dyn RequestHandler + Send + Sync>>) -> Self { | ||
Self { | ||
url: url.into(), | ||
view, | ||
} | ||
} | ||
} | ||
|
||
pub type Request = axum::extract::Request; | ||
|
||
type HeadersMap = IndexMap<String, String>; | ||
|
||
#[derive(Debug)] | ||
pub struct Response { | ||
status: StatusCode, | ||
headers: HeadersMap, | ||
body: Body, | ||
} | ||
|
||
const CONTENT_TYPE_HEADER: &str = "Content-Type"; | ||
const HTML_CONTENT_TYPE: &str = "text/html"; | ||
|
||
impl Response { | ||
#[must_use] | ||
pub fn new_html(status: StatusCode, body: Body) -> Self { | ||
Self { | ||
status, | ||
headers: Self::html_headers(), | ||
body, | ||
} | ||
} | ||
|
||
#[must_use] | ||
fn html_headers() -> HeadersMap { | ||
let mut headers = HeadersMap::new(); | ||
headers.insert(CONTENT_TYPE_HEADER.to_owned(), HTML_CONTENT_TYPE.to_owned()); | ||
headers | ||
} | ||
} | ||
|
||
pub enum Body { | ||
NoContent, | ||
Fixed(Vec<u8>), | ||
Streaming(Box<dyn Read>), | ||
} | ||
|
||
impl Debug for Body { | ||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { | ||
todo!() | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
impl Body { | ||
#[must_use] | ||
pub fn empty() -> Self { | ||
Self::NoContent | ||
} | ||
|
||
#[must_use] | ||
pub fn fixed(data: Vec<u8>) -> Self { | ||
Self::Fixed(data) | ||
} | ||
|
||
// TODO streaming | ||
} | ||
|
||
#[derive(Debug, thiserror::Error)] | ||
pub enum Error {} | ||
|
||
#[derive(Clone, Debug, Builder)] | ||
#[builder(setter(into))] | ||
pub struct FlareonProject { | ||
apps: Vec<FlareonApp>, | ||
router: Router, | ||
} | ||
|
||
#[test] | ||
fn it_works() { | ||
let result = add(2, 2); | ||
assert_eq!(result, 4); | ||
impl FlareonProjectBuilder { | ||
#[allow(unused_mut)] | ||
pub fn urls<T: Into<Vec<Route>>>(&mut self, urls: T) -> &mut Self { | ||
let mut new = self; | ||
new.router = Some(Router::with_urls(urls.into())); | ||
new | ||
} | ||
} | ||
|
||
impl FlareonProject { | ||
#[must_use] | ||
pub fn builder() -> FlareonProjectBuilder { | ||
FlareonProjectBuilder::default() | ||
} | ||
} | ||
|
||
pub async fn run(project: FlareonProject, address_str: &str) -> Result<(), Error> { | ||
let listener = tokio::net::TcpListener::bind(address_str).await.unwrap(); | ||
|
||
let handler = |request: axum::extract::Request| async move { | ||
let _response = project.router.handle(request).await; | ||
|
||
"123" | ||
}; | ||
axum::serve(listener, handler.into_make_service()) | ||
.await | ||
.unwrap(); | ||
|
||
todo!() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
pub use crate::{ | ||
Body, Error, FlareonApp, FlareonProject, Request, RequestHandler, Response, Route, StatusCode, | ||
}; |