Extend the app state

This commit is contained in:
Lennart
2023-09-05 17:00:32 +02:00
parent a87425f632
commit 6b6788ec98
8 changed files with 94 additions and 23 deletions

View File

@@ -6,6 +6,7 @@ use error::Error;
use routes::{calendar, event, principal, root}; use routes::{calendar, event, principal, root};
use rustical_store::calendar::CalendarStore; use rustical_store::calendar::CalendarStore;
use std::str::FromStr; use std::str::FromStr;
use std::sync::Arc;
use tokio::sync::RwLock; use tokio::sync::RwLock;
pub mod depth_extractor; pub mod depth_extractor;
@@ -14,11 +15,20 @@ pub mod namespace;
mod propfind; mod propfind;
pub mod routes; pub mod routes;
pub struct Context<C: CalendarStore> {
pub prefix: String,
pub store: Arc<RwLock<C>>,
}
pub fn configure_well_known(cfg: &mut web::ServiceConfig, caldav_root: String) { pub fn configure_well_known(cfg: &mut web::ServiceConfig, caldav_root: String) {
cfg.service(web::redirect("/caldav", caldav_root).permanent()); cfg.service(web::redirect("/caldav", caldav_root).permanent());
} }
pub fn configure_dav<C: CalendarStore>(cfg: &mut web::ServiceConfig, store: Data<RwLock<C>>) { pub fn configure_dav<C: CalendarStore>(
cfg: &mut web::ServiceConfig,
prefix: String,
store: Arc<RwLock<C>>,
) {
let propfind_method = || Method::from_str("PROPFIND").unwrap(); let propfind_method = || Method::from_str("PROPFIND").unwrap();
let report_method = || Method::from_str("REPORT").unwrap(); let report_method = || Method::from_str("REPORT").unwrap();
@@ -31,7 +41,8 @@ pub fn configure_dav<C: CalendarStore>(cfg: &mut web::ServiceConfig, store: Data
} }
}); });
cfg.app_data(store) // cfg.app_data(store)
cfg.app_data(Data::new(Context { prefix, store }))
.service( .service(
web::resource("{path:.*}") web::resource("{path:.*}")
// Without the guard this service would handle all requests // Without the guard this service would handle all requests

View File

@@ -0,0 +1,42 @@
use std::pin::Pin;
use actix_web::{http::StatusCode, Either, FromRequest, HttpRequest, ResponseError};
use derive_more::Display;
use futures_util::{
future::{err, ok, Ready},
Future,
};
#[derive(Debug, Display)]
pub struct BadPropfindRequest {}
impl ResponseError for BadPropfindRequest {
fn status_code(&self) -> actix_web::http::StatusCode {
StatusCode::BAD_REQUEST
}
}
#[derive(Debug, PartialEq)]
pub struct Propfind(Vec<String>);
impl FromRequest for Propfind {
type Error = BadPropfindRequest;
type Future = Either<PropfindExtractFut, Ready<Result<Self, Self::Error>>>;
fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future {}
}
pub struct PropfindExtractFut {
body_fut: HttpMessageBody,
}
impl Future for PropfindExtractFut {
type Output = Result<Propfind, BadPropfindRequest>;
fn poll(
self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Self::Output> {
Pin::new()
}
}

View File

@@ -3,7 +3,7 @@ use crate::propfind::{
generate_multistatus, parse_propfind, write_invalid_props_response, write_propstat_response, generate_multistatus, parse_propfind, write_invalid_props_response, write_propstat_response,
write_resourcetype, write_resourcetype,
}; };
use crate::Error; use crate::{Context, Error};
use actix_web::http::header::ContentType; use actix_web::http::header::ContentType;
use actix_web::http::StatusCode; use actix_web::http::StatusCode;
use actix_web::web::{Data, Path}; use actix_web::web::{Data, Path};
@@ -17,7 +17,6 @@ use rustical_store::calendar::{Calendar, CalendarStore, Event};
use std::collections::HashSet; use std::collections::HashSet;
use std::ops::Deref; use std::ops::Deref;
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::RwLock;
async fn handle_report_calendar_query( async fn handle_report_calendar_query(
query_node: Node<'_, '_>, query_node: Node<'_, '_>,
@@ -71,7 +70,7 @@ async fn handle_report_calendar_query(
} }
pub async fn route_report_calendar<C: CalendarStore>( pub async fn route_report_calendar<C: CalendarStore>(
store: Data<RwLock<C>>, context: Data<Context<C>>,
body: String, body: String,
path: Path<(String, String)>, path: Path<(String, String)>,
request: HttpRequest, request: HttpRequest,
@@ -80,7 +79,7 @@ pub async fn route_report_calendar<C: CalendarStore>(
let doc = roxmltree::Document::parse(&body).map_err(|_e| Error::InternalError)?; let doc = roxmltree::Document::parse(&body).map_err(|_e| Error::InternalError)?;
let query_node = doc.root_element(); let query_node = doc.root_element();
let events = store.read().await.get_events(&cid).await.unwrap(); let events = context.store.read().await.get_events(&cid).await.unwrap();
// TODO: implement filtering // TODO: implement filtering
match query_node.tag_name().name() { match query_node.tag_name().name() {
@@ -173,10 +172,11 @@ pub async fn route_propfind_calendar<C: CalendarStore>(
body: String, body: String,
request: HttpRequest, request: HttpRequest,
auth: BasicAuth, auth: BasicAuth,
store: Data<RwLock<C>>, context: Data<Context<C>>,
) -> Result<HttpResponse, Error> { ) -> Result<HttpResponse, Error> {
let (_principal, cid) = path.into_inner(); let (_principal, cid) = path.into_inner();
let calendar = store let calendar = context
.store
.read() .read()
.await .await
.get_calendar(&cid) .get_calendar(&cid)

View File

@@ -1,18 +1,18 @@
use crate::Error; use crate::{Context, Error};
use actix_web::web::{Data, Path}; use actix_web::web::{Data, Path};
use actix_web::HttpResponse; use actix_web::HttpResponse;
use rustical_store::calendar::CalendarStore; use rustical_store::calendar::CalendarStore;
use tokio::sync::RwLock;
pub async fn delete_event<C: CalendarStore>( pub async fn delete_event<C: CalendarStore>(
store: Data<RwLock<C>>, context: Data<Context<C>>,
path: Path<(String, String, String)>, path: Path<(String, String, String)>,
) -> Result<HttpResponse, Error> { ) -> Result<HttpResponse, Error> {
let (_principal, mut cid, uid) = path.into_inner(); let (_principal, mut cid, uid) = path.into_inner();
if cid.ends_with(".ics") { if cid.ends_with(".ics") {
cid.truncate(cid.len() - 4); cid.truncate(cid.len() - 4);
} }
store context
.store
.write() .write()
.await .await
.delete_event(&uid) .delete_event(&uid)
@@ -23,14 +23,15 @@ pub async fn delete_event<C: CalendarStore>(
} }
pub async fn get_event<C: CalendarStore>( pub async fn get_event<C: CalendarStore>(
store: Data<RwLock<C>>, context: Data<Context<C>>,
path: Path<(String, String, String)>, path: Path<(String, String, String)>,
) -> Result<HttpResponse, Error> { ) -> Result<HttpResponse, Error> {
let (_principal, mut cid, uid) = path.into_inner(); let (_principal, mut cid, uid) = path.into_inner();
if cid.ends_with(".ics") { if cid.ends_with(".ics") {
cid.truncate(cid.len() - 4); cid.truncate(cid.len() - 4);
} }
let event = store let event = context
.store
.read() .read()
.await .await
.get_event(&uid) .get_event(&uid)
@@ -43,7 +44,7 @@ pub async fn get_event<C: CalendarStore>(
} }
pub async fn put_event<C: CalendarStore>( pub async fn put_event<C: CalendarStore>(
store: Data<RwLock<C>>, context: Data<Context<C>>,
path: Path<(String, String, String)>, path: Path<(String, String, String)>,
body: String, body: String,
) -> Result<HttpResponse, Error> { ) -> Result<HttpResponse, Error> {
@@ -53,7 +54,8 @@ pub async fn put_event<C: CalendarStore>(
cid.truncate(cid.len() - 4); cid.truncate(cid.len() - 4);
} }
dbg!(&body); dbg!(&body);
store context
.store
.write() .write()
.await .await
.upsert_event(uid, body) .upsert_event(uid, body)

View File

@@ -6,7 +6,7 @@ use crate::{
generate_multistatus, parse_propfind, write_invalid_props_response, generate_multistatus, parse_propfind, write_invalid_props_response,
write_propstat_response, write_resourcetype, write_propstat_response, write_resourcetype,
}, },
Error, Context, Error,
}; };
use actix_web::{ use actix_web::{
http::{header::ContentType, StatusCode}, http::{header::ContentType, StatusCode},
@@ -20,7 +20,6 @@ use quick_xml::{
Writer, Writer,
}; };
use rustical_store::calendar::CalendarStore; use rustical_store::calendar::CalendarStore;
use tokio::sync::RwLock;
// Executes the PROPFIND request and returns a XML string to be written into a <mulstistatus> object. // Executes the PROPFIND request and returns a XML string to be written into a <mulstistatus> object.
pub async fn generate_propfind_principal_response( pub async fn generate_propfind_principal_response(
@@ -90,7 +89,7 @@ pub async fn route_propfind_principal<C: CalendarStore>(
body: String, body: String,
request: HttpRequest, request: HttpRequest,
auth: BasicAuth, auth: BasicAuth,
store: Data<RwLock<C>>, context: Data<Context<C>>,
depth: Depth, depth: Depth,
) -> Result<HttpResponse, Error> { ) -> Result<HttpResponse, Error> {
let props = parse_propfind(&body).map_err(|_e| Error::BadRequest)?; let props = parse_propfind(&body).map_err(|_e| Error::BadRequest)?;
@@ -98,7 +97,8 @@ pub async fn route_propfind_principal<C: CalendarStore>(
let mut responses = Vec::new(); let mut responses = Vec::new();
// also get calendars: // also get calendars:
if depth != Depth::Zero { if depth != Depth::Zero {
let cals = store let cals = context
.store
.read() .read()
.await .await
.get_calendars() .get_calendars()

8
crates/davfs/Cargo.toml Normal file
View File

@@ -0,0 +1,8 @@
[package]
name = "davfs"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

3
crates/davfs/src/main.rs Normal file
View File

@@ -0,0 +1,3 @@
fn main() {
println!("Hello, world!");
}

View File

@@ -9,6 +9,7 @@ use clap::Parser;
use config::{CalendarStoreConfig, JsonCalendarStoreConfig}; use config::{CalendarStoreConfig, JsonCalendarStoreConfig};
use rustical_api::configure_api; use rustical_api::configure_api;
use rustical_dav::{configure_dav, configure_well_known}; use rustical_dav::{configure_dav, configure_well_known};
use rustical_frontend::configure_frontend;
use rustical_store::calendar::JsonCalendarStore; use rustical_store::calendar::JsonCalendarStore;
use tokio::sync::RwLock; use tokio::sync::RwLock;
@@ -45,9 +46,9 @@ async fn main() -> Result<()> {
App::new() App::new()
.wrap(Logger::new("[%s] %r")) .wrap(Logger::new("[%s] %r"))
.wrap(NormalizePath::trim()) .wrap(NormalizePath::trim())
.service( .service(web::scope("/caldav").configure(|cfg| {
web::scope("/dav").configure(|cfg| configure_dav(cfg, cal_store.clone().into())), configure_dav(cfg, "/caldav".to_string(), cal_store.clone().into())
) }))
.service( .service(
web::scope("/.well-known") web::scope("/.well-known")
.configure(|cfg| configure_well_known(cfg, "/dav".to_string())), .configure(|cfg| configure_well_known(cfg, "/dav".to_string())),
@@ -55,6 +56,10 @@ async fn main() -> Result<()> {
.service( .service(
web::scope("/api").configure(|cfg| configure_api(cfg, cal_store.clone().into())), web::scope("/api").configure(|cfg| configure_api(cfg, cal_store.clone().into())),
) )
.service(
web::scope("/frontend")
.configure(|cfg| configure_frontend(cfg, cal_store.clone().into())),
)
}) })
.bind(("0.0.0.0", 4000))? .bind(("0.0.0.0", 4000))?
.run() .run()