zero4rs 2.0.0

zero4rs is a powerful, pragmatic, and extremely fast web framework for Rust
Documentation
use actix_web::middleware::Condition;
use lazy_static::lazy_static;

use actix_web::http::Method;
use actix_web::web;
use actix_web::HttpRequest;
use actix_web::Route;
use actix_web::{web::ServiceConfig, Responder};

// use actix_web_lab::middleware::from_fn;
use actix_web::middleware::from_fn;

use crate::commons;

use crate::core::auth0::Authorized;
use crate::core::auth0::Protected;

use crate::core::cacheable::YourCache;
use crate::core::middlewares::request_id;

use crate::server::AppContext;

use crate::core::csrf::CsrfMiddleware;

lazy_static! {
    static ref CACHE_KEY: &'static str = "__URL_COUNT";
    static ref RS_CACHE_60S: YourCache::<usize> = YourCache::build(60, 5 * 1024 * 1024);
}

#[allow(deprecated)]
pub fn url_dispatch<F, Args>(
    cfg: &mut ServiceConfig,
    app_state: actix_web::web::Data<AppContext>,
    method: &str,
    protected: &Protected,
    path: &str,
    handler: F,
) where
    F: actix_web::Handler<Args>,
    Args: actix_web::FromRequest + 'static,
    F::Output: actix_web::Responder + 'static,
{
    let line = if !path.contains("forward:") {
        format!(
            "url-dispatch: {} {} > {}",
            &method.to_uppercase(),
            &path,
            get_function_name(&handler)
        )
    } else {
        format!(
            "url-upstream: {} {} > {}",
            &method.to_uppercase(),
            &path,
            get_function_name(&handler)
        )
    };

    if !crate::core::cacheable::exists60s(&line) {
        log::info!(
            "({}){}",
            format_args!("{:0>width$}", incr(), width = 3),
            line
        );
        crate::core::cacheable::put60s(&line, "");
    }

    if method == "*" || method == "Any" {
        cfg.service(
            web::resource(path)
                .wrap(from_fn(request_id))
                .route(actix_web::web::get().to(handler.clone()))
                .route(actix_web::web::post().to(handler.clone()))
                .route(actix_web::web::delete().to(handler.clone()))
                .route(actix_web::web::put().to(handler.clone()))
                .route(actix_web::web::patch().to(handler.clone())),
        );
    } else {
        let method = Method::from_bytes(method.to_uppercase().trim().as_bytes()).unwrap();

        cfg.service(
            web::resource(path)
                .wrap(from_fn(request_id))
                .wrap(Condition::new(path == "/login", CsrfMiddleware::new()))
                .wrap(Condition::new(path == "/signup", CsrfMiddleware::new()))
                .wrap(Authorized::builder(app_state, protected.to_owned()))
                .route(Route::new().method(method).to(handler))
                .default_service(web::route().to(crate::sitepages::default::e405)),
        );
    }
}

async fn favicon(_req: HttpRequest) -> std::io::Result<actix_files::NamedFile> {
    actix_files::NamedFile::open(format!(
        "{}/favicon.ico",
        commons::read_env("static", "./RichMedias")
    ))
}

async fn favicon_svg() -> impl Responder {
    actix_files::NamedFile::open_async(format!(
        "{}/favicon.svg",
        commons::read_env("static", "./RichMedias")
    ))
    .await
    .unwrap()
}

pub fn static_router(config: &mut ServiceConfig) {
    let fs = actix_files::Files::new("/RichMedias", commons::read_env("static", "./RichMedias"));

    // .wrap(from_fn(crate::middlewares::cache_control::cache_control))
    config.service(fs);
}

async fn beautifier_js(_req: HttpRequest) -> std::io::Result<actix_files::NamedFile> {
    actix_files::NamedFile::open(format!(
        "{}/beautifier.min.js",
        commons::read_env("static", "./RichMedias/js_beautify/js/lib")
    ))
}

pub fn beautifier_js_router(config: &mut ServiceConfig) {
    config
        .route(
            "/developer/js/lib/beautifier.min.js",
            web::get().to(beautifier_js),
        )
        .default_service(actix_web::web::route().to(crate::sitepages::default::e405));
}

pub fn favicon_router(config: &mut ServiceConfig) {
    config
        .route("/favicon.ico", web::get().to(favicon))
        .route("/favicon.svg", web::get().to(favicon_svg))
        .default_service(actix_web::web::route().to(crate::sitepages::default::e405));
}

fn incr() -> usize {
    match RS_CACHE_60S.get(*CACHE_KEY) {
        Some(val) => {
            RS_CACHE_60S.put(*CACHE_KEY, val + 1);
            val + 1
        }
        None => {
            RS_CACHE_60S.put(*CACHE_KEY, 1);
            1
        }
    }
}

// 取得函数名
fn get_function_name<F, Args>(_: &F) -> &'static str
where
    F: actix_web::Handler<Args>,
    Args: actix_web::FromRequest + 'static,
    F::Output: actix_web::Responder + 'static,
{
    std::any::type_name::<F>()
}