From 751c2d1ce70e346e18e910a2f16b325ba41079d2 Mon Sep 17 00:00:00 2001 From: Lennart <18233294+lennart-k@users.noreply.github.com> Date: Wed, 15 Jan 2025 17:14:33 +0100 Subject: [PATCH] carddav: Implement DAV Push --- Cargo.lock | 1 + crates/caldav/src/calendar/methods/post.rs | 60 +----------- crates/caldav/src/calendar/prop.rs | 21 ----- crates/caldav/src/calendar/resource.rs | 5 +- crates/carddav/src/addressbook/methods/mod.rs | 1 + .../carddav/src/addressbook/methods/post.rs | 59 ++++++++++++ crates/carddav/src/addressbook/resource.rs | 34 ++++++- crates/carddav/src/lib.rs | 12 ++- crates/dav/src/lib.rs | 1 + crates/dav/src/push/mod.rs | 80 ++++++++++++++++ crates/store_sqlite/Cargo.toml | 1 + crates/store_sqlite/src/addressbook_store.rs | 92 ++++++++++++++++--- crates/store_sqlite/src/calendar_store.rs | 9 +- src/app.rs | 9 +- src/main.rs | 4 +- 15 files changed, 276 insertions(+), 113 deletions(-) create mode 100644 crates/carddav/src/addressbook/methods/post.rs create mode 100644 crates/dav/src/push/mod.rs diff --git a/Cargo.lock b/Cargo.lock index f29dbb0..0209598 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2884,6 +2884,7 @@ name = "rustical_store_sqlite" version = "0.1.0" dependencies = [ "async-trait", + "derive_more 1.0.0", "rustical_store", "serde", "sqlx", diff --git a/crates/caldav/src/calendar/methods/post.rs b/crates/caldav/src/calendar/methods/post.rs index 28aa1ab..32749ba 100644 --- a/crates/caldav/src/calendar/methods/post.rs +++ b/crates/caldav/src/calendar/methods/post.rs @@ -2,35 +2,13 @@ use crate::Error; use actix_web::http::header; use actix_web::web::{Data, Path}; use actix_web::{HttpRequest, HttpResponse}; +use rustical_dav::push::PushRegister; use rustical_store::auth::User; use rustical_store::{CalendarStore, Subscription, SubscriptionStore}; -use rustical_xml::{XmlDeserialize, XmlDocument, XmlRootTag}; +use rustical_xml::XmlDocument; use tracing::instrument; use tracing_actix_web::RootSpan; -#[derive(XmlDeserialize, Clone, Debug, PartialEq)] -#[xml(ns = "rustical_dav::namespace::NS_DAVPUSH")] -struct WebPushSubscription { - #[xml(ns = "rustical_dav::namespace::NS_DAVPUSH")] - push_resource: String, -} - -#[derive(XmlDeserialize, Clone, Debug, PartialEq)] -struct SubscriptionElement { - #[xml(ns = "rustical_dav::namespace::NS_DAVPUSH")] - pub web_push_subscription: WebPushSubscription, -} - -#[derive(XmlDeserialize, XmlRootTag, Clone, Debug, PartialEq)] -#[xml(root = b"push-register")] -#[xml(ns = "rustical_dav::namespace::NS_DAVPUSH")] -struct PushRegister { - #[xml(ns = "rustical_dav::namespace::NS_DAVPUSH")] - subscription: SubscriptionElement, - #[xml(ns = "rustical_dav::namespace::NS_DAVPUSH")] - expires: Option, -} - #[instrument(parent = root_span.id(), skip(store, subscription_store, root_span, req))] pub async fn route_post( path: Path<(String, String)>, @@ -79,37 +57,3 @@ pub async fn route_post - - - - https://up.example.net/yohd4yai5Phiz1wi - - - Wed, 20 Dec 2023 10:03:31 GMT - - "#, - ) - .unwrap(); - assert_eq!( - push_register, - PushRegister { - subscription: SubscriptionElement { - web_push_subscription: WebPushSubscription { - push_resource: "https://up.example.net/yohd4yai5Phiz1wi".to_owned() - } - }, - expires: Some("Wed, 20 Dec 2023 10:03:31 GMT".to_owned()) - } - ) - } -} diff --git a/crates/caldav/src/calendar/prop.rs b/crates/caldav/src/calendar/prop.rs index 4a66a85..506f49c 100644 --- a/crates/caldav/src/calendar/prop.rs +++ b/crates/caldav/src/calendar/prop.rs @@ -80,24 +80,3 @@ impl Default for SupportedReportSet { } } } - -#[derive(Debug, Clone, XmlSerialize, PartialEq)] -pub enum Transport { - #[xml(ns = "rustical_dav::namespace::NS_DAVPUSH")] - WebPush, -} - -#[derive(Debug, Clone, XmlSerialize, PartialEq)] -pub struct Transports { - #[xml(flatten, ty = "untagged")] - #[xml(ns = "rustical_dav::namespace::NS_DAVPUSH")] - transports: Vec, -} - -impl Default for Transports { - fn default() -> Self { - Self { - transports: vec![Transport::WebPush], - } - } -} diff --git a/crates/caldav/src/calendar/resource.rs b/crates/caldav/src/calendar/resource.rs index 78c4d4c..53be000 100644 --- a/crates/caldav/src/calendar/resource.rs +++ b/crates/caldav/src/calendar/resource.rs @@ -1,9 +1,7 @@ use super::methods::mkcalendar::route_mkcalendar; use super::methods::post::route_post; use super::methods::report::route_report_calendar; -use super::prop::{ - SupportedCalendarComponentSet, SupportedCalendarData, SupportedReportSet, Transports, -}; +use super::prop::{SupportedCalendarComponentSet, SupportedCalendarData, SupportedReportSet}; use crate::calendar_object::resource::CalendarObjectResource; use crate::principal::PrincipalResource; use crate::Error; @@ -13,6 +11,7 @@ use actix_web::web; use async_trait::async_trait; use derive_more::derive::{From, Into}; use rustical_dav::privileges::UserPrivilegeSet; +use rustical_dav::push::Transports; use rustical_dav::resource::{Resource, ResourceService}; use rustical_dav::xml::{HrefElement, Resourcetype, ResourcetypeInner}; use rustical_store::auth::User; diff --git a/crates/carddav/src/addressbook/methods/mod.rs b/crates/carddav/src/addressbook/methods/mod.rs index 769c33a..36ea3d9 100644 --- a/crates/carddav/src/addressbook/methods/mod.rs +++ b/crates/carddav/src/addressbook/methods/mod.rs @@ -1,2 +1,3 @@ pub mod mkcol; +pub mod post; pub mod report; diff --git a/crates/carddav/src/addressbook/methods/post.rs b/crates/carddav/src/addressbook/methods/post.rs new file mode 100644 index 0000000..af65569 --- /dev/null +++ b/crates/carddav/src/addressbook/methods/post.rs @@ -0,0 +1,59 @@ +use crate::Error; +use actix_web::http::header; +use actix_web::web::{Data, Path}; +use actix_web::{HttpRequest, HttpResponse}; +use rustical_dav::push::PushRegister; +use rustical_store::auth::User; +use rustical_store::{AddressbookStore, Subscription, SubscriptionStore}; +use rustical_xml::XmlDocument; +use tracing::instrument; +use tracing_actix_web::RootSpan; + +#[instrument(parent = root_span.id(), skip(store, subscription_store, root_span, req))] +pub async fn route_post( + path: Path<(String, String)>, + body: String, + user: User, + store: Data, + subscription_store: Data, + root_span: RootSpan, + req: HttpRequest, +) -> Result { + let (principal, addressbook_id) = path.into_inner(); + if principal != user.id { + return Err(Error::Unauthorized); + } + + let addressbook = store.get_addressbook(&principal, &addressbook_id).await?; + let request = PushRegister::parse_str(&body)?; + let sub_id = uuid::Uuid::new_v4().to_string(); + + let expires = if let Some(expires) = request.expires { + chrono::DateTime::parse_from_rfc2822(&expires) + .map_err(|err| crate::Error::Other(err.into()))? + } else { + chrono::Utc::now().fixed_offset() + chrono::Duration::weeks(1) + }; + + let subscription = Subscription { + id: sub_id.to_owned(), + push_resource: request + .subscription + .web_push_subscription + .push_resource + .to_owned(), + topic: addressbook.push_topic, + expiration: expires.naive_local(), + }; + subscription_store.upsert_subscription(subscription).await?; + + let location = req + .resource_map() + .url_for(&req, "subscription", &[sub_id]) + .unwrap(); + + Ok(HttpResponse::Created() + .append_header((header::LOCATION, location.to_string())) + .append_header((header::EXPIRES, expires.to_rfc2822())) + .finish()) +} diff --git a/crates/carddav/src/addressbook/resource.rs b/crates/carddav/src/addressbook/resource.rs index 5845da7..3b99fb0 100644 --- a/crates/carddav/src/addressbook/resource.rs +++ b/crates/carddav/src/addressbook/resource.rs @@ -1,4 +1,5 @@ use super::methods::mkcol::route_mkcol; +use super::methods::post::route_post; use super::methods::report::route_report_addressbook; use super::prop::{SupportedAddressData, SupportedReportSet}; use crate::address_object::resource::AddressObjectResource; @@ -10,22 +11,29 @@ use actix_web::web; use async_trait::async_trait; use derive_more::derive::{From, Into}; use rustical_dav::privileges::UserPrivilegeSet; +use rustical_dav::push::Transports; use rustical_dav::resource::{Resource, ResourceService}; use rustical_dav::xml::{Resourcetype, ResourcetypeInner}; use rustical_store::auth::User; -use rustical_store::{Addressbook, AddressbookStore}; +use rustical_store::{Addressbook, AddressbookStore, SubscriptionStore}; use rustical_xml::{XmlDeserialize, XmlSerialize}; +use std::marker::PhantomData; use std::str::FromStr; use std::sync::Arc; use strum::{EnumDiscriminants, EnumString, IntoStaticStr, VariantNames}; -pub struct AddressbookResourceService { +pub struct AddressbookResourceService +{ addr_store: Arc, + __phantom_sub: PhantomData, } -impl AddressbookResourceService { +impl AddressbookResourceService { pub fn new(addr_store: Arc) -> Self { - Self { addr_store } + Self { + addr_store, + __phantom_sub: PhantomData, + } } } @@ -42,6 +50,13 @@ pub enum AddressbookProp { #[xml(ns = "rustical_dav::namespace::NS_DAV", skip_deserializing)] Getcontenttype(&'static str), + // WebDav Push + #[xml(skip_deserializing)] + #[xml(ns = "rustical_dav::namespace::NS_DAVPUSH")] + Transports(Transports), + #[xml(ns = "rustical_dav::namespace::NS_DAVPUSH")] + Topic(String), + // CardDAV (RFC 6352) #[xml(ns = "rustical_dav::namespace::NS_CARDDAV")] AddressbookDescription(Option), @@ -90,6 +105,8 @@ impl Resource for AddressbookResource { AddressbookPropName::Getcontenttype => { AddressbookProp::Getcontenttype("text/vcard;charset=utf-8") } + AddressbookPropName::Transports => AddressbookProp::Transports(Default::default()), + AddressbookPropName::Topic => AddressbookProp::Topic(self.0.push_topic.to_owned()), AddressbookPropName::MaxResourceSize => AddressbookProp::MaxResourceSize(10000000), AddressbookPropName::SupportedReportSet => { AddressbookProp::SupportedReportSet(SupportedReportSet::default()) @@ -116,6 +133,8 @@ impl Resource for AddressbookResource { Ok(()) } AddressbookProp::Getcontenttype(_) => Err(rustical_dav::Error::PropReadOnly), + AddressbookProp::Transports(_) => Err(rustical_dav::Error::PropReadOnly), + AddressbookProp::Topic(_) => Err(rustical_dav::Error::PropReadOnly), AddressbookProp::MaxResourceSize(_) => Err(rustical_dav::Error::PropReadOnly), AddressbookProp::SupportedReportSet(_) => Err(rustical_dav::Error::PropReadOnly), AddressbookProp::SupportedAddressData(_) => Err(rustical_dav::Error::PropReadOnly), @@ -135,6 +154,8 @@ impl Resource for AddressbookResource { Ok(()) } AddressbookPropName::Getcontenttype => Err(rustical_dav::Error::PropReadOnly), + AddressbookPropName::Transports => Err(rustical_dav::Error::PropReadOnly), + AddressbookPropName::Topic => Err(rustical_dav::Error::PropReadOnly), AddressbookPropName::MaxResourceSize => Err(rustical_dav::Error::PropReadOnly), AddressbookPropName::SupportedReportSet => Err(rustical_dav::Error::PropReadOnly), AddressbookPropName::SupportedAddressData => Err(rustical_dav::Error::PropReadOnly), @@ -153,7 +174,9 @@ impl Resource for AddressbookResource { } #[async_trait(?Send)] -impl ResourceService for AddressbookResourceService { +impl ResourceService + for AddressbookResourceService +{ type MemberType = AddressObjectResource; type PathComponents = (String, String); // principal, addressbook_id type Resource = AddressbookResource; @@ -220,5 +243,6 @@ impl ResourceService for AddressbookResourceServi let report_method = web::method(Method::from_str("REPORT").unwrap()); res.route(mkcol_method.to(route_mkcol::)) .route(report_method.to(route_report_addressbook::)) + .post(route_post::) } } diff --git a/crates/carddav/src/lib.rs b/crates/carddav/src/lib.rs index 1d69f17..94cbccc 100644 --- a/crates/carddav/src/lib.rs +++ b/crates/carddav/src/lib.rs @@ -16,7 +16,7 @@ use rustical_dav::resource::{NamedRoute, ResourceService}; use rustical_dav::resources::RootResourceService; use rustical_store::{ auth::{AuthenticationMiddleware, AuthenticationProvider}, - AddressbookStore, + AddressbookStore, SubscriptionStore, }; use std::sync::Arc; @@ -29,10 +29,15 @@ pub fn configure_well_known(cfg: &mut web::ServiceConfig, carddav_root: String) cfg.service(web::redirect("/carddav", carddav_root).permanent()); } -pub fn configure_dav( +pub fn configure_dav< + AP: AuthenticationProvider, + A: AddressbookStore + ?Sized, + S: SubscriptionStore + ?Sized, +>( cfg: &mut web::ServiceConfig, auth_provider: Arc, store: Arc, + subscription_store: Arc, ) { cfg.service( web::scope("") @@ -58,6 +63,7 @@ pub fn configure_dav( }), ) .app_data(Data::from(store.clone())) + .app_data(Data::from(subscription_store)) .service(RootResourceService::::default().actix_resource()) .service( web::scope("/user").service( @@ -70,7 +76,7 @@ pub fn configure_dav( .service( web::scope("/{addressbook}") .service( - AddressbookResourceService::::new(store.clone()) + AddressbookResourceService::::new(store.clone()) .actix_resource(), ) .service( diff --git a/crates/dav/src/lib.rs b/crates/dav/src/lib.rs index fa87230..16b2dac 100644 --- a/crates/dav/src/lib.rs +++ b/crates/dav/src/lib.rs @@ -2,6 +2,7 @@ pub mod depth_header; pub mod error; pub mod namespace; pub mod privileges; +pub mod push; pub mod resource; pub mod resources; pub mod xml; diff --git a/crates/dav/src/push/mod.rs b/crates/dav/src/push/mod.rs new file mode 100644 index 0000000..e48aaa8 --- /dev/null +++ b/crates/dav/src/push/mod.rs @@ -0,0 +1,80 @@ +use rustical_xml::{XmlDeserialize, XmlRootTag, XmlSerialize}; + +#[derive(Debug, Clone, XmlSerialize, PartialEq)] +pub enum Transport { + #[xml(ns = "crate::namespace::NS_DAVPUSH")] + WebPush, +} + +#[derive(Debug, Clone, XmlSerialize, PartialEq)] +pub struct Transports { + #[xml(flatten, ty = "untagged")] + #[xml(ns = "crate::namespace::NS_DAVPUSH")] + transports: Vec, +} + +impl Default for Transports { + fn default() -> Self { + Self { + transports: vec![Transport::WebPush], + } + } +} + +#[derive(XmlDeserialize, Clone, Debug, PartialEq)] +#[xml(ns = "crate::namespace::NS_DAVPUSH")] +pub struct WebPushSubscription { + #[xml(ns = "crate::namespace::NS_DAVPUSH")] + pub push_resource: String, +} + +#[derive(XmlDeserialize, Clone, Debug, PartialEq)] +pub struct SubscriptionElement { + #[xml(ns = "crate::namespace::NS_DAVPUSH")] + pub web_push_subscription: WebPushSubscription, +} + +#[derive(XmlDeserialize, XmlRootTag, Clone, Debug, PartialEq)] +#[xml(root = b"push-register")] +#[xml(ns = "crate::namespace::NS_DAVPUSH")] +pub struct PushRegister { + #[xml(ns = "crate::namespace::NS_DAVPUSH")] + pub subscription: SubscriptionElement, + #[xml(ns = "crate::namespace::NS_DAVPUSH")] + pub expires: Option, +} + +#[cfg(test)] +mod tests { + use super::*; + use rustical_xml::XmlDocument; + + #[test] + fn test_xml_push_register() { + let push_register = PushRegister::parse_str( + r#" + + + + + https://up.example.net/yohd4yai5Phiz1wi + + + Wed, 20 Dec 2023 10:03:31 GMT + + "#, + ) + .unwrap(); + assert_eq!( + push_register, + PushRegister { + subscription: SubscriptionElement { + web_push_subscription: WebPushSubscription { + push_resource: "https://up.example.net/yohd4yai5Phiz1wi".to_owned() + } + }, + expires: Some("Wed, 20 Dec 2023 10:03:31 GMT".to_owned()) + } + ) + } +} diff --git a/crates/store_sqlite/Cargo.toml b/crates/store_sqlite/Cargo.toml index 165d9ae..c34c6c9 100644 --- a/crates/store_sqlite/Cargo.toml +++ b/crates/store_sqlite/Cargo.toml @@ -14,3 +14,4 @@ serde = { workspace = true } sqlx = { workspace = true } thiserror = { workspace = true } tracing = { workspace = true } +derive_more.workspace = true diff --git a/crates/store_sqlite/src/addressbook_store.rs b/crates/store_sqlite/src/addressbook_store.rs index 3079f40..81455e0 100644 --- a/crates/store_sqlite/src/addressbook_store.rs +++ b/crates/store_sqlite/src/addressbook_store.rs @@ -1,7 +1,12 @@ -use super::{ChangeOperation, SqliteStore}; +use super::ChangeOperation; use async_trait::async_trait; -use rustical_store::{AddressObject, Addressbook, AddressbookStore}; -use sqlx::{Sqlite, Transaction}; +use derive_more::derive::Constructor; +use rustical_store::{ + synctoken::format_synctoken, AddressObject, Addressbook, AddressbookStore, CollectionOperation, + CollectionOperationDomain, CollectionOperationType, Error, +}; +use sqlx::{Sqlite, SqlitePool, Transaction}; +use tokio::sync::mpsc::Sender; use tracing::instrument; #[derive(Debug, Clone)] @@ -25,16 +30,21 @@ async fn log_object_operation( addressbook_id: &str, object_id: &str, operation: ChangeOperation, -) -> Result<(), sqlx::Error> { - sqlx::query!( +) -> Result { + struct Synctoken { + synctoken: i64, + } + let Synctoken { synctoken } = sqlx::query_as!( + Synctoken, r#" UPDATE addressbooks SET synctoken = synctoken + 1 - WHERE (principal, id) = (?1, ?2)"#, + WHERE (principal, id) = (?1, ?2) + RETURNING synctoken"#, principal, addressbook_id ) - .execute(&mut **tx) + .fetch_one(&mut **tx) .await?; sqlx::query!( @@ -50,11 +60,17 @@ async fn log_object_operation( ) .execute(&mut **tx) .await?; - Ok(()) + Ok(format_synctoken(synctoken)) +} + +#[derive(Debug, Constructor)] +pub struct SqliteAddressbookStore { + db: SqlitePool, + sender: Sender, } #[async_trait] -impl AddressbookStore for SqliteStore { +impl AddressbookStore for SqliteAddressbookStore { #[instrument] async fn get_addressbook( &self, @@ -165,6 +181,12 @@ impl AddressbookStore for SqliteStore { addressbook_id: &str, use_trashbin: bool, ) -> Result<(), rustical_store::Error> { + let addressbook = match self.get_addressbook(principal, addressbook_id).await { + Ok(addressbook) => Some(addressbook), + Err(Error::NotFound) => None, + Err(err) => return Err(err), + }; + match use_trashbin { true => { sqlx::query!( @@ -185,6 +207,17 @@ impl AddressbookStore for SqliteStore { .map_err(crate::Error::from)?; } }; + + if let Some(addressbook) = addressbook { + // TODO: Watch for errors here? + let _ = self.sender.try_send(CollectionOperation { + r#type: CollectionOperationType::Delete, + domain: CollectionOperationDomain::Addressbook, + topic: addressbook.push_topic, + sync_token: None, + }); + } + Ok(()) } @@ -320,7 +353,7 @@ impl AddressbookStore for SqliteStore { .await .map_err(crate::Error::from)?; - log_object_operation( + let synctoken = log_object_operation( &mut tx, &principal, &addressbook_id, @@ -330,6 +363,17 @@ impl AddressbookStore for SqliteStore { .await .map_err(crate::Error::from)?; + // TODO: Watch for errors here? + let _ = self.sender.try_send(CollectionOperation { + r#type: CollectionOperationType::Object, + domain: CollectionOperationDomain::Addressbook, + topic: self + .get_addressbook(&principal, &addressbook_id) + .await? + .push_topic, + sync_token: Some(synctoken), + }); + tx.commit().await.map_err(crate::Error::from)?; Ok(()) } @@ -366,7 +410,7 @@ impl AddressbookStore for SqliteStore { .map_err(crate::Error::from)?; } }; - log_object_operation( + let synctoken = log_object_operation( &mut tx, principal, addressbook_id, @@ -375,7 +419,19 @@ impl AddressbookStore for SqliteStore { ) .await .map_err(crate::Error::from)?; + tx.commit().await.map_err(crate::Error::from)?; + + // TODO: Watch for errors here? + let _ = self.sender.try_send(CollectionOperation { + r#type: CollectionOperationType::Object, + domain: CollectionOperationDomain::Addressbook, + topic: self + .get_addressbook(principal, addressbook_id) + .await? + .push_topic, + sync_token: Some(synctoken), + }); Ok(()) } @@ -397,7 +453,7 @@ impl AddressbookStore for SqliteStore { .execute(&mut *tx) .await.map_err(crate::Error::from)?; - log_object_operation( + let synctoken = log_object_operation( &mut tx, principal, addressbook_id, @@ -407,6 +463,18 @@ impl AddressbookStore for SqliteStore { .await .map_err(crate::Error::from)?; tx.commit().await.map_err(crate::Error::from)?; + + // TODO: Watch for errors here? + let _ = self.sender.try_send(CollectionOperation { + r#type: CollectionOperationType::Object, + domain: CollectionOperationDomain::Addressbook, + topic: self + .get_addressbook(principal, addressbook_id) + .await? + .push_topic, + sync_token: Some(synctoken), + }); + Ok(()) } } diff --git a/crates/store_sqlite/src/calendar_store.rs b/crates/store_sqlite/src/calendar_store.rs index de564e0..fc24200 100644 --- a/crates/store_sqlite/src/calendar_store.rs +++ b/crates/store_sqlite/src/calendar_store.rs @@ -1,5 +1,6 @@ use super::ChangeOperation; use async_trait::async_trait; +use derive_more::derive::Constructor; use rustical_store::synctoken::format_synctoken; use rustical_store::{Calendar, CalendarObject, CalendarStore, Error}; use rustical_store::{CollectionOperation, CollectionOperationType}; @@ -65,18 +66,12 @@ async fn log_object_operation( Ok(format_synctoken(synctoken)) } -#[derive(Debug)] +#[derive(Debug, Constructor)] pub struct SqliteCalendarStore { db: SqlitePool, sender: Sender, } -impl SqliteCalendarStore { - pub fn new(db: SqlitePool, sender: Sender) -> Self { - Self { db, sender } - } -} - #[async_trait] impl CalendarStore for SqliteCalendarStore { #[instrument] diff --git a/src/app.rs b/src/app.rs index 5cab08a..df8623d 100644 --- a/src/app.rs +++ b/src/app.rs @@ -37,11 +37,16 @@ pub fn make_app< auth_provider.clone(), cal_store.clone(), addr_store.clone(), - subscription_store, + subscription_store.clone(), ) })) .service(web::scope("/carddav").configure(|cfg| { - rustical_carddav::configure_dav(cfg, auth_provider.clone(), addr_store.clone()) + rustical_carddav::configure_dav( + cfg, + auth_provider.clone(), + addr_store.clone(), + subscription_store, + ) })) .service( web::scope("/.well-known") diff --git a/src/main.rs b/src/main.rs index 6f9b093..d292af5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ use config::{DataStoreConfig, SqliteDataStoreConfig}; use rustical_dav::xml::multistatus::PropstatElement; use rustical_store::auth::StaticUserStore; use rustical_store::{AddressbookStore, CalendarStore, CollectionOperation, SubscriptionStore}; +use rustical_store_sqlite::addressbook_store::SqliteAddressbookStore; use rustical_store_sqlite::calendar_store::SqliteCalendarStore; use rustical_store_sqlite::{create_db_pool, SqliteStore}; use rustical_xml::{XmlRootTag, XmlSerialize, XmlSerializeRoot}; @@ -56,7 +57,7 @@ async fn get_data_stores( // Channel to watch for changes (for DAV Push) let (send, recv) = tokio::sync::mpsc::channel(1000); - let addressbook_store = Arc::new(SqliteStore::new(db.clone())); + let addressbook_store = Arc::new(SqliteAddressbookStore::new(db.clone(), send.clone())); let cal_store = Arc::new(SqliteCalendarStore::new(db.clone(), send)); let subscription_store = Arc::new(SqliteStore::new(db.clone())); (addressbook_store, cal_store, subscription_store, recv) @@ -107,7 +108,6 @@ async fn main() -> Result<()> { tokio::spawn(async move { let subscription_store = subscription_store_clone.clone(); while let Some(message) = update_recv.recv().await { - dbg!(&message); if let Ok(subscribers) = subscription_store.get_subscriptions(&message.topic).await {