Compare commits

..

10 commits

Author SHA1 Message Date
daladim
2281c34529 Version 0.4.0
Some checks are pending
Rust / build (push) Waiting to run
2022-01-19 09:22:24 +01:00
daladim
c36c06ba94 Upgrade dependencies 2022-01-19 09:22:24 +01:00
daladim
fd216ff7c3 [doc] improvements and rewordings 2022-01-19 09:17:09 +01:00
daladim
511f2123e6 [minor] Examples have different data folders 2022-01-19 09:16:25 +01:00
daladim
7cc1e778bb Added a progress counter 2021-12-24 15:36:34 +01:00
daladim
7b13d74edc [optim] Download 30 changed items at once in a single HTTP request from the server 2021-12-24 14:56:23 +01:00
daladim
159b6199fa Poor man's generic function to work around passing an async closure 2021-12-24 14:56:22 +01:00
daladim
313f2ed0e9 [minor] Unused variable 2021-12-24 14:56:22 +01:00
daladim
6c64bcce8e [optim] Download 30 added items at once in a single HTTP request from the server 2021-12-24 14:56:22 +01:00
daladim
56484a6d4d Split a function 2021-12-24 11:47:56 +01:00
13 changed files with 298 additions and 198 deletions

264
Cargo.lock generated
View file

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

View file

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

View file

@ -17,6 +17,8 @@ mod shared;
use shared::initial_sync; use shared::initial_sync;
use shared::{URL, USERNAME, EXAMPLE_EXISTING_CALENDAR_URL, EXAMPLE_CREATED_CALENDAR_URL}; use shared::{URL, USERNAME, EXAMPLE_EXISTING_CALENDAR_URL, EXAMPLE_CREATED_CALENDAR_URL};
const CACHE_FOLDER: &str = "test_cache/provider_sync";
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
@ -33,7 +35,7 @@ async fn main() {
println!(" * EXAMPLE_CREATED_CALENDAR_URL = {}", EXAMPLE_CREATED_CALENDAR_URL); println!(" * EXAMPLE_CREATED_CALENDAR_URL = {}", EXAMPLE_CREATED_CALENDAR_URL);
pause(); pause();
let mut provider = initial_sync().await; let mut provider = initial_sync(CACHE_FOLDER).await;
add_items_and_sync_again(&mut provider).await; add_items_and_sync_again(&mut provider).await;
} }

View file

