aboutsummaryrefslogtreecommitdiff
path: root/aero-proto/src
diff options
context:
space:
mode:
authorQuentin Dufour <quentin@deuxfleurs.fr>2024-03-18 15:04:46 +0100
committerQuentin Dufour <quentin@deuxfleurs.fr>2024-03-18 15:04:46 +0100
commit4a5ae87059c41ea3e264a0ffef0d9ff4c55b8b83 (patch)
treece2c088c46d94ffd2e79b933c3504ef779ad41a3 /aero-proto/src
parent3b57d21e30302be409556711db98e16dc1a9badc (diff)
downloadaerogramme-4a5ae87059c41ea3e264a0ffef0d9ff4c55b8b83.tar.gz
aerogramme-4a5ae87059c41ea3e264a0ffef0d9ff4c55b8b83.zip
WIP DAV hierarchy
Diffstat (limited to 'aero-proto/src')
-rw-r--r--aero-proto/src/dav.rs149
1 files changed, 104 insertions, 45 deletions
diff --git a/aero-proto/src/dav.rs b/aero-proto/src/dav.rs
index 2bc1247..7f0f28d 100644
--- a/aero-proto/src/dav.rs
+++ b/aero-proto/src/dav.rs
@@ -196,20 +196,22 @@ async fn router(user: std::sync::Arc<User>, req: Request<Incoming>) -> Result<Re
let path = req.uri().path().to_string();
let path_segments: Vec<_> = path.split("/").filter(|s| *s != "").collect();
let method = req.method().as_str().to_uppercase();
+ let node = match Box::new(RootNode {}).fetch(&user, &path_segments) {
+ Ok(v) => v,
+ Err(e) => {
+ tracing::warn!(err=?e, "dav node fetch failed");
+ return Ok(Response::builder()
+ .status(404)
+ .body(text_body("Resource not found"))?)
+ }
+ };
- match (method.as_str(), path_segments.as_slice()) {
- ("OPTIONS", _) => return Ok(Response::builder()
+ match method.as_str() {
+ "OPTIONS" => return Ok(Response::builder()
.status(200)
.header("DAV", "1")
.body(text_body(""))?),
- ("PROPFIND", []) => propfind_root(user, req).await,
- (_, [ username, ..]) if *username != user.username => return Ok(Response::builder()
- .status(403)
- .body(text_body("Accessing other user ressources is not allowed"))?),
- ("PROPFIND", [ _ ]) => propfind_home(user, &req).await,
- ("PROPFIND", [ _, "calendar" ]) => propfind_all_calendars(user, &req).await,
- ("PROPFIND", [ _, "calendar", colname ]) => propfind_this_calendar(user, &req, colname).await,
- ("PROPFIND", [ _, "calendar", colname, event ]) => propfind_event(user, req, colname, event).await,
+ "PROPFIND" => propfind(user, req, node).await,
_ => return Ok(Response::builder()
.status(501)
.body(text_body("Not implemented"))?),
@@ -224,8 +226,7 @@ const SUPPORTED_PROPNAME: [dav::PropertyRequest<Calendar>; 2] = [
dav::PropertyRequest::ResourceType,
];
-async fn propfind_root(user: std::sync::Arc<User>, req: Request<Incoming>) -> Result<Response<BoxBody<Bytes, std::io::Error>>> {
- let node = RootNode {};
+async fn propfind(user: std::sync::Arc<User>, req: Request<Incoming>, node: Box<dyn DavNode>) -> Result<Response<BoxBody<Bytes, std::io::Error>>> {
let depth = depth(&req);
@@ -258,36 +259,6 @@ async fn propfind_root(user: std::sync::Arc<User>, req: Request<Incoming>) -> Re
serialize(node.multistatus_val(&user, &propname, depth))
}
-async fn propfind_home(user: std::sync::Arc<User>, req: &Request<impl hyper::body::Body>) -> Result<Response<BoxBody<Bytes, std::io::Error>>> {
- tracing::info!("user home");
- Ok(Response::new(text_body("Hello World!")))
-}
-
-async fn propfind_all_calendars(user: std::sync::Arc<User>, req: &Request<impl hyper::body::Body>) -> Result<Response<BoxBody<Bytes, std::io::Error>>> {
- tracing::info!("calendar");
- Ok(Response::new(text_body("Hello World!")))
-}
-
-async fn propfind_this_calendar(
- user: std::sync::Arc<User>,
- req: &Request<Incoming>,
- colname: &str
-) -> Result<Response<BoxBody<Bytes, std::io::Error>>> {
- tracing::info!(name=colname, "selected calendar");
- Ok(Response::new(text_body("Hello World!")))
-}
-
-async fn propfind_event(
- user: std::sync::Arc<User>,
- req: Request<Incoming>,
- colname: &str,
- event: &str,
-) -> Result<Response<BoxBody<Bytes, std::io::Error>>> {
- tracing::info!(name=colname, obj=event, "selected event");
- Ok(Response::new(text_body("Hello World!")))
-}
-
-
#[allow(dead_code)]
async fn collections(_user: std::sync::Arc<User>, _req: Request<impl hyper::body::Body>) -> Result<Response<Full<Bytes>>> {
unimplemented!();
@@ -326,7 +297,7 @@ fn serialize<T: dxml::QWrite + Send + 'static>(elem: T) -> Result<Response<BoxBo
let sink = PollSender::new(tx).sink_map_err(|_| Error::from(ErrorKind::BrokenPipe));
let mut writer = SinkWriter::new(CopyToBytes::new(sink));
let q = quick_xml::writer::Writer::new_with_indent(&mut writer, b' ', 4);
- let ns_to_apply = vec![ ("xmlns:D".into(), "DAV:".into()) ];
+ let ns_to_apply = vec![ ("xmlns:D".into(), "DAV:".into()), ("xmlns:C".into(), "urn:ietf:params:xml:ns:caldav".into()) ];
let mut qwriter = dxml::Writer { q, ns_to_apply };
let decl = quick_xml::events::BytesDecl::from_start(quick_xml::events::BytesStart::from_content("xml encoding='utf-8' version='1.0'", 0));
match qwriter.q.write_event_async(quick_xml::events::Event::Decl(decl)).await {
@@ -369,16 +340,22 @@ async fn deserialize<T: dxml::Node<T>>(req: Request<Incoming>) -> Result<T> {
//---
type ArcUser = std::sync::Arc<User>;
-trait DavNode {
+trait DavNode: Send {
+ // ------- specialized logic
+
// recurence
fn children(&self, user: &ArcUser) -> Vec<Box<dyn DavNode>>;
+ fn fetch(self: Box<Self>, user: &ArcUser, path: &[&str]) -> Result<Box<dyn DavNode>>;
// node properties
+ fn path(&self, user: &ArcUser) -> String;
fn name(&self, user: &ArcUser) -> String;
fn supported_properties(&self, user: &ArcUser) -> dav::PropName<Calendar>;
fn properties(&self, user: &ArcUser, props: &dav::PropName<Calendar>) -> dav::PropValue<Calendar>;
- // building DAV responses
+ // ----- common
+
+ /// building DAV responses
fn multistatus_name(&self, user: &ArcUser, depth: dav::Depth) -> dav::Multistatus<Calendar, dav::PropName<Calendar>> {
let mut names = vec![(".".into(), self.supported_properties(user))];
if matches!(depth, dav::Depth::One | dav::Depth::Infinity) {
@@ -436,6 +413,23 @@ trait DavNode {
struct RootNode {}
impl DavNode for RootNode {
+ fn fetch(self: Box<Self>, user: &ArcUser, path: &[&str]) -> Result<Box<dyn DavNode>> {
+ if path.len() == 0 {
+ return Ok(self)
+ }
+
+ if path[0] == user.username {
+ let child = Box::new(HomeNode {});
+ return child.fetch(user, &path[1..])
+ }
+
+ Err(anyhow!("Not found"))
+ }
+
+ fn path(&self, user: &ArcUser) -> String {
+ todo!();
+ }
+
fn name(&self, _user: &ArcUser) -> String {
"/".into()
}
@@ -459,6 +453,23 @@ impl DavNode for RootNode {
struct HomeNode {}
impl DavNode for HomeNode {
+ fn fetch(self: Box<Self>, user: &ArcUser, path: &[&str]) -> Result<Box<dyn DavNode>> {
+ if path.len() == 0 {
+ return Ok(self)
+ }
+
+ if path[0] == "calendar" {
+ let child = Box::new(CalendarListNode {});
+ return child.fetch(user, &path[1..])
+ }
+
+ Err(anyhow!("Not found"))
+ }
+
+ fn path(&self, user: &ArcUser) -> String {
+ todo!();
+ }
+
fn name(&self, user: &ArcUser) -> String {
format!("{}/", user.username)
}
@@ -482,6 +493,24 @@ impl DavNode for HomeNode {
struct CalendarListNode {}
impl DavNode for CalendarListNode {
+ fn fetch(self: Box<Self>, user: &ArcUser, path: &[&str]) -> Result<Box<dyn DavNode>> {
+ if path.len() == 0 {
+ return Ok(self)
+ }
+
+ //@FIXME hardcoded logic
+ if path[0] == "personal" {
+ let child = Box::new(CalendarNode { name: "personal".to_string() });
+ return child.fetch(user, &path[1..])
+ }
+
+ Err(anyhow!("Not found"))
+ }
+
+ fn path(&self, user: &ArcUser) -> String {
+ todo!();
+ }
+
fn name(&self, _user: &ArcUser) -> String {
"calendar/".into()
}
@@ -507,6 +536,24 @@ struct CalendarNode {
name: String,
}
impl DavNode for CalendarNode {
+ fn fetch(self: Box<Self>, user: &ArcUser, path: &[&str]) -> Result<Box<dyn DavNode>> {
+ if path.len() == 0 {
+ return Ok(self)
+ }
+
+ //@FIXME hardcoded logic
+ if path[0] == "something.ics" {
+ let child = Box::new(EventNode { file: "something.ics".to_string() });
+ return child.fetch(user, &path[1..])
+ }
+
+ Err(anyhow!("Not found"))
+ }
+
+ fn path(&self, user: &ArcUser) -> String {
+ todo!();
+ }
+
fn name(&self, _user: &ArcUser) -> String {
format!("{}/", self.name)
}
@@ -535,6 +582,18 @@ struct EventNode {
file: String,
}
impl DavNode for EventNode {
+ fn fetch(self: Box<Self>, user: &ArcUser, path: &[&str]) -> Result<Box<dyn DavNode>> {
+ if path.len() == 0 {
+ return Ok(self)
+ }
+
+ Err(anyhow!("Not found"))
+ }
+
+ fn path(&self, user: &ArcUser) -> String {
+ todo!();
+ }
+
fn name(&self, _user: &ArcUser) -> String {
self.file.to_string()
}