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,16 +1,14 @@
use actix_web::body::MessageBody;
use actix_web::dev::{ServiceFactory, ServiceRequest, ServiceResponse};
use actix_web::middleware::NormalizePath;
use actix_web::{App, web};
use rustical_caldav::caldav_service;
use rustical_carddav::carddav_service;
use rustical_frontend::nextcloud_login::{NextcloudFlows, configure_nextcloud_login};
use rustical_frontend::{FrontendConfig, configure_frontend};
use axum::Router;
use axum::response::Redirect;
use axum::routing::get;
use rustical_caldav::caldav_router;
use rustical_carddav::carddav_router;
use rustical_frontend::nextcloud_login::NextcloudFlows;
use rustical_frontend::{FrontendConfig, frontend_router};
use rustical_oidc::OidcConfig;
use rustical_store::auth::AuthenticationProvider;
use rustical_store::{AddressbookStore, CalendarStore, SubscriptionStore};
use std::sync::Arc;
use tracing_actix_web::TracingLogger;
use crate::config::NextcloudLoginConfig;
@@ -24,61 +22,61 @@ pub fn make_app<AS: AddressbookStore, CS: CalendarStore, S: SubscriptionStore>(
oidc_config: Option<OidcConfig>,
nextcloud_login_config: NextcloudLoginConfig,
nextcloud_flows_state: Arc<NextcloudFlows>,
) -> App<
impl ServiceFactory<
ServiceRequest,
Response = ServiceResponse<impl MessageBody>,
Config = (),
InitError = (),
Error = actix_web::Error,
>,
> {
let mut app = App::new()
// .wrap(Logger::new("[%s] %r"))
.wrap(TracingLogger::default())
.wrap(NormalizePath::trim())
.service(web::scope("/caldav").service(caldav_service(
) -> Router {
let mut router = Router::new()
.nest(
"/caldav",
auth_provider.clone(),
cal_store.clone(),
addr_store.clone(),
subscription_store.clone(),
)))
.service(web::scope("/carddav").service(carddav_service(
caldav_router(
"/caldav",
auth_provider.clone(),
cal_store.clone(),
addr_store.clone(),
subscription_store.clone(),
),
)
.nest(
"/carddav",
auth_provider.clone(),
addr_store.clone(),
subscription_store,
)))
.service(
web::scope("/.well-known")
.service(web::redirect("/caldav", "/caldav"))
.service(web::redirect("/carddav", "/carddav")),
carddav_router(
"/carddav",
auth_provider.clone(),
addr_store.clone(),
subscription_store.clone(),
),
)
.route(
"/.well-known/caldav",
get(async || Redirect::permanent("/caldav")),
)
.route(
"/.well-known/carddav",
get(async || Redirect::permanent("/caldav")),
);
if nextcloud_login_config.enabled {
app = app.configure(|cfg| {
configure_nextcloud_login(
cfg,
nextcloud_flows_state,
auth_provider.clone(),
frontend_config.secret_key,
)
});
}
if frontend_config.enabled {
app = app
.service(web::scope("/frontend").configure(|cfg| {
configure_frontend(
cfg,
router = router
.nest(
"/frontend",
frontend_router(
auth_provider.clone(),
cal_store.clone(),
addr_store.clone(),
frontend_config,
oidc_config,
)
}))
.service(web::redirect("/", "/frontend").see_other());
),
)
.route("/", get(async || Redirect::to("/frontend")));
}
app
router
// if nextcloud_login_config.enabled {
// app = app.configure(|cfg| {
// configure_nextcloud_login(
// cfg,
// nextcloud_flows_state,
// auth_provider.clone(),
// frontend_config.secret_key,
// )
// });
// }
}

View File

@@ -1,6 +1,4 @@
use crate::config::Config;
use actix_web::HttpServer;
use actix_web::http::KeepAlive;
use anyhow::Result;
use app::make_app;
use clap::{Parser, Subcommand};
@@ -105,67 +103,24 @@ async fn main() -> Result<()> {
let nextcloud_flows = Arc::new(NextcloudFlows::default());
HttpServer::new(move || {
make_app(
addr_store.clone(),
cal_store.clone(),
subscription_store.clone(),
principal_store.clone(),
config.frontend.clone(),
config.oidc.clone(),
config.nextcloud_login.clone(),
nextcloud_flows.clone(),
)
})
.bind((config.http.host, config.http.port))?
// Workaround for a weird bug where
// new requests might timeout since they cannot properly reuse the connection
// https://github.com/lennart-k/rustical/issues/10
.keep_alive(KeepAlive::Disabled)
.run()
let app = make_app(
addr_store.clone(),
cal_store.clone(),
subscription_store.clone(),
principal_store.clone(),
config.frontend.clone(),
config.oidc.clone(),
config.nextcloud_login.clone(),
nextcloud_flows.clone(),
);
let listener = tokio::net::TcpListener::bind(&format!(
"{}:{}",
config.http.host, config.http.port
))
.await?;
axum::serve(listener, app).await?;
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use crate::{app::make_app, config::NextcloudLoginConfig, get_data_stores};
use actix_web::{http::StatusCode, test::TestRequest};
use rustical_frontend::nextcloud_login::NextcloudFlows;
use rustical_frontend::{FrontendConfig, generate_frontend_secret};
use std::sync::Arc;
#[tokio::test]
async fn test_main() {
let (addr_store, cal_store, subscription_store, principal_store, _update_recv) =
get_data_stores(
true,
&crate::config::DataStoreConfig::Sqlite(crate::config::SqliteDataStoreConfig {
db_url: "".to_owned(),
}),
)
.await
.unwrap();
let app = make_app(
addr_store,
cal_store,
subscription_store,
principal_store,
FrontendConfig {
enabled: false,
secret_key: generate_frontend_secret(),
allow_password_login: false,
},
None,
NextcloudLoginConfig { enabled: false },
Arc::new(NextcloudFlows::default()),
);
let app = actix_web::test::init_service(app).await;
let req = TestRequest::get().uri("/").to_request();
let resp = actix_web::test::call_service(&app, req).await;
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
}
}