Skip to content

Commit

Permalink
Create logger service (#101)
Browse files Browse the repository at this point in the history
* feat: create logger service

* feat: opt out __tuono/data routes from logger

* feat: update version to v0.12.1
  • Loading branch information
Valerioageno authored Nov 16, 2024
1 parent f22249f commit c394898
Show file tree
Hide file tree
Showing 13 changed files with 133 additions and 43 deletions.
2 changes: 1 addition & 1 deletion crates/tuono/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "tuono"
version = "0.12.0"
version = "0.12.1"
edition = "2021"
authors = ["V. Ageno <[email protected]>"]
description = "The react/rust fullstack framework"
Expand Down
7 changes: 5 additions & 2 deletions crates/tuono_lib/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "tuono_lib"
version = "0.12.0"
version = "0.12.1"
edition = "2021"
authors = ["V. Ageno <[email protected]>"]
description = "The react/rust fullstack framework"
Expand Down Expand Up @@ -33,9 +33,12 @@ either = "1.13.0"
tower-http = {version = "0.6.0", features = ["fs"]}
colored = "2.1.0"

tuono_lib_macros = {path = "../tuono_lib_macros", version = "0.12.0"}
tuono_lib_macros = {path = "../tuono_lib_macros", version = "0.12.1"}
# Match the same version used by axum
tokio-tungstenite = "0.24.0"
futures-util = { version = "0.3", default-features = false, features = ["sink", "std"] }
tungstenite = "0.24.0"
http = "1.1.0"
pin-project = "1.1.7"
tower = "0.5.1"

15 changes: 0 additions & 15 deletions crates/tuono_lib/src/catch_all.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
use crate::{ssr::Js, Payload};
use axum::extract::{Path, Request};
use axum::response::Html;
use colored::*;
use std::collections::HashMap;
use tokio::time::Instant;

pub async fn catch_all(
Path(params): Path<HashMap<String, String>>,
request: Request,
) -> Html<String> {
let start = Instant::now();
let pathname = request.uri();
let headers = request.headers();

Expand All @@ -20,18 +17,6 @@ pub async fn catch_all(

let result = Js::render_to_string(Some(&payload));

let duration = start.elapsed();

// TODO: handle 404 error on catch_all route
let http_code = "200";

println!(
" GET {} {} in {}ms",
req.uri.path(),
http_code.green(),
duration.as_millis()
);

match result {
Ok(html) => Html(html),
_ => Html("500 internal server error".to_string()),
Expand Down
1 change: 1 addition & 0 deletions crates/tuono_lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod payload;
mod request;
mod response;
mod server;
mod services;
mod ssr;
mod vite_reverse_proxy;
mod vite_websocket_proxy;
Expand Down
18 changes: 2 additions & 16 deletions crates/tuono_lib/src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ use crate::{ssr::Js, Payload};
use axum::http::{HeaderMap, StatusCode};
use axum::response::{Html, IntoResponse, Redirect};
use axum::Json;
use colored::*;
use erased_serde::Serialize;
use tokio::time::Instant;

pub struct Props {
data: Box<dyn Serialize>,
Expand Down Expand Up @@ -74,25 +72,13 @@ impl Response {
pub fn render_to_string(&self, req: Request) -> impl IntoResponse {
match self {
Self::Props(Props { data, http_code }) => {
let start = Instant::now();
let payload = Payload::new(&req, data).client_payload().unwrap();

let response = match Js::render_to_string(Some(&payload)) {
match Js::render_to_string(Some(&payload)) {
Ok(html) => (*http_code, Html(html)),
Err(_) => (*http_code, Html("500 Internal server error".to_string())),
}
.into_response();

let duration = start.elapsed();

println!(
" GET {} {} in {}ms",
req.uri.path(),
http_code.as_str().green(),
duration.as_millis()
);

response
.into_response()
}
Self::Redirect(to) => Redirect::permanent(to).into_response(),
Self::Custom(response) => response.clone().into_response(),
Expand Down
16 changes: 12 additions & 4 deletions crates/tuono_lib/src/server.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::mode::{Mode, GLOBAL_MODE};

use crate::manifest::load_manifest;
use crate::mode::{Mode, GLOBAL_MODE};
use crate::services::logger::LoggerLayer;
use axum::routing::{get, Router};
use colored::Colorize;
use ssr_rs::Ssr;
Expand Down Expand Up @@ -42,9 +42,13 @@ impl Server {
let router = self
.router
.to_owned()
.layer(LoggerLayer::new())
.route("/vite-server/", get(vite_websocket_proxy))
.route("/vite-server/*path", get(vite_reverse_proxy))
.fallback_service(ServeDir::new(DEV_PUBLIC_DIR).fallback(get(catch_all)))
.fallback_service(
ServeDir::new(DEV_PUBLIC_DIR)
.fallback(get(catch_all).layer(LoggerLayer::new())),
)
.with_state(fetch);

axum::serve(listener, router)
Expand All @@ -58,7 +62,11 @@ impl Server {
let router = self
.router
.to_owned()
.fallback_service(ServeDir::new(PROD_PUBLIC_DIR).fallback(get(catch_all)))
.layer(LoggerLayer::new())
.fallback_service(
ServeDir::new(PROD_PUBLIC_DIR)
.fallback(get(catch_all).layer(LoggerLayer::new())),
)
.with_state(fetch);

axum::serve(listener, router)
Expand Down
1 change: 1 addition & 0 deletions crates/tuono_lib/src/services.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod logger;
106 changes: 106 additions & 0 deletions crates/tuono_lib/src/services/logger.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
use colored::Colorize;
use http::{method::Method, Request, Response};
use pin_project::pin_project;
use std::fmt::Debug;
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::time::Instant;
use tower::{Layer, Service};

#[derive(Clone)]
pub struct LoggerLayer {}

impl LoggerLayer {
pub fn new() -> Self {
LoggerLayer {}
}
}

impl<S> Layer<S> for LoggerLayer {
type Service = Logger<S>;

fn layer(&self, inner: S) -> Self::Service {
Logger::new(inner)
}
}

#[derive(Clone)]
pub struct Logger<S> {
inner: S,
}

impl<S> Logger<S> {
pub fn new(inner: S) -> Self {
Logger { inner }
}
}

impl<S, ReqBody, ResBody> Service<Request<ReqBody>> for Logger<S>
where
S: Service<Request<ReqBody>, Response = Response<ResBody>>,
ResBody: Default,
<S as Service<Request<ReqBody>>>::Error: Debug,
{
type Response = S::Response;
type Error = S::Error;
type Future = LoggerFuture<S::Future>;

fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.inner.poll_ready(cx)
}

fn call(&mut self, req: Request<ReqBody>) -> Self::Future {
let method = req.method().clone();
let path = req.uri().path().to_string();

LoggerFuture {
future: self.inner.call(req),
method,
path,
start: Instant::now(),
}
}
}

#[pin_project]
pub struct LoggerFuture<F> {
#[pin]
future: F,
method: Method,
path: String,
start: Instant,
}

impl<F, B, E> Future for LoggerFuture<F>
where
F: Future<Output = Result<Response<B>, E>>,
B: Default,
E: Debug,
{
type Output = Result<Response<B>, E>;

fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();
let res: F::Output = match this.future.poll(cx) {
Poll::Ready(res) => res,
Poll::Pending => return Poll::Pending,
};

if this.path.starts_with("/__tuono/data") {
return Poll::Ready(res);
}

let status_code = res.as_ref().unwrap().status();

println!(
" {} {} {} in {}ms",
this.method,
this.path,
status_code.as_str().green(),
this.start.elapsed().as_millis()
);

Poll::Ready(res)
}
}
2 changes: 1 addition & 1 deletion crates/tuono_lib_macros/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "tuono_lib_macros"
version = "0.12.0"
version = "0.12.1"
edition = "2021"
description = "The react/rust fullstack framework"
keywords = [ "react", "typescript", "fullstack", "web", "ssr"]
Expand Down
2 changes: 1 addition & 1 deletion packages/fs-router-vite-plugin/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tuono-fs-router-vite-plugin",
"version": "0.12.0",
"version": "0.12.1",
"description": "Plugin for the tuono's file system router. Tuono is the react/rust fullstack framework",
"scripts": {
"dev": "vite build --watch",
Expand Down
2 changes: 1 addition & 1 deletion packages/lazy-fn-vite-plugin/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tuono-lazy-fn-vite-plugin",
"version": "0.12.0",
"version": "0.12.1",
"description": "Plugin for the tuono's lazy fn. Tuono is the react/rust fullstack framework",
"scripts": {
"dev": "vite build --watch",
Expand Down
2 changes: 1 addition & 1 deletion packages/router/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tuono-router",
"version": "0.12.0",
"version": "0.12.1",
"description": "React routing component for the framework tuono. Tuono is the react/rust fullstack framework",
"scripts": {
"dev": "vite build --watch",
Expand Down
2 changes: 1 addition & 1 deletion packages/tuono/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tuono",
"version": "0.12.0",
"version": "0.12.1",
"description": "The react/rust fullstack framework",
"scripts": {
"dev": "vite build --watch",
Expand Down

0 comments on commit c394898

Please sign in to comment.