@ -14,16 +14,14 @@ 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_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/"; pub const EXAMPLE_CREATED_CALENDAR_URL: &str = "https://my.server.com/remote.php/dav/calendars/john/a_calendar_that_we_have_created/";
const CACHE_FOLDER: &str = "test_cache/provider_sync";
fn main() { fn main() {
panic!("This file is not supposed to be executed"); panic!("This file is not supposed to be executed");
} }
/// Initializes a Provider, and run an initial sync from the server /// Initializes a Provider, and run an initial sync from the server
pub async fn initial_sync() -> CalDavProvider { pub async fn initial_sync(cache_folder: &str) -> CalDavProvider {
let cache_path = Path::new(CACHE_FOLDER); let cache_path = Path::new(cache_folder);
let client = Client::new(URL, USERNAME, PASSWORD).unwrap(); let client = Client::new(URL, USERNAME, PASSWORD).unwrap();
let cache = match Cache::from_folder(&cache_path) { let cache = match Cache::from_folder(&cache_path) {

View file

@ -14,6 +14,7 @@ mod shared;
use shared::initial_sync; use shared::initial_sync;
use shared::{URL, USERNAME}; use shared::{URL, USERNAME};
const CACHE_FOLDER: &str = "test_cache/toggle_completion";
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
@ -28,7 +29,7 @@ async fn main() {
println!(" * USERNAME = {}", USERNAME); println!(" * USERNAME = {}", USERNAME);
pause(); pause();
let mut provider = initial_sync().await; let mut provider = initial_sync(CACHE_FOLDER).await;
toggle_all_tasks_and_sync_again(&mut provider).await.unwrap(); toggle_all_tasks_and_sync_again(&mut provider).await.unwrap();
} }

View file

@ -27,7 +27,8 @@ 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`] /// 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 methods are part of the `CalDavSource` trait implementation /// 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
#[derive(Debug)] #[derive(Debug)]
pub struct Cache { pub struct Cache {
backing_folder: PathBuf, backing_folder: PathBuf,

View file

@ -19,7 +19,8 @@ use crate::mock_behaviour::MockBehaviour;
/// A calendar used by the [`cache`](crate::cache) module /// A calendar used by the [`cache`](crate::cache) module
/// ///
/// Most of its methods are part of traits implementations /// 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
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CachedCalendar { pub struct CachedCalendar {
name: String, name: String,

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). \ //! 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 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. 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. \ //! 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. \
//! 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 :-) //! 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 //! ## Possible uses

View file

@ -6,7 +6,10 @@ use std::error::Error;
use std::collections::HashSet; use std::collections::HashSet;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::fmt::{Display, Formatter};
use url::Url; use url::Url;
use itertools::Itertools;
use crate::traits::{BaseCalendar, CalDavSource, DavCalendar}; use crate::traits::{BaseCalendar, CalDavSource, DavCalendar};
use crate::traits::CompleteCalendar; use crate::traits::CompleteCalendar;
@ -16,6 +19,30 @@ pub mod sync_progress;
use sync_progress::SyncProgress; use sync_progress::SyncProgress;
use sync_progress::{FeedbackSender, SyncEvent}; 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. /// 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>`. \ /// 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>`. \
@ -159,8 +186,10 @@ where
let cal_name = cal_local.name().to_string(); let cal_name = cal_local.name().to_string();
progress.info(&format!("Syncing calendar {}", cal_name)); progress.info(&format!("Syncing calendar {}", cal_name));
progress.reset_counter();
progress.feedback(SyncEvent::InProgress{ progress.feedback(SyncEvent::InProgress{
calendar: cal_name.clone(), calendar: cal_name.clone(),
items_done_already: 0,
details: "started".to_string() details: "started".to_string()
}); });
@ -176,6 +205,7 @@ where
let remote_items = cal_remote.get_item_version_tags().await?; let remote_items = cal_remote.get_item_version_tags().await?;
progress.feedback(SyncEvent::InProgress{ progress.feedback(SyncEvent::InProgress{
calendar: cal_name.clone(), calendar: cal_name.clone(),
items_done_already: 0,
details: format!("{} remote items", remote_items.len()), details: format!("{} remote items", remote_items.len()),
}); });
@ -271,10 +301,13 @@ where
progress.trace("Committing changes..."); progress.trace("Committing changes...");
for url_del in local_del { for url_del in local_del {
progress.debug(&format!("> Pushing local deletion {} to the server", url_del)); progress.debug(&format!("> Pushing local deletion {} to the server", url_del));
progress.increment_counter(1);
progress.feedback(SyncEvent::InProgress{ progress.feedback(SyncEvent::InProgress{
calendar: cal_name.clone(), calendar: cal_name.clone(),
items_done_already: progress.counter(),
details: Self::item_name(&cal_local, &url_del).await, details: Self::item_name(&cal_local, &url_del).await,
}); });
match cal_remote.delete_item(&url_del).await { match cal_remote.delete_item(&url_del).await {
Err(err) => { Err(err) => {
progress.warn(&format!("Unable to delete remote item {}: {}", url_del, err)); progress.warn(&format!("Unable to delete remote item {}: {}", url_del, err));
@ -290,8 +323,10 @@ where
for url_del in remote_del { for url_del in remote_del {
progress.debug(&format!("> Applying remote deletion {} locally", url_del)); progress.debug(&format!("> Applying remote deletion {} locally", url_del));
progress.increment_counter(1);
progress.feedback(SyncEvent::InProgress{ progress.feedback(SyncEvent::InProgress{
calendar: cal_name.clone(), calendar: cal_name.clone(),
items_done_already: progress.counter(),
details: Self::item_name(&cal_local, &url_del).await, details: Self::item_name(&cal_local, &url_del).await,
}); });
if let Err(err) = cal_local.immediately_delete_item(&url_del).await { if let Err(err) = cal_local.immediately_delete_item(&url_del).await {
@ -299,61 +334,29 @@ where
} }
} }
for url_add in remote_additions { Self::apply_remote_additions(
progress.debug(&format!("> Applying remote addition {} locally", url_add)); remote_additions,
progress.feedback(SyncEvent::InProgress{ &mut *cal_local,
calendar: cal_name.clone(), &mut *cal_remote,
details: Self::item_name(&cal_local, &url_add).await, progress,
}); &cal_name
match cal_remote.get_item_by_url(&url_add).await { ).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));
}
},
},
}
}
for url_change in remote_changes { Self::apply_remote_changes(
progress.debug(&format!("> Applying remote change {} locally", url_change)); remote_changes,
progress.feedback(SyncEvent::InProgress{ &mut *cal_local,
calendar: cal_name.clone(), &mut *cal_remote,
details: Self::item_name(&cal_local, &url_change).await, progress,
}); &cal_name
match cal_remote.get_item_by_url(&url_change).await { ).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 { for url_add in local_additions {
progress.debug(&format!("> Pushing local addition {} to the server", url_add)); progress.debug(&format!("> Pushing local addition {} to the server", url_add));
progress.increment_counter(1);
progress.feedback(SyncEvent::InProgress{ progress.feedback(SyncEvent::InProgress{
calendar: cal_name.clone(), calendar: cal_name.clone(),
items_done_already: progress.counter(),
details: Self::item_name(&cal_local, &url_add).await, details: Self::item_name(&cal_local, &url_add).await,
}); });
match cal_local.get_item_by_url_mut(&url_add).await { match cal_local.get_item_by_url_mut(&url_add).await {
@ -375,8 +378,10 @@ where
for url_change in local_changes { for url_change in local_changes {
progress.debug(&format!("> Pushing local change {} to the server", url_change)); progress.debug(&format!("> Pushing local change {} to the server", url_change));
progress.increment_counter(1);
progress.feedback(SyncEvent::InProgress{ progress.feedback(SyncEvent::InProgress{
calendar: cal_name.clone(), calendar: cal_name.clone(),
items_done_already: progress.counter(),
details: Self::item_name(&cal_local, &url_change).await, details: Self::item_name(&cal_local, &url_change).await,
}); });
match cal_local.get_item_by_url_mut(&url_change).await { match cal_local.get_item_by_url_mut(&url_change).await {
@ -404,6 +409,78 @@ where
cal.get_item_by_url(url).await.map(|item| item.name()).unwrap_or_default().to_string() 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 /// Sync has just started but no calendar is handled yet
Started, Started,
/// Sync is in progress. /// Sync is in progress.
InProgress{ calendar: String, details: String}, InProgress{ calendar: String, items_done_already: usize, details: String},
/// Sync is finished /// Sync is finished
Finished{ success: bool }, Finished{ success: bool },
} }
@ -20,7 +20,7 @@ impl Display for SyncEvent {
match self { match self {
SyncEvent::NotStarted => write!(f, "Not started"), SyncEvent::NotStarted => write!(f, "Not started"),
SyncEvent::Started => write!(f, "Sync has started..."), SyncEvent::Started => write!(f, "Sync has started..."),
SyncEvent::InProgress{calendar, details} => write!(f, "[{}] {}...", calendar, details), SyncEvent::InProgress{calendar, items_done_already, details} => write!(f, "{} [{}/?] {}...", calendar, items_done_already, details),
SyncEvent::Finished{success} => match success { SyncEvent::Finished{success} => match success {
true => write!(f, "Sync successfully finished"), true => write!(f, "Sync successfully finished"),
false => write!(f, "Sync finished with errors"), false => write!(f, "Sync finished with errors"),
@ -53,16 +53,33 @@ pub fn feedback_channel() -> (FeedbackSender, FeedbackReceiver) {
/// A structure that tracks the progression and the errors that happen during a sync /// A structure that tracks the progression and the errors that happen during a sync
pub struct SyncProgress { pub struct SyncProgress {
n_errors: u32, n_errors: u32,
feedback_channel: Option<FeedbackSender> feedback_channel: Option<FeedbackSender>,
counter: usize,
} }
impl SyncProgress { impl SyncProgress {
pub fn new() -> Self { pub fn new() -> Self {
Self { n_errors: 0, feedback_channel: None } Self { n_errors: 0, feedback_channel: None, counter: 0 }
} }
pub fn new_with_feedback_channel(channel: FeedbackSender) -> Self { pub fn new_with_feedback_channel(channel: FeedbackSender) -> Self {
Self { n_errors: 0, feedback_channel: Some(channel) } Self { n_errors: 0, feedback_channel: Some(channel), counter: 0 }
} }
/// 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 { pub fn is_success(&self) -> bool {
self.n_errors == 0 self.n_errors == 0

View file

@ -84,7 +84,7 @@ pub trait DavCalendar : BaseCalendar {
async fn get_item_by_url(&self, url: &Url) -> Result<Option<Item>, Box<dyn Error>>; async fn get_item_by_url(&self, url: &Url) -> Result<Option<Item>, Box<dyn Error>>;
/// Returns a set of items. /// Returns a set of items.
/// This is usually faster than calling multiple consecutive [`get_item_by_url`], since it only issues one HTTP request. /// 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>>; async fn get_items_by_url(&self, urls: &[Url]) -> Result<Vec<Option<Item>>, Box<dyn Error>>;
/// Delete an item /// Delete an item

View file

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

View file

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