From 7dbde13c9c5fef7ebefce36877cf526a8f8b7607 Mon Sep 17 00:00:00 2001 From: "husni.zuhdi@accelbyte.net" Date: Sun, 18 Aug 2024 13:49:03 +0700 Subject: [PATCH 01/13] chore: bump version and fix main async function --- cmd/Cargo.toml | 5 +++-- cmd/src/main.rs | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/cmd/Cargo.toml b/cmd/Cargo.toml index 13613b2..c2171d6 100644 --- a/cmd/Cargo.toml +++ b/cmd/Cargo.toml @@ -1,10 +1,11 @@ [package] name = "cmd" -version = "0.1.2" +version = "0.1.3" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -internal = { path = "../internal", version = "0.1.2"} +internal = { path = "../internal", version = "0.1.3"} actix-web = "4.4.0" +tokio = { version = "1.0", features = ["full"] } diff --git a/cmd/src/main.rs b/cmd/src/main.rs index bedfc0b..3696605 100644 --- a/cmd/src/main.rs +++ b/cmd/src/main.rs @@ -1,7 +1,8 @@ use internal::{self, config::Config, handler::handler}; -#[actix_web::main] +#[tokio::main] async fn main() -> std::io::Result<()> { let config = Config::from_envar(); - handler(config).await + handler(config).await; + Ok(()) } From be80331c9dd92c1b1563725190c0180d5e2e5785 Mon Sep 17 00:00:00 2001 From: "husni.zuhdi@accelbyte.net" Date: Sun, 18 Aug 2024 13:50:34 +0700 Subject: [PATCH 02/13] feat: introduce axum --- internal/Cargo.toml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/internal/Cargo.toml b/internal/Cargo.toml index dda2483..962b6f3 100644 --- a/internal/Cargo.toml +++ b/internal/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "internal" -version = "0.1.2" +version = "0.1.3" edition = "2021" build = "build.rs" @@ -10,6 +10,14 @@ build = "build.rs" actix-web = "4.4.0" actix-web-lab = "0.20.0" actix-files = "0.6.5" +axum = "0.7.5" +tokio = { version = "1.0", features = ["full"] } +# Might not need this +tracing = "0.1" +# Might not need this +tracing-subscriber = { version = "0.3", features = ["env-filter"] } +tower = { version = "0.4", features = ["util"] } +tower-http = { version = "0.5.0", features = ["fs", "trace"] } askama = { version = "0.12.1"} env_logger = "0.10.1" log = "0.4.20" From c58888346347a4dd318f81df4810b812ca38122e Mon Sep 17 00:00:00 2001 From: "husni.zuhdi@accelbyte.net" Date: Sun, 18 Aug 2024 13:51:35 +0700 Subject: [PATCH 03/13] feat: change actix-web -> axum handlers --- internal/src/handler.rs | 58 +++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/internal/src/handler.rs b/internal/src/handler.rs index 347889d..60b520a 100644 --- a/internal/src/handler.rs +++ b/internal/src/handler.rs @@ -1,43 +1,49 @@ use crate::config::Config; use crate::model::data::BlogsData; use crate::router::*; -use actix_web::{middleware, web, App, HttpServer}; +use axum::{ + routing::{get, get_service}, + Router, +}; use log::info; +use tower_http::services::{ServeDir, ServeFile}; -pub async fn handler(cfg: Config) -> std::io::Result<()> { +pub async fn handler(cfg: Config) -> () { + // initialize tracing and logger + // tracing_subscriber::fmt::init(); env_logger::init_from_env(env_logger::Env::new().default_filter_or(cfg.log_level.clone())); let endpoint = cfg.svc_endpoint.as_str(); - let port = cfg - .svc_port - .parse::() - .expect("Failed to get port number"); + let port = cfg.svc_port.as_str(); + let running_endpoint = format!("{}:{}", endpoint, port); let config = cfg.clone(); + + // Build BlogsData let mut blogs_data = BlogsData::default(); if !config.gh_owner.is_empty() && !config.gh_repo.is_empty() && !config.gh_branch.is_empty() { blogs_data = BlogsData::with_gh(&config.gh_owner, &config.gh_repo, &config.gh_branch).await; } - info!( - "Starting HTTP Server at http://{}:{}", - cfg.svc_endpoint, cfg.svc_port - ); + info!("Starting HTTP Server at http://{}", running_endpoint); + + // Axum Application + let app = Router::new() + .route("/", get(get_profile)) + .route("/not-found", get(get_404_not_found)) + .nest_service("/statics", get_service(ServeDir::new("./statics/favicon/"))) + .nest_service( + "/statics/styles.css", + get_service(ServeFile::new("./statics/styles.css")), + ) + .fallback(get(get_404_not_found)); + // .route("/blogs", get(get_blogs)) + // .route("/blogs/:blog_id", get(get_blog)) + // .route("/version", get(get_version)) - HttpServer::new(move || { - App::new() - .wrap(middleware::Logger::default()) - .app_data(web::Data::new(blogs_data.clone())) - .app_data(web::Data::new(config.clone())) - .service(web::resource("/").route(web::get().to(profile))) - .service(web::resource("/statics/{static_file}").route(web::get().to(statics))) - .service(web::resource("/blogs").route(web::get().to(get_blogs))) - .service(web::resource("/blogs/{blogid}").route(web::get().to(get_blog))) - .service(web::resource("/version").route(web::get().to(get_version))) - .service(web::resource("/not-found").route(web::get().to(get_404_not_found))) - }) - .bind((endpoint, port)) - .expect("Failed to start Http Server") - .run() - .await + // Start Axum Application + let listener = tokio::net::TcpListener::bind(running_endpoint) + .await + .unwrap(); + axum::serve(listener, app).await.unwrap(); } From 344431a55a68ccefef9cd238005d5361a1ff2e47 Mon Sep 17 00:00:00 2001 From: "husni.zuhdi@accelbyte.net" Date: Wed, 21 Aug 2024 11:27:45 +0700 Subject: [PATCH 04/13] feat: wip move handler function to use axum --- internal/src/router.rs | 158 ++++++++++++++++++++--------------------- 1 file changed, 76 insertions(+), 82 deletions(-) diff --git a/internal/src/router.rs b/internal/src/router.rs index d9b53c3..0ce2243 100644 --- a/internal/src/router.rs +++ b/internal/src/router.rs @@ -3,94 +3,88 @@ use crate::model::{data::*, templates::*}; use crate::utils::read_version_manifest; use actix_files::NamedFile; use actix_web::{web, Responder, Result}; -use actix_web_lab::respond::Html; +// use actix_web_lab::respond::Html; use askama::Template; -use log::{error, info}; +use axum::extract::Path; +use axum::http::StatusCode; +use axum::response::{Html, IntoResponse}; +use log::{debug, error, info}; +use tower_http::services::ServeFile; -pub async fn statics(path: web::Path) -> Result { - info!("Statics path: {}", path.clone()); - let static_path = match path.into_inner().as_str() { - "styles.css" => Ok(format!("./statics/styles.css")), - "apple-touch-icon.png" => Ok(format!("./statics/favicon/apple-touch-icon.png")), - "favicon-16x16.png" => Ok(format!("./statics/favicon/favicon-16x16.png")), - "favicon-32x32.png" => Ok(format!("./statics/favicon/favicon-32x32.png")), - _ => { - let err = "Failed to get static path. Statics path is not allowed."; - error!("{}", err); - Err(err) - } - } - .expect("Failed to get static path"); - let static_file = NamedFile::open(static_path).expect("Failed to render static file(s)"); - Ok(static_file) -} +/// Note: In axum [example](https://docs.rs/axum/latest/axum/response/index.html#building-responses) +/// They show an example to return Html<&'static str> +/// Instaed of Html. But using static give me a headache :") -pub async fn profile() -> Result { +/// get_profile +/// Serve Profile/Biography HTML file +pub async fn get_profile() -> Html { let profile = Profile.render().expect("Failed to render profile.html"); - Ok(Html(profile)) + Html(profile) } -pub async fn get_404_not_found() -> Result { +// get_404_not_found +// Serve 404 Not found HTML file +pub async fn get_404_not_found() -> Html { let html = NotFound.render().expect("Failed to render not_found.html"); - Ok(Html(html)) + Html(html) } -pub async fn get_blogs(blogs_data: web::Data) -> Result { - // Copy data to Template struct - let blogs_template: Vec = blogs_data - .blogs - .iter() - .map(|blog| Blog { - id: &blog.id, - name: &blog.name, - filename: &blog.filename, - body: &blog.body, - }) - .collect(); - - let blogs = Blogs { - blogs: &blogs_template, - } - .render() - .expect("Failed to render blogs.html"); - info!("Blogs Template created"); - Ok(Html(blogs)) -} - -pub async fn get_blog( - path: web::Path, - blogs_data: web::Data, -) -> Result { - let blog_id = path.into_inner(); - let blog_data = blogs_data - .blogs - .iter() - .filter(|blog| blog.id == blog_id) - .next() - .expect("Failed to get blog name with id {blog_id}"); - - let blog = Blog { - id: &blog_id, - name: &blog_data.name, - filename: &blog_data.filename, - body: &blog_data.body, - } - .render() - .expect("Failed to render blog.html"); - Ok(Html(blog)) -} - -pub async fn get_version(config: web::Data) -> Result { - let version_json = read_version_manifest().expect("Failed to get version manifest"); - let version = Version { - version: version_json.version.as_str(), - environment: config.environment.as_str(), - build_hash: version_json.build_hash.as_str(), - build_date: version_json.build_date.as_str(), - } - .render() - .expect("Failed to render version.html"); - info!("Version Template created"); - - Ok(Html(version)) -} +// pub async fn get_blogs(blogs_data: web::Data) -> Result { +// // Copy data to Template struct +// let blogs_template: Vec = blogs_data +// .blogs +// .iter() +// .map(|blog| Blog { +// id: &blog.id, +// name: &blog.name, +// filename: &blog.filename, +// body: &blog.body, +// }) +// .collect(); +// +// let blogs = Blogs { +// blogs: &blogs_template, +// } +// .render() +// .expect("Failed to render blogs.html"); +// info!("Blogs Template created"); +// Ok(Html(blogs)) +// } +// +// pub async fn get_blog( +// path: web::Path, +// blogs_data: web::Data, +// ) -> Result { +// let blog_id = path.into_inner(); +// let blog_data = blogs_data +// .blogs +// .iter() +// .filter(|blog| blog.id == blog_id) +// .next() +// .expect("Failed to get blog name with id {blog_id}"); +// +// let blog = Blog { +// id: &blog_id, +// name: &blog_data.name, +// filename: &blog_data.filename, +// body: &blog_data.body, +// } +// .render() +// .expect("Failed to render blog.html"); +// Ok(Html(blog)) +// } +// +// pub async fn get_version(config: web::Data) -> Result { +// let version_json = read_version_manifest().expect("Failed to get version manifest"); +// let version = Version { +// version: version_json.version.as_str(), +// environment: config.environment.as_str(), +// build_hash: version_json.build_hash.as_str(), +// build_date: version_json.build_date.as_str(), +// } +// .render() +// .expect("Failed to render version.html"); +// info!("Version Template created"); +// +// Ok(Html(version)) +// } From 27b3b73c06943be580345f05f513062e31b19199 Mon Sep 17 00:00:00 2001 From: "husni.zuhdi@accelbyte.net" Date: Thu, 22 Aug 2024 14:28:36 +0700 Subject: [PATCH 05/13] feat: minimal axum migration --- internal/src/handler.rs | 16 ++--- internal/src/model/data.rs | 9 +++ internal/src/router.rs | 119 ++++++++++++++++++------------------- 3 files changed, 77 insertions(+), 67 deletions(-) diff --git a/internal/src/handler.rs b/internal/src/handler.rs index 60b520a..0d55df4 100644 --- a/internal/src/handler.rs +++ b/internal/src/handler.rs @@ -1,7 +1,8 @@ use crate::config::Config; -use crate::model::data::BlogsData; +use crate::model::data::{AppState, BlogsData}; use crate::router::*; use axum::{ + extract::State, routing::{get, get_service}, Router, }; @@ -9,7 +10,7 @@ use log::info; use tower_http::services::{ServeDir, ServeFile}; pub async fn handler(cfg: Config) -> () { - // initialize tracing and logger + // Initialize Tracing and Logger // tracing_subscriber::fmt::init(); env_logger::init_from_env(env_logger::Env::new().default_filter_or(cfg.log_level.clone())); @@ -17,13 +18,13 @@ pub async fn handler(cfg: Config) -> () { let port = cfg.svc_port.as_str(); let running_endpoint = format!("{}:{}", endpoint, port); + // Setup config and blogs_data states let config = cfg.clone(); - - // Build BlogsData let mut blogs_data = BlogsData::default(); if !config.gh_owner.is_empty() && !config.gh_repo.is_empty() && !config.gh_branch.is_empty() { blogs_data = BlogsData::with_gh(&config.gh_owner, &config.gh_repo, &config.gh_branch).await; } + let app_state = AppState { config, blogs_data }; info!("Starting HTTP Server at http://{}", running_endpoint); @@ -31,15 +32,16 @@ pub async fn handler(cfg: Config) -> () { let app = Router::new() .route("/", get(get_profile)) .route("/not-found", get(get_404_not_found)) + .route("/version", get(get_version)) + .route("/blogs", get(get_blogs)) + .route("/blogs/:blog_id", get(get_blog)) .nest_service("/statics", get_service(ServeDir::new("./statics/favicon/"))) .nest_service( "/statics/styles.css", get_service(ServeFile::new("./statics/styles.css")), ) + .with_state(app_state) .fallback(get(get_404_not_found)); - // .route("/blogs", get(get_blogs)) - // .route("/blogs/:blog_id", get(get_blog)) - // .route("/version", get(get_version)) // Start Axum Application let listener = tokio::net::TcpListener::bind(running_endpoint) diff --git a/internal/src/model/data.rs b/internal/src/model/data.rs index 60711c7..a21ac5f 100644 --- a/internal/src/model/data.rs +++ b/internal/src/model/data.rs @@ -1,4 +1,5 @@ use crate::api::github::get_gh_blog_data; +use crate::config::Config; use crate::utils::{capitalize, md_to_html}; use log::{debug, info}; use serde::{Deserialize, Serialize}; @@ -158,6 +159,14 @@ pub struct Tree { pub url: String, } +// Axum state +// Consist of Config and BlogsData +#[derive(Debug, Clone)] +pub struct AppState { + pub config: Config, + pub blogs_data: BlogsData, +} + #[cfg(test)] mod test { use super::*; diff --git a/internal/src/router.rs b/internal/src/router.rs index 0ce2243..2395fcd 100644 --- a/internal/src/router.rs +++ b/internal/src/router.rs @@ -5,7 +5,7 @@ use actix_files::NamedFile; use actix_web::{web, Responder, Result}; // use actix_web_lab::respond::Html; use askama::Template; -use axum::extract::Path; +use axum::extract::{Path, State}; use axum::http::StatusCode; use axum::response::{Html, IntoResponse}; use log::{debug, error, info}; @@ -29,62 +29,61 @@ pub async fn get_404_not_found() -> Html { Html(html) } -// pub async fn get_blogs(blogs_data: web::Data) -> Result { -// // Copy data to Template struct -// let blogs_template: Vec = blogs_data -// .blogs -// .iter() -// .map(|blog| Blog { -// id: &blog.id, -// name: &blog.name, -// filename: &blog.filename, -// body: &blog.body, -// }) -// .collect(); -// -// let blogs = Blogs { -// blogs: &blogs_template, -// } -// .render() -// .expect("Failed to render blogs.html"); -// info!("Blogs Template created"); -// Ok(Html(blogs)) -// } -// -// pub async fn get_blog( -// path: web::Path, -// blogs_data: web::Data, -// ) -> Result { -// let blog_id = path.into_inner(); -// let blog_data = blogs_data -// .blogs -// .iter() -// .filter(|blog| blog.id == blog_id) -// .next() -// .expect("Failed to get blog name with id {blog_id}"); -// -// let blog = Blog { -// id: &blog_id, -// name: &blog_data.name, -// filename: &blog_data.filename, -// body: &blog_data.body, -// } -// .render() -// .expect("Failed to render blog.html"); -// Ok(Html(blog)) -// } -// -// pub async fn get_version(config: web::Data) -> Result { -// let version_json = read_version_manifest().expect("Failed to get version manifest"); -// let version = Version { -// version: version_json.version.as_str(), -// environment: config.environment.as_str(), -// build_hash: version_json.build_hash.as_str(), -// build_date: version_json.build_date.as_str(), -// } -// .render() -// .expect("Failed to render version.html"); -// info!("Version Template created"); -// -// Ok(Html(version)) -// } +pub async fn get_blogs(State(app_state): State) -> Html { + // Copy data to Template struct + let blogs_template: Vec = app_state + .blogs_data + .blogs + .iter() + .map(|blog| Blog { + id: &blog.id, + name: &blog.name, + filename: &blog.filename, + body: &blog.body, + }) + .collect(); + + let blogs = Blogs { + blogs: &blogs_template, + } + .render() + .expect("Failed to render blogs.html"); + info!("Blogs Template created"); + Html(blogs) +} + +pub async fn get_blog(Path(path): Path, State(app_state): State) -> Html { + let blog_id = path; + let blog_data = app_state + .blogs_data + .blogs + .iter() + .filter(|blog| blog.id == blog_id) + .next() + .expect("Failed to get blog name with id {blog_id}"); + + let blog = Blog { + id: &blog_id, + name: &blog_data.name, + filename: &blog_data.filename, + body: &blog_data.body, + } + .render() + .expect("Failed to render blog.html"); + Html(blog) +} + +pub async fn get_version(State(app_state): State) -> Html { + let version_json = read_version_manifest().expect("Failed to get version manifest"); + let version = Version { + version: version_json.version.as_str(), + environment: app_state.config.environment.as_str(), + build_hash: version_json.build_hash.as_str(), + build_date: version_json.build_date.as_str(), + } + .render() + .expect("Failed to render version.html"); + info!("Version Template created"); + + Html(version) +} From de297e278f3b9fd8e519087bfd044e13e9881d6e Mon Sep 17 00:00:00 2001 From: "husni.zuhdi@accelbyte.net" Date: Thu, 22 Aug 2024 19:13:19 +0700 Subject: [PATCH 06/13] feat: add 500 internal server error and update 404 not found html files --- .../{not_found.html => 404_not_found.html} | 0 .../templates/500_internal_server_error.html | 22 +++++++++++++++++++ 2 files changed, 22 insertions(+) rename internal/templates/{not_found.html => 404_not_found.html} (100%) create mode 100644 internal/templates/500_internal_server_error.html diff --git a/internal/templates/not_found.html b/internal/templates/404_not_found.html similarity index 100% rename from internal/templates/not_found.html rename to internal/templates/404_not_found.html diff --git a/internal/templates/500_internal_server_error.html b/internal/templates/500_internal_server_error.html new file mode 100644 index 0000000..b5fa479 --- /dev/null +++ b/internal/templates/500_internal_server_error.html @@ -0,0 +1,22 @@ +{% extends "base.html" %} + +{% block title %}500 Internal Server Error{% endblock %} +{% block description %}"Sorry, there is an issue in our server. Please try again later."{% endblock %} + +{% block content %} + +
+
+

