Checkpoint: Migration to axum

This commit is contained in:
Lennart
2025-06-08 14:10:12 +02:00
parent 790c657b08
commit 95889e3df1
60 changed files with 1476 additions and 2205 deletions

View File

@@ -1,97 +1,72 @@
use std::marker::PhantomData;
use actix_web::{
body::BoxBody,
dev::{
HttpServiceFactory, ResourceDef, Service, ServiceFactory, ServiceRequest, ServiceResponse,
},
http::{header, Method},
HttpResponse,
use axum::{
RequestExt,
body::Body,
extract::{Path, Request},
response::{IntoResponse, Response},
};
use futures_core::future::LocalBoxFuture;
use futures_core::future::BoxFuture;
use headers::{ContentType, ETag, HeaderMapExt};
use http::{Method, StatusCode};
use rust_embed::RustEmbed;
use std::{convert::Infallible, marker::PhantomData, str::FromStr};
use tower::Service;
#[derive(RustEmbed)]
#[derive(Clone, RustEmbed)]
#[folder = "public/assets"]
pub struct Assets;
#[derive(Clone)]
pub struct EmbedService<E>
where
E: 'static + RustEmbed,
{
_embed: PhantomData<E>,
prefix: String,
}
impl<E> EmbedService<E>
where
E: 'static + RustEmbed,
{
pub fn new(prefix: String) -> Self {
pub fn new() -> Self {
Self {
prefix,
_embed: PhantomData,
}
}
}
impl<E> HttpServiceFactory for EmbedService<E>
impl<E> Service<Request> for EmbedService<E>
where
E: 'static + RustEmbed,
{
fn register(self, config: &mut actix_web::dev::AppService) {
let resource_def = if config.is_root() {
ResourceDef::root_prefix(&self.prefix)
} else {
ResourceDef::prefix(&self.prefix)
};
config.register_service(resource_def, None, self, None);
type Response = Response;
type Error = Infallible;
type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;
#[inline]
fn poll_ready(
&mut self,
_cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Result<(), Self::Error>> {
Ok(()).into()
}
}
impl<E> ServiceFactory<ServiceRequest> for EmbedService<E>
where
E: 'static + RustEmbed,
{
type Response = ServiceResponse;
type Error = actix_web::Error;
type Config = ();
type Service = EmbedService<E>;
type InitError = ();
type Future = LocalBoxFuture<'static, Result<Self::Service, Self::InitError>>;
fn new_service(&self, _: ()) -> Self::Future {
let prefix = self.prefix.clone();
Box::pin(async move {
Ok(Self {
prefix,
_embed: PhantomData,
})
})
}
}
impl<E> Service<ServiceRequest> for EmbedService<E>
where
E: 'static + RustEmbed,
{
type Response = ServiceResponse<BoxBody>;
type Error = actix_web::Error;
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
actix_web::dev::always_ready!();
fn call(&self, req: ServiceRequest) -> Self::Future {
#[inline]
fn call(&mut self, mut req: Request) -> Self::Future {
Box::pin(async move {
if req.method() != Method::GET && req.method() != Method::HEAD {
return Ok(req.into_response(HttpResponse::MethodNotAllowed()));
return Ok(StatusCode::METHOD_NOT_ALLOWED.into_response());
}
let path = req.match_info().unprocessed().trim_start_matches('/');
let path: String = if let Ok(Path(path)) = req.extract_parts().await.unwrap() {
path
} else {
return Ok(StatusCode::NOT_FOUND.into_response());
};
match E::get(path) {
match E::get(&path) {
Some(file) => {
let data = file.data;
let hash = hex::encode(file.metadata.sha256_hash());
let etag = format!("\"{hash}\"");
let mime = mime_guess::from_path(path).first_or_octet_stream();
let body = if req.method() == Method::HEAD {
@@ -99,14 +74,13 @@ where
} else {
data
};
Ok(req.into_response(
HttpResponse::Ok()
.content_type(mime)
.insert_header((header::ETAG, hash))
.body(body),
))
let mut res = Response::builder().status(StatusCode::OK);
let hdrs = res.headers_mut().unwrap();
hdrs.typed_insert(ContentType::from(mime));
hdrs.typed_insert(ETag::from_str(&etag).unwrap());
Ok(res.body(Body::from(body)).unwrap())
}
None => Ok(req.into_response(HttpResponse::NotFound())),
None => Ok(StatusCode::NOT_FOUND.into_response()),
}
})
}