perf(neglible): completely veto Arc from AppState
This commit is contained in:
@@ -43,6 +43,8 @@ multiple_crate_versions = { level = "allow" } # otherwise there's too much
|
|||||||
|
|
||||||
correctness = { level = "deny", priority = -1 }
|
correctness = { level = "deny", priority = -1 }
|
||||||
nursery = { level = "deny", priority = -1 }
|
nursery = { level = "deny", priority = -1 }
|
||||||
|
option_if_let_else = { level = "allow" } # I personally sometimes prefer what this prevents
|
||||||
|
|
||||||
pedantic = { level = "deny", priority = -1 }
|
pedantic = { level = "deny", priority = -1 }
|
||||||
perf = { level = "deny", priority = -1 }
|
perf = { level = "deny", priority = -1 }
|
||||||
style = { level = "deny", priority = -1 }
|
style = { level = "deny", priority = -1 }
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use actix_web::{App, HttpServer, web};
|
|||||||
|
|
||||||
pub mod caches;
|
pub mod caches;
|
||||||
pub mod services;
|
pub mod services;
|
||||||
|
pub mod static_app_data;
|
||||||
|
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
pub args: crate::args::Args,
|
pub args: crate::args::Args,
|
||||||
@@ -11,6 +12,9 @@ pub struct AppState {
|
|||||||
pub cache: caches::AppCache<'static>,
|
pub cache: caches::AppCache<'static>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Type alias to be used just as `data: AppData,` extractor in [`actix_web`] request handlers.
|
||||||
|
pub type AppData = static_app_data::StaticAppDataExtractor<&'static AppState>;
|
||||||
|
|
||||||
/// Leaks memory for the sake of not atomic'ing all over.
|
/// Leaks memory for the sake of not atomic'ing all over.
|
||||||
#[expect(clippy::missing_errors_doc)]
|
#[expect(clippy::missing_errors_doc)]
|
||||||
pub async fn start_app(args: crate::args::Args, config: crate::conf::Config) -> io::Result<()> {
|
pub async fn start_app(args: crate::args::Args, config: crate::conf::Config) -> io::Result<()> {
|
||||||
@@ -18,10 +22,7 @@ pub async fn start_app(args: crate::args::Args, config: crate::conf::Config) ->
|
|||||||
|
|
||||||
let config = Box::leak(Box::new(config));
|
let config = Box::leak(Box::new(config));
|
||||||
|
|
||||||
let cache = caches::AppCache::new(
|
let cache = caches::AppCache::new(&config.unix.magic_paths, &config.unix.groups);
|
||||||
&config.unix.magic_paths,
|
|
||||||
&config.unix.groups,
|
|
||||||
);
|
|
||||||
|
|
||||||
let app: &AppState = Box::leak(Box::new(AppState {
|
let app: &AppState = Box::leak(Box::new(AppState {
|
||||||
args,
|
args,
|
||||||
@@ -36,7 +37,7 @@ pub async fn start_app(args: crate::args::Args, config: crate::conf::Config) ->
|
|||||||
|
|
||||||
HttpServer::new(move || {
|
HttpServer::new(move || {
|
||||||
App::new()
|
App::new()
|
||||||
.app_data(web::Data::new(app))
|
.app_data(app)
|
||||||
.service(services::images::make_scope(ws::IMAGES))
|
.service(services::images::make_scope(ws::IMAGES))
|
||||||
.default_service(web::to(services::not_found::not_found))
|
.default_service(web::to(services::not_found::not_found))
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ use actix_web::{
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
consts::{self, web_scopes as ws},
|
consts::{self, web_scopes as ws},
|
||||||
server,
|
server::{self, AppData},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@@ -27,7 +27,7 @@ pub fn make_scope(path: &str) -> actix_web::Scope {
|
|||||||
|
|
||||||
#[get("/")]
|
#[get("/")]
|
||||||
async fn get_default_image(
|
async fn get_default_image(
|
||||||
_data: web::Data<&server::AppState>,
|
data: AppData,
|
||||||
_username: web::Path<String>,
|
_username: web::Path<String>,
|
||||||
) -> HttpResponse {
|
) -> HttpResponse {
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok()
|
||||||
@@ -41,7 +41,7 @@ async fn get_default_image(
|
|||||||
|
|
||||||
#[get("/{username}")]
|
#[get("/{username}")]
|
||||||
async fn get_image(
|
async fn get_image(
|
||||||
data: web::Data<&server::AppState>,
|
data: AppData,
|
||||||
username: web::Path<String>,
|
username: web::Path<String>,
|
||||||
) -> web::Either<Redirect, HttpResponse> {
|
) -> web::Either<Redirect, HttpResponse> {
|
||||||
let cached_pfp = data.cache.get_pfp(username.to_string()).await;
|
let cached_pfp = data.cache.get_pfp(username.to_string()).await;
|
||||||
|
|||||||
38
src/server/static_app_data.rs
Normal file
38
src/server/static_app_data.rs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
use std::{future::Ready, ops::Deref};
|
||||||
|
|
||||||
|
use actix_web::{error::InternalError, http::StatusCode};
|
||||||
|
|
||||||
|
/// App data extractor without any [`Arc`] inbetween, perefct if the app data is a simple
|
||||||
|
/// `&'static` reference that can be copied, no atomic anywhere.
|
||||||
|
pub struct StaticAppDataExtractor<T> {
|
||||||
|
pub data: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Deref for StaticAppDataExtractor<T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Copy + 'static> actix_web::FromRequest for StaticAppDataExtractor<T> {
|
||||||
|
type Error = InternalError<&'static str>;
|
||||||
|
type Future = Ready<Result<Self, Self::Error>>;
|
||||||
|
|
||||||
|
fn from_request(
|
||||||
|
req: &actix_web::HttpRequest,
|
||||||
|
_payload: &mut actix_web::dev::Payload,
|
||||||
|
) -> Self::Future {
|
||||||
|
let val = match req.app_data::<T>() {
|
||||||
|
Some(&data) => Ok(Self { data }),
|
||||||
|
None => Err(InternalError::new(
|
||||||
|
"Requested application data is not configured correctly. \
|
||||||
|
View/enable debug logs for more details.",
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
)),
|
||||||
|
};
|
||||||
|
|
||||||
|
std::future::ready(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user