500

+

Internal Server Error

+

Sorry, there is an issue in our server. Please try again later.

+
+
+{% endblock content %} From 1d5a5dc1805469967d464e91171fa50f148f8318 Mon Sep 17 00:00:00 2001 From: "husni.zuhdi@accelbyte.net" Date: Thu, 22 Aug 2024 19:13:47 +0700 Subject: [PATCH 07/13] feat: bump rust version from 1.73 => 1.74 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index baf68ec..0144895 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.73-buster AS builder +FROM rust:1.74-buster AS builder COPY . . RUN cargo build --release From 70aab36af41424691e88dcf686d3ad5bbf86178c Mon Sep 17 00:00:00 2001 From: "husni.zuhdi@accelbyte.net" Date: Thu, 22 Aug 2024 19:14:47 +0700 Subject: [PATCH 08/13] feat: remove actix-web dependencies --- cmd/Cargo.toml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cmd/Cargo.toml b/cmd/Cargo.toml index c2171d6..8f25a94 100644 --- a/cmd/Cargo.toml +++ b/cmd/Cargo.toml @@ -1,11 +1,10 @@ [package] name = "cmd" -version = "0.1.3" +version = "0.1.4" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -internal = { path = "../internal", version = "0.1.3"} -actix-web = "4.4.0" +internal = { path = "../internal", version = "0.1.4"} tokio = { version = "1.0", features = ["full"] } From 53d393ebd53ad49b536dffc632eae9fd3a4827ee Mon Sep 17 00:00:00 2001 From: "husni.zuhdi@accelbyte.net" Date: Thu, 22 Aug 2024 19:15:22 +0700 Subject: [PATCH 09/13] feat: remove actix-web dependencies --- internal/Cargo.toml | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/internal/Cargo.toml b/internal/Cargo.toml index 962b6f3..d819b24 100644 --- a/internal/Cargo.toml +++ b/internal/Cargo.toml @@ -1,21 +1,16 @@ [package] name = "internal" -version = "0.1.3" +version = "0.1.4" edition = "2021" build = "build.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -actix-web = "4.4.0" -actix-web-lab = "0.20.0" -actix-files = "0.6.5" axum = "0.7.5" tokio = { version = "1.0", features = ["full"] } -# Might not need this -tracing = "0.1" -# Might not need this -tracing-subscriber = { version = "0.3", features = ["env-filter"] } +# tracing = "0.1" # Might not need this +# tracing-subscriber = { version = "0.3", features = ["env-filter"] } # Might not need this tower = { version = "0.4", features = ["util"] } tower-http = { version = "0.5.0", features = ["fs", "trace"] } askama = { version = "0.12.1"} @@ -31,5 +26,4 @@ regex = "1.10.6" [build-dependencies] anyhow = "1.0.86" -# Minimal vergen -vergen = { version = "8.0.0", features = ["build", "git", "gitcl"] } +vergen = { version = "8.0.0", features = ["build", "git", "gitcl"] } #Minimal Vergen From b46cb4cebeca8abcb3bf35cf6dfff543c51f1a28 Mon Sep 17 00:00:00 2001 From: "husni.zuhdi@accelbyte.net" Date: Thu, 22 Aug 2024 19:16:10 +0700 Subject: [PATCH 10/13] feat: migrate to axum --- internal/src/handler.rs | 15 ++--- internal/src/router.rs | 142 +++++++++++++++++++++++++++++----------- 2 files changed, 109 insertions(+), 48 deletions(-) diff --git a/internal/src/handler.rs b/internal/src/handler.rs index 0d55df4..40701a2 100644 --- a/internal/src/handler.rs +++ b/internal/src/handler.rs @@ -2,7 +2,6 @@ use crate::config::Config; use crate::model::data::{AppState, BlogsData}; use crate::router::*; use axum::{ - extract::State, routing::{get, get_service}, Router, }; @@ -10,14 +9,9 @@ use log::info; use tower_http::services::{ServeDir, ServeFile}; pub async fn handler(cfg: Config) -> () { - // Initialize Tracing and Logger - // tracing_subscriber::fmt::init(); + // Initialize Logger env_logger::init_from_env(env_logger::Env::new().default_filter_or(cfg.log_level.clone())); - let endpoint = cfg.svc_endpoint.as_str(); - let port = cfg.svc_port.as_str(); - let running_endpoint = format!("{}:{}", endpoint, port); - // Setup config and blogs_data states let config = cfg.clone(); let mut blogs_data = BlogsData::default(); @@ -26,7 +20,8 @@ pub async fn handler(cfg: Config) -> () { } let app_state = AppState { config, blogs_data }; - info!("Starting HTTP Server at http://{}", running_endpoint); + let endpoint = format!("{}:{}", cfg.svc_endpoint, cfg.svc_port); + info!("Starting HTTP Server at http://{}", endpoint); // Axum Application let app = Router::new() @@ -44,8 +39,6 @@ pub async fn handler(cfg: Config) -> () { .fallback(get(get_404_not_found)); // Start Axum Application - let listener = tokio::net::TcpListener::bind(running_endpoint) - .await - .unwrap(); + let listener = tokio::net::TcpListener::bind(endpoint).await.unwrap(); axum::serve(listener, app).await.unwrap(); } diff --git a/internal/src/router.rs b/internal/src/router.rs index 2395fcd..9bb16de 100644 --- a/internal/src/router.rs +++ b/internal/src/router.rs @@ -1,15 +1,9 @@ -use crate::config::Config; use crate::model::{data::*, templates::*}; use crate::utils::read_version_manifest; -use actix_files::NamedFile; -use actix_web::{web, Responder, Result}; -// use actix_web_lab::respond::Html; use askama::Template; use axum::extract::{Path, State}; -use axum::http::StatusCode; -use axum::response::{Html, IntoResponse}; -use log::{debug, error, info}; -use tower_http::services::ServeFile; +use axum::response::Html; +use log::{debug, error, info, warn}; /// Note: In axum [example](https://docs.rs/axum/latest/axum/response/index.html#building-responses) /// They show an example to return Html<&'static str> @@ -18,20 +12,25 @@ use tower_http::services::ServeFile; /// get_profile /// Serve Profile/Biography HTML file pub async fn get_profile() -> Html { - let profile = Profile.render().expect("Failed to render profile.html"); - Html(profile) -} - -// get_404_not_found -// Serve 404 Not found HTML file -pub async fn get_404_not_found() -> Html { - let html = NotFound.render().expect("Failed to render not_found.html"); - Html(html) + let profile = Profile.render(); + match profile { + Ok(res) => { + info!("Profile askama template rendered."); + Html(res) + } + Err(err) => { + error!("Failed to render profile.html. {}", err); + get_500_internal_server_error() + } + } } +/// get_blogs +/// Serve get_blogs HTML file +/// List our blogs title and id pub async fn get_blogs(State(app_state): State) -> Html { // Copy data to Template struct - let blogs_template: Vec = app_state + let blogs: Vec = app_state .blogs_data .blogs .iter() @@ -42,37 +41,67 @@ pub async fn get_blogs(State(app_state): State) -> Html { body: &blog.body, }) .collect(); + debug!("Blogs: {:?}", &blogs); - let blogs = Blogs { - blogs: &blogs_template, + let blogs_res = Blogs { blogs: &blogs }.render(); + match blogs_res { + Ok(res) => { + info!("Blogs askama template rendered."); + Html(res) + } + Err(err) => { + error!("Failed to render get_blogs.html. {}", err); + get_500_internal_server_error() + } } - .render() - .expect("Failed to render blogs.html"); - info!("Blogs Template created"); - Html(blogs) } +/// get_blog +/// Serve get_blog HTML file +/// Render our blog pub async fn get_blog(Path(path): Path, State(app_state): State) -> Html { - let blog_id = path; - let blog_data = app_state + let state = app_state .blogs_data .blogs .iter() - .filter(|blog| blog.id == blog_id) - .next() - .expect("Failed to get blog name with id {blog_id}"); + .filter(|blog| &blog.id == &path) + .next(); + debug!("BlogData: {:?}", &state); + match state { + Some(_) => {} + None => { + warn!( + "Failed to get blog with ID {}. Retunre 404 Not Found", + &path + ); + return get_404_not_found().await; + } + } + + let blog_data = state.unwrap(); let blog = Blog { - id: &blog_id, + id: path.clone().as_str(), name: &blog_data.name, filename: &blog_data.filename, body: &blog_data.body, } - .render() - .expect("Failed to render blog.html"); - Html(blog) + .render(); + + match blog { + Ok(res) => { + info!("Blog ID {} askama template rendered.", &path); + Html(res) + } + Err(err) => { + error!("Failed to render blog.html. {}", err); + get_500_internal_server_error() + } + } } +/// get_version +/// Serve get_version HTML file pub async fn get_version(State(app_state): State) -> Html { let version_json = read_version_manifest().expect("Failed to get version manifest"); let version = Version { @@ -81,9 +110,48 @@ pub async fn get_version(State(app_state): State) -> Html { build_hash: version_json.build_hash.as_str(), build_date: version_json.build_date.as_str(), } - .render() - .expect("Failed to render version.html"); - info!("Version Template created"); + .render(); - Html(version) + match version { + Ok(res) => { + info!("Version askama template rendered."); + Html(res) + } + Err(err) => { + error!("Failed to render version.html. {}", err); + get_500_internal_server_error() + } + } +} + +/// get_404_not_found +/// Serve 404 Not found HTML file +pub async fn get_404_not_found() -> Html { + let not_found = NotFound.render(); + match not_found { + Ok(res) => { + info!("NotFound askama template rendered."); + Html(res) + } + Err(err) => { + error!("Failed to render 404_not_found.html. {}", err); + get_500_internal_server_error() + } + } +} + +/// get_500_internal_server_error +/// Serve 500 Internal Server Error HTML file +fn get_500_internal_server_error() -> Html { + let internal_server_error = InternalServerError.render(); + match internal_server_error { + Ok(res) => { + info!("InternalServerError askama template rendered."); + Html(res) + } + Err(err) => { + error!("Failed to render 500_internal_server_error.html. {}", err); + Html("We're fucked up.".to_string()) + } + } } From 74d560942557a143de86e3f2ee58f27d7f3392a9 Mon Sep 17 00:00:00 2001 From: "husni.zuhdi@accelbyte.net" Date: Thu, 22 Aug 2024 19:16:34 +0700 Subject: [PATCH 11/13] feat: add InternalServerError html template --- internal/src/model/templates.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/internal/src/model/templates.rs b/internal/src/model/templates.rs index 545abef..e44d65a 100644 --- a/internal/src/model/templates.rs +++ b/internal/src/model/templates.rs @@ -29,5 +29,9 @@ pub struct Version<'a> { } #[derive(Template, Debug)] -#[template(path = "not_found.html")] +#[template(path = "404_not_found.html")] pub struct NotFound; + +#[derive(Template, Debug)] +#[template(path = "500_internal_server_error.html")] +pub struct InternalServerError; From a0fd36aa9b2816a0e73213ef67912e3eda33a047 Mon Sep 17 00:00:00 2001 From: "husni.zuhdi@accelbyte.net" Date: Thu, 22 Aug 2024 19:23:15 +0700 Subject: [PATCH 12/13] fix: fix versioning --- cmd/Cargo.toml | 4 ++-- internal/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/Cargo.toml b/cmd/Cargo.toml index 8f25a94..ac34576 100644 --- a/cmd/Cargo.toml +++ b/cmd/Cargo.toml @@ -1,10 +1,10 @@ [package] name = "cmd" -version = "0.1.4" +version = "0.1.3" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -internal = { path = "../internal", version = "0.1.4"} +internal = { path = "../internal", version = "0.1.3"} tokio = { version = "1.0", features = ["full"] } diff --git a/internal/Cargo.toml b/internal/Cargo.toml index d819b24..195a4a5 100644 --- a/internal/Cargo.toml +++ b/internal/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "internal" -version = "0.1.4" +version = "0.1.3" edition = "2021" build = "build.rs" From 6da32af06613278aed0cb6dc04c12d73a1519186 Mon Sep 17 00:00:00 2001 From: "husni.zuhdi@accelbyte.net" Date: Thu, 22 Aug 2024 19:23:48 +0700 Subject: [PATCH 13/13] chore: bump version --- version.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/version.json b/version.json index f0c2ec7..48065e0 100644 --- a/version.json +++ b/version.json @@ -1,5 +1,5 @@ { - "version": "0.1.2", - "build_date": "2024-08-17", - "build_hash": "de2b571e742340fce11890f5fe9084c19adb721d" + "version": "0.1.3", + "build_date": "2024-08-22", + "build_hash": "a0fd36aa9b2816a0e73213ef67912e3eda33a047" }