diff --git a/Cargo.toml b/Cargo.toml index e3ee4d6..71cb425 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,9 +19,12 @@ async-trait = "0.1.80" axum = "0.7.5" chrono = { version = "0.4.38", features = ["serde"] } clap = { version = "4.5.8", features = ["derive", "env"] } +derive_builder = "0.20.0" env_logger = "0.11.3" +indexmap = "2.2.6" itertools = "0.13.0" log = "0.4.22" +regex = "1.10.5" serde = "1.0.203" slug = "0.1.5" tokio = { version = "1.38.0", features = ["macros", "rt-multi-thread"] } diff --git a/examples/hello-world/Cargo.toml b/examples/hello-world/Cargo.toml index 1203b9a..05cdc2e 100644 --- a/examples/hello-world/Cargo.toml +++ b/examples/hello-world/Cargo.toml @@ -3,6 +3,8 @@ name = "example-hello-world" version = "0.1.0" publish = false description = "Hello World - Flareon example." +edition = "2021" [dependencies] flareon = { path = "../../flareon" } +tokio = { version = "1.38.0", features = ["macros", "rt-multi-thread"] } diff --git a/examples/hello-world/src/main.rs b/examples/hello-world/src/main.rs index f328e4d..e93476c 100644 --- a/examples/hello-world/src/main.rs +++ b/examples/hello-world/src/main.rs @@ -1 +1,27 @@ -fn main() {} +use std::sync::Arc; + +use flareon::prelude::{ + Body, Error, FlareonApp, FlareonProject, Request, Response, Route, StatusCode, +}; +use flareon::View; + +fn return_hello(_app: &FlareonApp, _request: &Request) -> Result { + Ok(Response::new_html( + StatusCode::OK, + Body::fixed("

Hello Flareon!

".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]).build().unwrap(); + + flareon::run(flareon_project, "127.0.0.1:8000") + .await + .unwrap(); +} diff --git a/flareon/Cargo.toml b/flareon/Cargo.toml index e20a072..64b8602 100644 --- a/flareon/Cargo.toml +++ b/flareon/Cargo.toml @@ -6,6 +6,10 @@ license.workspace = true description = "Modern web framework focused on speed and ease of use." [dependencies] +async-trait.workspace = true axum.workspace = true +derive_builder.workspace = true +indexmap.workspace = true +regex.workspace = true tokio.workspace = true tower.workspace = true diff --git a/flareon/src/lib.rs b/flareon/src/lib.rs index b93cf3f..d54308a 100644 --- a/flareon/src/lib.rs +++ b/flareon/src/lib.rs @@ -1,14 +1,141 @@ -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 derive_builder::Builder; +use indexmap::IndexMap; + +pub type StatusCode = axum::http::StatusCode; + +#[async_trait] +pub trait View { + async fn get_response(&self, app: &FlareonApp, request: &Request) -> Result; +} + +#[async_trait] +impl View for T +where + T: Fn(&FlareonApp, &Request) -> Result + Send + Sync, +{ + async fn get_response(&self, app: &FlareonApp, request: &Request) -> Result { + todo!() + } } -#[cfg(test)] -mod tests { - use super::*; +#[derive(Clone, Debug, Builder)] +#[builder(setter(into))] +pub struct FlareonApp { + urls: Vec, +} - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); +impl FlareonApp { + #[must_use] + pub fn builder() -> FlareonAppBuilder { + FlareonAppBuilder::default() } } + +#[derive(Clone)] +pub struct Route { + url: String, + view: Arc>, +} + +impl Debug for Route { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + todo!() + } +} + +impl Route { + #[must_use] + pub fn new>(url: T, view: Arc>) -> Self { + Self { + url: url.into(), + view, + } + } +} + +#[derive(Debug)] +pub struct Request {} + +type HeadersMap = IndexMap; + +#[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), + Streaming(Box), +} + +impl Debug for Body { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + todo!() + } +} + +impl Body { + #[must_use] + pub fn empty() -> Self { + Self::NoContent + } + + #[must_use] + pub fn fixed(data: Vec) -> Self { + Self::Fixed(data) + } + + // TODO streaming +} + +#[derive(Debug)] +pub struct Error {} + +#[derive(Clone, Default, Debug, Builder)] +#[builder(setter(into))] +pub struct FlareonProject { + apps: Vec, +} + +impl FlareonProject { + #[must_use] + pub fn builder() -> FlareonProjectBuilder { + FlareonProjectBuilder::default() + } +} + +pub async fn run(project: FlareonProject, address_str: &str) -> Result<(), Error> { + todo!() +} diff --git a/flareon/src/prelude.rs b/flareon/src/prelude.rs new file mode 100644 index 0000000..4a21cf7 --- /dev/null +++ b/flareon/src/prelude.rs @@ -0,0 +1 @@ +pub use crate::{Body, Error, FlareonApp, FlareonProject, Request, Response, Route, StatusCode};