Compare commits

..

No commits in common. "master" and "v0.3.0" have entirely different histories.

18 changed files with 244 additions and 520 deletions

262
Cargo.lock generated
View File

@ -1,7 +1,5 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "0.7.18"
@ -13,9 +11,9 @@ dependencies = [
[[package]]
name = "async-trait"
version = "0.1.52"
version = "0.1.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3"
checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e"
dependencies = [
"proc-macro2",
"quote",
@ -53,9 +51,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bumpalo"
version = "3.9.1"
version = "3.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899"
checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
[[package]]
name = "bytes"
@ -115,17 +113,11 @@ dependencies = [
"serde",
]
[[package]]
name = "either"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "encoding_rs"
version = "0.8.30"
version = "0.8.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df"
checksum = "a74ea89a0a1b98f6332de42c95baff457ada66d1cb4030f9ff151b2041a1c746"
dependencies = [
"cfg-if",
]
@ -143,15 +135,6 @@ dependencies = [
"termcolor",
]
[[package]]
name = "fastrand"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "779d043b6a0b90cc4c0ed7ee380a6504394cee7efd7db050e3774eee387324b2"
dependencies = [
"instant",
]
[[package]]
name = "fnv"
version = "1.0.7"
@ -185,36 +168,36 @@ dependencies = [
[[package]]
name = "futures-channel"
version = "0.3.19"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b"
checksum = "7fc8cd39e3dbf865f7340dce6a2d401d24fd37c6fe6c4f0ee0de8bfca2252d27"
dependencies = [
"futures-core",
]
[[package]]
name = "futures-core"
version = "0.3.19"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7"
checksum = "629316e42fe7c2a0b9a65b47d159ceaa5453ab14e8f0a3c5eedbb8cd55b4a445"
[[package]]
name = "futures-sink"
version = "0.3.19"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508"
checksum = "996c6442437b62d21a32cd9906f9c41e7dc1e19a9579843fad948696769305af"
[[package]]
name = "futures-task"
version = "0.3.19"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72"
checksum = "dabf1872aaab32c886832f2276d2f5399887e2bd613698a02359e4ea83f8de12"
[[package]]
name = "futures-util"
version = "0.3.19"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164"
checksum = "41d22213122356472061ac0f1ab2cee28d2bac8491410fd68c2af53d1cedb83e"
dependencies = [
"futures-core",
"futures-task",
@ -235,20 +218,20 @@ dependencies = [
[[package]]
name = "getrandom"
version = "0.2.4"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c"
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
dependencies = [
"cfg-if",
"libc",
"wasi 0.10.3+wasi-snapshot-preview1",
"wasi 0.10.2+wasi-snapshot-preview1",
]
[[package]]
name = "h2"
version = "0.3.10"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c9de88456263e249e241fcd211d3954e2c9b0ef7ccfc235a444eb367cae3689"
checksum = "7fd819562fcebdac5afc5c113c3ec36f902840b70fd4fc458799c8ce4607ae55"
dependencies = [
"bytes",
"fnv",
@ -280,13 +263,13 @@ dependencies = [
[[package]]
name = "http"
version = "0.2.6"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03"
checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b"
dependencies = [
"bytes",
"fnv",
"itoa 1.0.1",
"itoa",
]
[[package]]
@ -320,9 +303,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "hyper"
version = "0.14.16"
version = "0.14.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7ec3e62bdc98a2f0393a5048e4c30ef659440ea6e0e572965103e72bd836f55"
checksum = "436ec0091e4f20e655156a30a0df3770fe2900aa301e548e08446ec794b6953c"
dependencies = [
"bytes",
"futures-channel",
@ -333,7 +316,7 @@ dependencies = [
"http-body",
"httparse",
"httpdate",
"itoa 0.4.8",
"itoa",
"pin-project-lite",
"socket2",
"tokio",
@ -384,50 +367,26 @@ dependencies = [
[[package]]
name = "indexmap"
version = "1.8.0"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "instant"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [
"cfg-if",
]
[[package]]
name = "ipnet"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9"
[[package]]
name = "itertools"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]]
name = "itoa"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
[[package]]
name = "js-sys"
version = "0.3.55"
@ -439,7 +398,7 @@ dependencies = [
[[package]]
name = "kitchen-fridge"
version = "0.4.0"
version = "0.3.0"
dependencies = [
"async-trait",
"bitflags",
@ -448,7 +407,6 @@ dependencies = [
"env_logger",
"ical-daladim",
"ics",
"itertools",
"log",
"minidom",
"once_cell",
@ -469,9 +427,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.112"
version = "0.2.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119"
[[package]]
name = "log"
@ -579,9 +537,9 @@ dependencies = [
[[package]]
name = "num_cpus"
version = "1.13.1"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
dependencies = [
"hermit-abi",
"libc",
@ -589,9 +547,9 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.9.0"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
[[package]]
name = "openssl"
@ -609,15 +567,15 @@ dependencies = [
[[package]]
name = "openssl-probe"
version = "0.1.5"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a"
[[package]]
name = "openssl-sys"
version = "0.9.72"
version = "0.9.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb"
checksum = "7df13d165e607909b363a4757a6f133f8a818a74e9d3a98d09c6128e15fa4c73"
dependencies = [
"autocfg",
"cc",
@ -650,7 +608,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526"
dependencies = [
"phf_shared",
"rand",
"rand 0.7.3",
]
[[package]]
@ -678,9 +636,9 @@ dependencies = [
[[package]]
name = "pin-project-lite"
version = "0.2.8"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c"
checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443"
[[package]]
name = "pin-utils"
@ -690,15 +648,15 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkg-config"
version = "0.3.24"
version = "0.3.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"
checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f"
[[package]]
name = "ppv-lite86"
version = "0.2.16"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba"
[[package]]
name = "proc-macro-hack"
@ -708,9 +666,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
[[package]]
name = "proc-macro2"
version = "1.0.36"
version = "1.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
dependencies = [
"unicode-xid",
]
@ -726,9 +684,9 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.14"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d"
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
dependencies = [
"proc-macro2",
]
@ -741,12 +699,24 @@ checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
dependencies = [
"getrandom 0.1.16",
"libc",
"rand_chacha",
"rand_core",
"rand_hc",
"rand_chacha 0.2.2",
"rand_core 0.5.1",
"rand_hc 0.2.0",
"rand_pcg",
]
[[package]]
name = "rand"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
dependencies = [
"libc",
"rand_chacha 0.3.1",
"rand_core 0.6.3",
"rand_hc 0.3.1",
]
[[package]]
name = "rand_chacha"
version = "0.2.2"
@ -754,7 +724,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
dependencies = [
"ppv-lite86",
"rand_core",
"rand_core 0.5.1",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core 0.6.3",
]
[[package]]
@ -766,13 +746,31 @@ dependencies = [
"getrandom 0.1.16",
]
[[package]]
name = "rand_core"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
dependencies = [
"getrandom 0.2.3",
]
[[package]]
name = "rand_hc"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
dependencies = [
"rand_core",
"rand_core 0.5.1",
]
[[package]]
name = "rand_hc"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
dependencies = [
"rand_core 0.6.3",
]
[[package]]
@ -781,7 +779,7 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
dependencies = [
"rand_core",
"rand_core 0.5.1",
]
[[package]]
@ -821,16 +819,15 @@ dependencies = [
[[package]]
name = "reqwest"
version = "0.11.9"
version = "0.11.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f242f1488a539a79bac6dbe7c8609ae43b7914b7736210f239a37cccb32525"
checksum = "66d2927ca2f685faf0fc620ac4834690d29e7abb153add10f5812eef20b5e280"
dependencies = [
"base64",
"bytes",
"encoding_rs",
"futures-core",
"futures-util",
"h2",
"http",
"http-body",
"hyper",
@ -857,9 +854,9 @@ dependencies = [
[[package]]
name = "ryu"
version = "1.0.9"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]]
name = "sanitize-filename"
@ -883,9 +880,9 @@ dependencies = [
[[package]]
name = "security-framework"
version = "2.5.0"
version = "2.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d09d3c15d814eda1d6a836f2f2b56a6abc1446c8a34351cb3180d3db92ffe4ce"
checksum = "525bc1abfda2e1998d152c45cf13e696f76d0a4972310b22fac1658b05df7c87"
dependencies = [
"bitflags",
"core-foundation",
@ -896,9 +893,9 @@ dependencies = [
[[package]]
name = "security-framework-sys"
version = "2.5.0"
version = "2.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e90dd10c41c6bfc633da6e0c659bd25d31e0791e5974ac42970267d59eba87f7"
checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e"
dependencies = [
"core-foundation-sys",
"libc",
@ -906,18 +903,18 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.133"
version = "1.0.130"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97565067517b60e2d1ea8b268e59ce036de907ac523ad83a0475da04e818989a"
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.133"
version = "1.0.130"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed201699328568d8d08208fdd080e3ff594e6c422e438b6705905da01005d537"
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
dependencies = [
"proc-macro2",
"quote",
@ -926,32 +923,32 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.75"
version = "1.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c059c05b48c5c0067d4b4b2b4f0732dd65feb52daf7e0ea09cd87e7dadc1af79"
checksum = "063bf466a64011ac24040a49009724ee60a57da1b437617ceb32e53ad61bfb19"
dependencies = [
"itoa 1.0.1",
"itoa",
"ryu",
"serde",
]
[[package]]
name = "serde_urlencoded"
version = "0.7.1"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9"
dependencies = [
"form_urlencoded",
"itoa 1.0.1",
"itoa",
"ryu",
"serde",
]
[[package]]
name = "siphasher"
version = "0.3.9"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a86232ab60fa71287d7f2ddae4a7073f6b7aac33631c3015abb556f08c6d0a3e"
checksum = "533494a8f9b724d33625ab53c6c4800f7cc445895924a8ef649222dcb76e938b"
[[package]]
name = "slab"
@ -971,9 +968,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.85"
version = "1.0.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a684ac3dcd8913827e18cd09a68384ee66c1de24157e3c556c9ab16d85695fb7"
checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966"
dependencies = [
"proc-macro2",
"quote",
@ -982,13 +979,13 @@ dependencies = [
[[package]]
name = "tempfile"
version = "3.3.0"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
dependencies = [
"cfg-if",
"fastrand",
"libc",
"rand 0.8.4",
"redox_syscall",
"remove_dir_all",
"winapi",
@ -1050,10 +1047,11 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "tokio"
version = "1.15.0"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbbf1c778ec206785635ce8ad57fe52b3009ae9e0c9f574a728f3049d3e55838"
checksum = "70e992e41e0d2fb9f755b37446f20900f64446ef54874f40a60c78f021ac6144"
dependencies = [
"autocfg",
"bytes",
"libc",
"memchr",
@ -1066,9 +1064,9 @@ dependencies = [
[[package]]
name = "tokio-macros"
version = "1.7.0"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7"
checksum = "c9efc1aba077437943f7515666aa2b882dfabfbfdf89c819ea75a8d6e9eaba5e"
dependencies = [
"proc-macro2",
"quote",
@ -1171,7 +1169,7 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
dependencies = [
"getrandom 0.2.4",
"getrandom 0.2.3",
]
[[package]]
@ -1198,9 +1196,9 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "wasi"
version = "0.10.3+wasi-snapshot-preview1"
version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46a2e384a3f170b0c7543787a91411175b71afd56ba4d3a0ae5678d4e2243c0e"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "wasm-bindgen"

View File

@ -1,6 +1,6 @@
[package]
name = "kitchen-fridge"
version = "0.4.0"
version = "0.3.0"
authors = ["daladim"]
edition = "2018"
description = "A CalDAV (ical file management over WebDAV) library"
@ -35,4 +35,3 @@ ics = "0.5"
chrono = { version = "0.4", features = ["serde"] }
csscolorparser = { version = "0.5", features = ["serde"] }
once_cell = "1.8"
itertools = "0.10"

View File

@ -1,31 +1,40 @@
//! This is an example of how kitchen-fridge can be used
use std::path::Path;
use chrono::{Utc};
use url::Url;
use kitchen_fridge::traits::CalDavSource;
use kitchen_fridge::{client::Client, traits::CalDavSource};
use kitchen_fridge::calendar::SupportedComponents;
use kitchen_fridge::Item;
use kitchen_fridge::Task;
use kitchen_fridge::task::CompletionStatus;
use kitchen_fridge::cache::Cache;
use kitchen_fridge::CalDavProvider;
use kitchen_fridge::traits::BaseCalendar;
use kitchen_fridge::traits::CompleteCalendar;
use kitchen_fridge::utils::pause;
mod shared;
use shared::initial_sync;
use shared::{URL, USERNAME, EXAMPLE_EXISTING_CALENDAR_URL, EXAMPLE_CREATED_CALENDAR_URL};
const CACHE_FOLDER: &str = "test_cache/provider_sync";
// TODO: change these values with yours
pub const URL: &str = "https://my.server.com/remote.php/dav/files/john";
pub const USERNAME: &str = "username";
pub const PASSWORD: &str = "secret_password";
pub const EXAMPLE_EXISTING_CALENDAR_URL: &str = "https://my.server.com/remote.php/dav/calendars/john/a_calendar_name/";
pub const EXAMPLE_CREATED_CALENDAR_URL: &str = "https://my.server.com/remote.php/dav/calendars/john/a_calendar_that_we_have_created/";
#[tokio::main]
async fn main() {
env_logger::init();
println!("This example show how to sync a remote server with a local cache, using a Provider.");
println!("Make sure you have edited the constants in the 'shared.rs' file to include correct URLs and credentials.");
println!("This examples show how to sync a remote server with a local cache, using a Provider.");
println!("Make sure you have edited the constants in this file to include correct URLs and credentials.");
println!("You can also set the RUST_LOG environment variable to display more info about the sync.");
println!("");
println!("This will use the following settings:");
@ -35,12 +44,39 @@ async fn main() {
println!(" * EXAMPLE_CREATED_CALENDAR_URL = {}", EXAMPLE_CREATED_CALENDAR_URL);
pause();
let mut provider = initial_sync(CACHE_FOLDER).await;
let cache_path = Path::new(CACHE_FOLDER);
let client = Client::new(URL, USERNAME, PASSWORD).unwrap();
let cache = match Cache::from_folder(&cache_path) {
Ok(cache) => cache,
Err(err) => {
log::warn!("Invalid cache file: {}. Using a default cache", err);
Cache::new(&cache_path)
}
};
let mut provider = CalDavProvider::new(client, cache);
let cals = provider.local().get_calendars().await.unwrap();
println!("---- Local items, before sync -----");
kitchen_fridge::utils::print_calendar_list(&cals).await;
println!("Starting a sync...");
println!("Depending on your RUST_LOG value, you may see more or less details about the progress.");
// Note that we could use sync_with_feedback() to have better and formatted feedback
if provider.sync().await == false {
log::warn!("Sync did not complete, see the previous log lines for more info. You can safely start a new sync.");
}
provider.local().save_to_folder().unwrap();
println!("---- Local items, after sync -----");
let cals = provider.local().get_calendars().await.unwrap();
kitchen_fridge::utils::print_calendar_list(&cals).await;
add_items_and_sync_again(&mut provider).await;
}
async fn add_items_and_sync_again(provider: &mut CalDavProvider) {
async fn add_items_and_sync_again(provider: &mut CalDavProvider)
{
println!("\nNow, we'll add a calendar and a few tasks and run the sync again.");
pause();

View File

@ -1,54 +0,0 @@
use std::path::Path;
use kitchen_fridge::client::Client;
use kitchen_fridge::traits::CalDavSource;
use kitchen_fridge::CalDavProvider;
use kitchen_fridge::cache::Cache;
// TODO: change these values with yours
pub const URL: &str = "https://my.server.com/remote.php/dav/files/john";
pub const USERNAME: &str = "username";
pub const PASSWORD: &str = "secret_password";
pub const EXAMPLE_EXISTING_CALENDAR_URL: &str = "https://my.server.com/remote.php/dav/calendars/john/a_calendar_name/";
pub const EXAMPLE_CREATED_CALENDAR_URL: &str = "https://my.server.com/remote.php/dav/calendars/john/a_calendar_that_we_have_created/";
fn main() {
panic!("This file is not supposed to be executed");
}
/// Initializes a Provider, and run an initial sync from the server
pub async fn initial_sync(cache_folder: &str) -> CalDavProvider {
let cache_path = Path::new(cache_folder);
let client = Client::new(URL, USERNAME, PASSWORD).unwrap();
let cache = match Cache::from_folder(&cache_path) {
Ok(cache) => cache,
Err(err) => {
log::warn!("Invalid cache file: {}. Using a default cache", err);
Cache::new(&cache_path)
}
};
let mut provider = CalDavProvider::new(client, cache);
let cals = provider.local().get_calendars().await.unwrap();
println!("---- Local items, before sync -----");
kitchen_fridge::utils::print_calendar_list(&cals).await;
println!("Starting a sync...");
println!("Depending on your RUST_LOG value, you may see more or less details about the progress.");
// Note that we could use sync_with_feedback() to have better and formatted feedback
if provider.sync().await == false {
log::warn!("Sync did not complete, see the previous log lines for more info. You can safely start a new sync.");
}
provider.local().save_to_folder().unwrap();
println!("---- Local items, after sync -----");
let cals = provider.local().get_calendars().await.unwrap();
kitchen_fridge::utils::print_calendar_list(&cals).await;
provider
}

View File

@ -1,65 +0,0 @@
//! This is an example of how kitchen-fridge can be used.
//! This binary simply toggles all completion statuses of the tasks it finds.
use std::error::Error;
use chrono::Utc;
use kitchen_fridge::item::Item;
use kitchen_fridge::task::CompletionStatus;
use kitchen_fridge::CalDavProvider;
use kitchen_fridge::utils::pause;
mod shared;
use shared::initial_sync;
use shared::{URL, USERNAME};
const CACHE_FOLDER: &str = "test_cache/toggle_completion";
#[tokio::main]
async fn main() {
env_logger::init();
println!("This example show how to sync a remote server with a local cache, using a Provider.");
println!("Make sure you have edited the constants in the 'shared.rs' file to include correct URLs and credentials.");
println!("You can also set the RUST_LOG environment variable to display more info about the sync.");
println!("");
println!("This will use the following settings:");
println!(" * URL = {}", URL);
println!(" * USERNAME = {}", USERNAME);
pause();
let mut provider = initial_sync(CACHE_FOLDER).await;
toggle_all_tasks_and_sync_again(&mut provider).await.unwrap();
}
async fn toggle_all_tasks_and_sync_again(provider: &mut CalDavProvider) -> Result<(), Box<dyn Error>> {
let mut n_toggled = 0;
for (_url, cal) in provider.local().get_calendars_sync()?.iter() {
for (_url, item) in cal.lock().unwrap().get_items_mut_sync()?.iter_mut() {
match item {
Item::Task(task) => {
match task.completed() {
false => task.set_completion_status(CompletionStatus::Completed(Some(Utc::now()))),
true => task.set_completion_status(CompletionStatus::Uncompleted),
};
n_toggled += 1;
}
Item::Event(_) => {
// Not doing anything with calendar events
},
}
}
}
println!("{} items toggled.", n_toggled);
println!("Syncing...");
provider.sync().await;
println!("Syncing complete.");
Ok(())
}

View File

@ -23,11 +23,11 @@
inkscape:collect="always"
id="linearGradient850-3">
<stop
style="stop-color:#555555;stop-opacity:1"
style="stop-color:#7a7a7a;stop-opacity:1"
offset="0"
id="stop846" />
<stop
style="stop-color:#ffffff;stop-opacity:1"
style="stop-color:#000000;stop-opacity:0;"
offset="1"
id="stop848" />
</linearGradient>
@ -49,10 +49,10 @@
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.7"
inkscape:cx="732.34868"
inkscape:cx="730.92011"
inkscape:cy="461.7807"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
inkscape:current-layer="layer2"
showgrid="false"
inkscape:window-width="2510"
inkscape:window-height="1376"
@ -71,23 +71,10 @@
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="layer5"
inkscape:label="Fond"
style="display:none">
<rect
style="fill:#102335;fill-opacity:1;stroke:#b40f00;stroke-width:0.26499999;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect867"
width="213.55655"
height="212.42261"
x="0"
y="0.37030393" />
</g>
<g
inkscape:label="Fridge"
inkscape:groupmode="layer"

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -27,8 +27,7 @@ const MAIN_FILE: &str = "data.json";
///
/// It automatically updates the content of the folder when dropped (see its `Drop` implementation), but you can also manually call [`Cache::save_to_folder`]
///
/// Most of its functionality is provided by the `CalDavSource` async trait it implements.
/// However, since these functions do not _need_ to be actually async, non-async versions of them are also provided for better convenience. See [`Cache::get_calendar_sync`] for example
/// Most of its methods are part of the `CalDavSource` trait implementation
#[derive(Debug)]
pub struct Cache {
backing_folder: PathBuf,

View File

@ -19,8 +19,7 @@ use crate::mock_behaviour::MockBehaviour;
/// A calendar used by the [`cache`](crate::cache) module
///
/// Most of its functionality is provided by the async traits it implements.
/// However, since these functions do not _need_ to be actually async, non-async versions of them are also provided for better convenience. See [`CachedCalendar::add_item_sync`] for example
/// Most of its methods are part of traits implementations
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CachedCalendar {
name: String,
@ -135,14 +134,6 @@ impl CachedCalendar {
)
}
/// The non-async version of [`Self::get_items_mut`]
pub fn get_items_mut_sync(&mut self) -> Result<HashMap<Url, &mut Item>, Box<dyn Error>> {
Ok(self.items.iter_mut()
.map(|(url, item)| (url.clone(), item))
.collect()
)
}
/// The non-async version of [`Self::get_item_by_url`]
pub fn get_item_by_url_sync<'a>(&'a self, url: &Url) -> Option<&'a Item> {
self.items.get(url)
@ -262,10 +253,6 @@ impl CompleteCalendar for CachedCalendar {
self.get_items_sync()
}
async fn get_items_mut(&mut self) -> Result<HashMap<Url, &mut Item>, Box<dyn Error>> {
self.get_items_mut_sync()
}
async fn get_item_by_url<'a>(&'a self, url: &Url) -> Option<&'a Item> {
self.get_item_by_url_sync(url)
}
@ -327,14 +314,6 @@ impl DavCalendar for CachedCalendar {
Ok(self.items.get(url).cloned())
}
async fn get_items_by_url(&self, urls: &[Url]) -> Result<Vec<Option<Item>>, Box<dyn Error>> {
let mut v = Vec::new();
for url in urls {
v.push(DavCalendar::get_item_by_url(self, url).await?);
}
Ok(v)
}
async fn delete_item(&mut self, item_url: &Url) -> Result<(), Box<dyn Error>> {
#[cfg(feature = "local_calendar_mocks_remote_calendars")]
self.mock_behaviour.as_ref().map_or(Ok(()), |b| b.lock().unwrap().can_delete_item())?;

View File

@ -14,7 +14,6 @@ use crate::item::Item;
use crate::item::VersionTag;
use crate::item::SyncStatus;
use crate::resource::Resource;
use crate::utils::find_elem;
static TASKS_BODY: &str = r#"
<c:calendar-query xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">
@ -29,15 +28,6 @@ static TASKS_BODY: &str = r#"
</c:calendar-query>
"#;
static MULTIGET_BODY_PREFIX: &str = r#"
<c:calendar-multiget xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">
<d:prop>
<c:calendar-data />
</d:prop>
"#;
static MULTIGET_BODY_SUFFIX: &str = r#"
</c:calendar-multiget>
"#;
@ -201,40 +191,6 @@ impl DavCalendar for RemoteCalendar {
Ok(Some(item))
}
async fn get_items_by_url(&self, urls: &[Url]) -> Result<Vec<Option<Item>>, Box<dyn Error>> {
// Build the request body
let mut hrefs = String::new();
for url in urls {
hrefs.push_str(&format!(" <d:href>{}</d:href>\n", url.path()));
}
let body = format!("{}{}{}", MULTIGET_BODY_PREFIX, hrefs, MULTIGET_BODY_SUFFIX);
// Send the request
let xml_replies = crate::client::sub_request_and_extract_elems(&self.resource, "REPORT", body, "response").await?;
// This is supposed to be cached
let version_tags = self.get_item_version_tags().await?;
// Parse the results
let mut results = Vec::new();
for xml_reply in xml_replies {
let href = find_elem(&xml_reply, "href").ok_or("Missing HREF")?.text();
let mut url = self.resource.url().clone();
url.set_path(&href);
let ical_data = find_elem(&xml_reply, "calendar-data").ok_or("Missing calendar-data")?.text();
let vt = match version_tags.get(&url) {
None => return Err(format!("Inconsistent data: {} has no version tag", url).into()),
Some(vt) => vt,
};
let item = crate::ical::parse(&ical_data, url.clone(), SyncStatus::Synced(vt.clone()))?;
results.push(Some(item));
}
Ok(results)
}
async fn delete_item(&mut self, item_url: &Url) -> Result<(), Box<dyn Error>> {
let del_response = reqwest::Client::new()
.delete(item_url.clone())

View File

@ -1,4 +1,4 @@
//! Support for library configuration options
//! Support for compile-time configuration options
use std::sync::{Arc, Mutex};
use once_cell::sync::Lazy;

View File

@ -50,17 +50,8 @@ pub fn parse(content: &str, item_url: Url, sync_status: SyncStatus) -> Result<It
// The property can be specified once, but is not mandatory
// "This property specifies the date and time that the information associated with
// the calendar component was last revised in the calendar store."
// "In the case of an iCalendar object that doesn't specify a "METHOD"
// property [e.g.: VTODO and VEVENT], this property is equivalent to the "LAST-MODIFIED" property".
last_modified = parse_date_time_from_property(&prop.value);
last_modified = parse_date_time_from_property(&prop.value)
},
"LAST-MODIFIED" => {
// The property can be specified once, but is not mandatory
// "This property specifies the date and time that the information associated with
// the calendar component was last revised in the calendar store."
// In practise, for VEVENT and VTODO, this is generally the same value as DTSTAMP.
last_modified = parse_date_time_from_property(&prop.value);
}
"COMPLETED" => {
// The property can be specified once, but is not mandatory
// "This property defines the date and time that a to-do was
@ -123,8 +114,7 @@ pub fn parse(content: &str, item_url: Url, sync_status: SyncStatus) -> Result<It
}
fn parse_date_time(dt: &str) -> Result<DateTime<Utc>, chrono::format::ParseError> {
Utc.datetime_from_str(dt, "%Y%m%dT%H%M%SZ")
.or_else(|_err| Utc.datetime_from_str(dt, "%Y%m%dT%H%M%S") )
Utc.datetime_from_str(dt, "%Y%m%dT%H%M%S")
}
fn parse_date_time_from_property(value: &Option<String>) -> Option<DateTime<Utc>> {

View File

@ -2,7 +2,7 @@
//! CalDAV is described as "Calendaring Extensions to WebDAV" in [RFC 4791](https://datatracker.ietf.org/doc/html/rfc4791) and [RFC 7986](https://datatracker.ietf.org/doc/html/rfc7986) and the underlying iCal format is described at least in [RFC 5545](https://datatracker.ietf.org/doc/html/rfc5545). \
//! This library has been intensivley tested with Nextcloud servers. It should support Owncloud and iCloud as well, since they use the very same CalDAV protocol.
//!
//! This initial implementation only supports TODO events. Thus it can fetch and update a CalDAV-hosted todo-list...just like [sticky notes on a kitchen fridge](https://www.google.com/search?q=kitchen+fridge+todo+list&tbm=isch) would. \
//! This initial implementation only supports TODO events. This it can fetch and update a CalDAV-hosted todo-list...just like [sticky notes on a kitchen fridge](https://www.google.com/search?q=kitchen+fridge+todo+list&tbm=isch) would. \
//! Supporting other items (and especially regular CalDAV calendar events) should be fairly trivial, as it should boil down to adding little logic in iCal files parsing, but any help is appreciated :-)
//!
//! ## Possible uses

View File

@ -6,10 +6,7 @@ use std::error::Error;
use std::collections::HashSet;
use std::marker::PhantomData;
use std::sync::{Arc, Mutex};
use std::fmt::{Display, Formatter};
use url::Url;
use itertools::Itertools;
use crate::traits::{BaseCalendar, CalDavSource, DavCalendar};
use crate::traits::CompleteCalendar;
@ -19,30 +16,6 @@ pub mod sync_progress;
use sync_progress::SyncProgress;
use sync_progress::{FeedbackSender, SyncEvent};
/// How many items will be batched in a single HTTP request when downloading from the server
#[cfg(not(test))]
const DOWNLOAD_BATCH_SIZE: usize = 30;
/// How many items will be batched in a single HTTP request when downloading from the server
#[cfg(test)]
const DOWNLOAD_BATCH_SIZE: usize = 3;
// I am too lazy to actually make `fetch_and_apply` generic over an async closure.
// Let's work around by passing an enum, so that `fetch_and_apply` will know what to do
enum BatchDownloadType {
RemoteAdditions,
RemoteChanges,
}
impl Display for BatchDownloadType {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
match self {
Self::RemoteAdditions => write!(f, "remote additions"),
Self::RemoteChanges => write!(f, "remote changes"),
}
}
}
/// A data source that combines two `CalDavSource`s, which is able to sync both sources.
///
/// Usually, you will only need to use a provider between a server and a local cache, that is to say a [`CalDavProvider`](crate::CalDavProvider), i.e. a `Provider<Cache, CachedCalendar, Client, RemoteCalendar>`. \
@ -186,10 +159,8 @@ where
let cal_name = cal_local.name().to_string();
progress.info(&format!("Syncing calendar {}", cal_name));
progress.reset_counter();
progress.feedback(SyncEvent::InProgress{
calendar: cal_name.clone(),
items_done_already: 0,
details: "started".to_string()
});
@ -205,7 +176,6 @@ where
let remote_items = cal_remote.get_item_version_tags().await?;
progress.feedback(SyncEvent::InProgress{
calendar: cal_name.clone(),
items_done_already: 0,
details: format!("{} remote items", remote_items.len()),
});
@ -301,13 +271,10 @@ where
progress.trace("Committing changes...");
for url_del in local_del {
progress.debug(&format!("> Pushing local deletion {} to the server", url_del));
progress.increment_counter(1);
progress.feedback(SyncEvent::InProgress{
calendar: cal_name.clone(),
items_done_already: progress.counter(),
details: Self::item_name(&cal_local, &url_del).await,
});
match cal_remote.delete_item(&url_del).await {
Err(err) => {
progress.warn(&format!("Unable to delete remote item {}: {}", url_del, err));
@ -323,10 +290,8 @@ where
for url_del in remote_del {
progress.debug(&format!("> Applying remote deletion {} locally", url_del));
progress.increment_counter(1);
progress.feedback(SyncEvent::InProgress{
calendar: cal_name.clone(),
items_done_already: progress.counter(),
details: Self::item_name(&cal_local, &url_del).await,
});
if let Err(err) = cal_local.immediately_delete_item(&url_del).await {
@ -334,29 +299,61 @@ where
}
}
Self::apply_remote_additions(
remote_additions,
&mut *cal_local,
&mut *cal_remote,
progress,
&cal_name
).await;
for url_add in remote_additions {
progress.debug(&format!("> Applying remote addition {} locally", url_add));
progress.feedback(SyncEvent::InProgress{
calendar: cal_name.clone(),
details: Self::item_name(&cal_local, &url_add).await,
});
match cal_remote.get_item_by_url(&url_add).await {
Err(err) => {
progress.warn(&format!("Unable to get remote item {}: {}. Skipping it.", url_add, err));
continue;
},
Ok(item) => match item {
None => {
progress.error(&format!("Inconsistency: new item {} has vanished from the remote end", url_add));
continue;
},
Some(new_item) => {
if let Err(err) = cal_local.add_item(new_item.clone()).await {
progress.error(&format!("Not able to add item {} to local calendar: {}", url_add, err));
}
},
},
}
}
Self::apply_remote_changes(
remote_changes,
&mut *cal_local,
&mut *cal_remote,
progress,
&cal_name
).await;
for url_change in remote_changes {
progress.debug(&format!("> Applying remote change {} locally", url_change));
progress.feedback(SyncEvent::InProgress{
calendar: cal_name.clone(),
details: Self::item_name(&cal_local, &url_change).await,
});
match cal_remote.get_item_by_url(&url_change).await {
Err(err) => {
progress.warn(&format!("Unable to get remote item {}: {}. Skipping it", url_change, err));
continue;
},
Ok(item) => match item {
None => {
progress.error(&format!("Inconsistency: modified item {} has vanished from the remote end", url_change));
continue;
},
Some(item) => {
if let Err(err) = cal_local.update_item(item.clone()).await {
progress.error(&format!("Unable to update item {} in local calendar: {}", url_change, err));
}
},
}
}
}
for url_add in local_additions {
progress.debug(&format!("> Pushing local addition {} to the server", url_add));
progress.increment_counter(1);
progress.feedback(SyncEvent::InProgress{
calendar: cal_name.clone(),
items_done_already: progress.counter(),
details: Self::item_name(&cal_local, &url_add).await,
});
match cal_local.get_item_by_url_mut(&url_add).await {
@ -378,10 +375,8 @@ where
for url_change in local_changes {
progress.debug(&format!("> Pushing local change {} to the server", url_change));
progress.increment_counter(1);
progress.feedback(SyncEvent::InProgress{
calendar: cal_name.clone(),
items_done_already: progress.counter(),
details: Self::item_name(&cal_local, &url_change).await,
});
match cal_local.get_item_by_url_mut(&url_change).await {
@ -409,78 +404,6 @@ where
cal.get_item_by_url(url).await.map(|item| item.name()).unwrap_or_default().to_string()
}
async fn apply_remote_additions(
mut remote_additions: HashSet<Url>,
cal_local: &mut T,
cal_remote: &mut U,
progress: &mut SyncProgress,
cal_name: &str
) {
for batch in remote_additions.drain().chunks(DOWNLOAD_BATCH_SIZE).into_iter() {
Self::fetch_batch_and_apply(BatchDownloadType::RemoteAdditions, batch, cal_local, cal_remote, progress, cal_name).await;
}
}
async fn apply_remote_changes(
mut remote_changes: HashSet<Url>,
cal_local: &mut T,
cal_remote: &mut U,
progress: &mut SyncProgress,
cal_name: &str
) {
for batch in remote_changes.drain().chunks(DOWNLOAD_BATCH_SIZE).into_iter() {
Self::fetch_batch_and_apply(BatchDownloadType::RemoteChanges, batch, cal_local, cal_remote, progress, cal_name).await;
}
}
async fn fetch_batch_and_apply<I: Iterator<Item = Url>>(
batch_type: BatchDownloadType,
remote_additions: I,
cal_local: &mut T,
cal_remote: &mut U,
progress: &mut SyncProgress,
cal_name: &str
) {
progress.debug(&format!("> Applying a batch of {} locally", batch_type) /* too bad Chunks does not implement ExactSizeIterator, that could provide useful debug info. See https://github.com/rust-itertools/itertools/issues/171 */);
let list_of_additions: Vec<Url> = remote_additions.map(|url| url.clone()).collect();
match cal_remote.get_items_by_url(&list_of_additions).await {
Err(err) => {
progress.warn(&format!("Unable to get the batch of {} {:?}: {}. Skipping them.", batch_type, list_of_additions, err));
},
Ok(items) => {
for item in items {
match item {
None => {
progress.error(&format!("Inconsistency: an item from the batch has vanished from the remote end"));
continue;
},
Some(new_item) => {
let local_update_result = match batch_type {
BatchDownloadType::RemoteAdditions => cal_local.add_item(new_item.clone()).await,
BatchDownloadType::RemoteChanges => cal_local.update_item(new_item.clone()).await,
};
if let Err(err) = local_update_result {
progress.error(&format!("Not able to add item {} to local calendar: {}", new_item.url(), err));
}
},
}
}
// Notifying every item at the same time would not make sense. Let's notify only one of them
let one_item_name = match list_of_additions.get(0) {
Some(url) => Self::item_name(&cal_local, &url).await,
None => String::from("<unable to get the name of the first batched item>"),
};
progress.increment_counter(list_of_additions.len());
progress.feedback(SyncEvent::InProgress{
calendar: cal_name.to_string(),
items_done_already: progress.counter(),
details: one_item_name,
});
},
}
}
}

View File

@ -10,7 +10,7 @@ pub enum SyncEvent {
/// Sync has just started but no calendar is handled yet
Started,
/// Sync is in progress.
InProgress{ calendar: String, items_done_already: usize, details: String},
InProgress{ calendar: String, details: String},
/// Sync is finished
Finished{ success: bool },
}
@ -20,7 +20,7 @@ impl Display for SyncEvent {
match self {
SyncEvent::NotStarted => write!(f, "Not started"),
SyncEvent::Started => write!(f, "Sync has started..."),
SyncEvent::InProgress{calendar, items_done_already, details} => write!(f, "{} [{}/?] {}...", calendar, items_done_already, details),
SyncEvent::InProgress{calendar, details} => write!(f, "[{}] {}...", calendar, details),
SyncEvent::Finished{success} => match success {
true => write!(f, "Sync successfully finished"),
false => write!(f, "Sync finished with errors"),
@ -53,33 +53,16 @@ pub fn feedback_channel() -> (FeedbackSender, FeedbackReceiver) {
/// A structure that tracks the progression and the errors that happen during a sync
pub struct SyncProgress {
n_errors: u32,
feedback_channel: Option<FeedbackSender>,
counter: usize,
feedback_channel: Option<FeedbackSender>
}
impl SyncProgress {
pub fn new() -> Self {
Self { n_errors: 0, feedback_channel: None, counter: 0 }
Self { n_errors: 0, feedback_channel: None }
}
pub fn new_with_feedback_channel(channel: FeedbackSender) -> Self {
Self { n_errors: 0, feedback_channel: Some(channel), counter: 0 }
Self { n_errors: 0, feedback_channel: Some(channel) }
}
/// Reset the user-info counter
pub fn reset_counter(&mut self) {
self.counter = 0;
}
/// Increments the user-info counter.
pub fn increment_counter(&mut self, increment: usize) {
self.counter += increment;
}
/// Retrieves the current user-info counter.
/// This counts "arbitrary things", that's provided as a convenience but it is not used internally
/// (e.g. that can be used to keep track of the items handled for the current calendar)
pub fn counter(&self) -> usize {
self.counter
}
pub fn is_success(&self) -> bool {
self.n_errors == 0

View File

@ -83,10 +83,6 @@ pub trait DavCalendar : BaseCalendar {
/// Returns a particular item
async fn get_item_by_url(&self, url: &Url) -> Result<Option<Item>, Box<dyn Error>>;
/// Returns a set of items.
/// This is usually faster than calling multiple consecutive [`DavCalendar::get_item_by_url`], since it only issues one HTTP request.
async fn get_items_by_url(&self, urls: &[Url]) -> Result<Vec<Option<Item>>, Box<dyn Error>>;
/// Delete an item
async fn delete_item(&mut self, item_url: &Url) -> Result<(), Box<dyn Error>>;
@ -119,9 +115,6 @@ pub trait CompleteCalendar : BaseCalendar {
/// Returns all items that this calendar contains
async fn get_items(&self) -> Result<HashMap<Url, &Item>, Box<dyn Error>>;
/// Returns all items that this calendar contains
async fn get_items_mut(&mut self) -> Result<HashMap<Url, &mut Item>, Box<dyn Error>>;
/// Returns a particular item
async fn get_item_by_url<'a>(&'a self, url: &Url) -> Option<&'a Item>;

View File

@ -1,4 +1,4 @@
//! Some utility functions
///! Some utility functions
use std::collections::{HashMap, HashSet};
use std::sync::{Arc, Mutex};

View File

@ -694,13 +694,13 @@ async fn get_or_insert_calendar(source: &mut Cache, url: &Url)
None => {
let new_name = format!("Test calendar for URL {}", url);
let supported_components = SupportedComponents::TODO;
let color = csscolorparser::parse("#ff8000").unwrap(); // TODO: we should rather have specific colors, depending on the calendars
let color = csscolorparser::parse("#ff8000"); // TODO: we should rather have specific colors, depending on the calendars
source.create_calendar(
url.clone(),
new_name.to_string(),
supported_components,
Some(color),
None,
).await
}
}

View File

@ -145,7 +145,7 @@ impl TestFlavour {
scenarii: scenarii::scenarii_basic(),
mock_behaviour: Arc::new(Mutex::new(MockBehaviour{
add_item_behaviour: (2,3),
get_item_by_url_behaviour: (1,12),
get_item_by_url_behaviour: (1,4),
..MockBehaviour::default()
})),
}