initial work on Actix middleware support

This commit is contained in:
Greg Johnston
2024-01-19 16:35:51 -05:00
parent 26d9d75cf2
commit 55ef106c50
7 changed files with 149 additions and 12 deletions

View File

@@ -118,9 +118,9 @@ pub fn Counters() -> impl IntoView {
// This is the typical pattern for a CRUD app
#[component]
pub fn Counter() -> impl IntoView {
let dec = create_action(|_: &()| adjust_server_count(-1, "decing".into()));
let inc = create_action(|_: &()| adjust_server_count(1, "incing".into()));
let clear = create_action(|_: &()| clear_server_count());
let dec = create_action(|_| adjust_server_count(-1, "decing".into()));
let inc = create_action(|_| adjust_server_count(1, "incing".into()));
let clear = create_action(|_| clear_server_count());
let counter = create_resource(
move || {
(
@@ -222,10 +222,9 @@ pub fn FormCounter() -> impl IntoView {
#[component]
pub fn MultiuserCounter() -> impl IntoView {
let dec =
create_action(|_: &()| adjust_server_count(-1, "dec dec goose".into()));
let inc =
create_action(|_: &()| adjust_server_count(1, "inc inc moose".into()));
let clear = create_action(|_: &()| clear_server_count());
create_action(|_| adjust_server_count(-1, "dec dec goose".into()));
let inc = create_action(|_| adjust_server_count(1, "inc inc moose".into()));
let clear = create_action(|_| clear_server_count());
#[cfg(not(feature = "ssr"))]
let multiplayer_value = {

View File

@@ -21,7 +21,7 @@ async fn main() {
// run our app with hyper
// `axum::Server` is a re-export of `hyper::Server`
logging::log!("listening on {}", addr);
leptos::logging::log!("listening on {}", addr);
let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
axum::serve(listener, app.into_make_service())
.await

View File

@@ -1,3 +1,5 @@
#[cfg(feature = "ssr")]
pub mod middleware;
pub mod todo;
#[cfg(feature = "hydrate")]

View File

@@ -0,0 +1,58 @@
use actix_web::{
dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform},
Error,
};
use std::{
future::{ready, Future, Ready},
pin::Pin,
};
pub struct LoggingLayer;
impl<S, B> Transform<S, ServiceRequest> for LoggingLayer
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Response = ServiceResponse<B>;
type Error = Error;
type InitError = ();
type Transform = LoggingService<S>;
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ready(Ok(LoggingService { service }))
}
}
pub struct LoggingService<S> {
service: S,
}
impl<S, B> Service<ServiceRequest> for LoggingService<S>
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Response = ServiceResponse<B>;
type Error = Error;
type Future =
Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;
forward_ready!(service);
fn call(&self, req: ServiceRequest) -> Self::Future {
println!("1. Middleware running before server fn.");
let fut = self.service.call(req);
Box::pin(async move {
let res = fut.await?;
println!("3. Middleware running after server fn.");
Ok(res)
})
}
}

View File

@@ -49,6 +49,7 @@ pub async fn get_todos() -> Result<Vec<Todo>, ServerFnError> {
}
#[server]
#[middleware(crate::middleware::LoggingLayer)]
pub async fn add_todo(title: String) -> Result<(), ServerFnError> {
use self::ssr::*;

View File

@@ -93,8 +93,8 @@ where
any(debug_assertions, feature = "ssr"),
tracing::instrument(level = "trace", skip_all,)
)]
pub fn dispatch(&self, input: impl Into<I>) {
self.0.with_value(|a| a.dispatch(input.into()))
pub fn dispatch(&self, input: I) {
self.0.with_value(|a| a.dispatch(input))
}
/// Create an [Action].

View File

@@ -2,7 +2,7 @@ use std::{future::Future, pin::Pin};
/// An abstraction over a middleware layer, which can be used to add additional
/// middleware layer to a [`Service`].
pub trait Layer<Req, Res>: Send + Sync + 'static {
pub trait Layer<Req, Res>: 'static {
/// Adds this layer to the inner service.
fn layer(&self, inner: BoxedService<Req, Res>) -> BoxedService<Req, Res>;
}
@@ -104,18 +104,53 @@ mod axum {
#[cfg(feature = "actix")]
mod actix {
use super::BoxedService;
use crate::{
request::actix::ActixRequest,
response::{actix::ActixResponse, Res},
ServerFnError,
};
use actix_web::{HttpRequest, HttpResponse};
use actix_web::{
dev::{Service, Transform},
HttpRequest, HttpResponse,
};
use std::{
fmt::{Debug, Display},
future::Future,
pin::Pin,
task::{Context, Poll},
};
impl<T> super::Layer<HttpRequest, HttpResponse> for T
where
T: Transform<BoxedService<HttpRequest, HttpResponse>, HttpRequest>
+ 'static, /* + Send
+ Sync
+ 'static,*/
{
fn layer(
&self,
inner: BoxedService<HttpRequest, HttpResponse>,
) -> BoxedService<HttpRequest, HttpResponse> {
todo!()
}
}
impl<T> super::Layer<ActixRequest, ActixResponse> for T
where
T: Transform<BoxedService<ActixRequest, ActixResponse>, HttpRequest>
//+ Send
//+ Sync
+ 'static,
{
fn layer(
&self,
inner: BoxedService<ActixRequest, ActixResponse>,
) -> BoxedService<ActixRequest, ActixResponse> {
todo!()
}
}
impl<S> super::Service<HttpRequest, HttpResponse> for S
where
S: actix_web::dev::Service<HttpRequest, Response = HttpResponse>,
@@ -157,4 +192,46 @@ mod actix {
})
}
}
impl<Req> Service<Req> for BoxedService<HttpRequest, HttpResponse> {
type Response = HttpResponse;
type Error = ServerFnError;
type Future = Pin<
Box<
dyn Future<Output = Result<Self::Response, Self::Error>> + Send,
>,
>;
fn poll_ready(
&self,
ctx: &mut Context<'_>,
) -> Poll<Result<(), Self::Error>> {
todo!()
}
fn call(&self, req: Req) -> Self::Future {
todo!()
}
}
impl<Req> Service<Req> for BoxedService<ActixRequest, ActixResponse> {
type Response = HttpResponse;
type Error = ServerFnError;
type Future = Pin<
Box<
dyn Future<Output = Result<Self::Response, Self::Error>> + Send,
>,
>;
fn poll_ready(
&self,
ctx: &mut Context<'_>,
) -> Poll<Result<(), Self::Error>> {
todo!()
}
fn call(&self, req: Req) -> Self::Future {
todo!()
}
}
}