use std::sync::Arc;
use hyper_rustls::HttpsConnectorBuilder;
use hyper_util::{client::legacy::Client as HyperClient, rt::TokioExecutor};
use libdav::{CalDavClient, dav::WebDavClient};
use tower_http::auth::AddAuthorization;
use vstorage::{
ItemKind,
base::{CreateItemOptions, FetchedItem, Storage},
caldav::{CalDavStorage, CollectionIdSegment},
vdir::VdirStorage,
};
async fn create_caldav_from_env() -> Arc<dyn Storage> {
let server = std::env::var("CALDAV_SERVER").unwrap();
let username = std::env::var("CALDAV_USERNAME").unwrap();
let password = std::env::var("CALDAV_PASSWORD").unwrap();
let connector = HttpsConnectorBuilder::new()
.with_native_roots()
.unwrap()
.https_or_http()
.enable_http1()
.build();
let raw_client = HyperClient::builder(TokioExecutor::new()).build(connector);
let auth_client = AddAuthorization::basic(raw_client, &username, &password);
let webdav = WebDavClient::new(server.parse().unwrap(), auth_client);
let caldav = CalDavClient::bootstrap_via_service_discovery(webdav)
.await
.unwrap();
let storage = CalDavStorage::builder(caldav)
.with_collection_id_segment(CollectionIdSegment::Last)
.build()
.await
.unwrap();
Arc::from(storage)
}
fn create_vdir_from_env() -> Arc<dyn Storage> {
let path = std::env::var("VDIR_PATH").unwrap();
let storage = VdirStorage::builder(path.into())
.unwrap()
.build(ItemKind::Calendar);
Arc::new(storage)
}
#[tokio::main]
async fn main() {
let caldav_storage = create_caldav_from_env().await;
let vdir_storage = create_vdir_from_env();
let discovery = caldav_storage.discover_collections().await.unwrap();
println!("Found {} collections", discovery.collection_count());
for discovered_collection in discovery.collections() {
println!("Creating {}", discovered_collection.href());
let collection_id = discovered_collection
.href()
.trim_end_matches('/')
.rsplit('/')
.next()
.expect("collection has at least one path segument");
let new_collection = vdir_storage.create_collection(collection_id).await.unwrap();
copy_collection(
caldav_storage.as_ref(),
discovered_collection.href(),
vdir_storage.as_ref(),
new_collection.href(),
)
.await;
}
}
async fn copy_collection(
source_storage: &dyn Storage,
source_collection_href: &str,
target_storage: &dyn Storage,
target_collection_href: &str,
) -> usize {
let mut count = 0;
for FetchedItem { item, .. } in source_storage
.get_all_items(source_collection_href)
.await
.expect("webcal remote has items")
{
let opts = CreateItemOptions::default();
count += 1;
target_storage
.create_item(target_collection_href, &item, opts)
.await
.expect("write to local filesystem collection");
}
count
}