Take the pain out of keeping all your calendars together

feat: add ical calendar merging

A key function of calpoll is taking multiple .ics calendars and merging
them together. This adds basic ical merging as follows:

- "Calendars" are in a database
- Calendars have multiple "subscriptions" (ical subscription URLs)
- When getting events from a calendar, we fetch all subscriptions, parse
them and add everything to one big ical file
- We expose this over http so this can itself be used as an ical
subscription URL

The reason we do it like this rather than, say, having an endpoint to
/merge/ calendars and be done with it is we want this to be an
application which you can share URLs out of even if you don't want to
make the subscription URLs of each underlying calendar public (e.g.
Google Calendar private .ics subscription links). We would also like the
ability to add support for more calendar sources in the future -
particularly, say, I need support for WebDav calendars for Stalwart.

---

You can test this change by using the merge-holidays-moon-phases.sql
queries in test-data/ to set up a test calendar like so:

$ cat test-data/merge-holidays-moon-phases.sql | psql $DATABASE_URL
$ curl http://127.0.0.1:3000/calendar/32da8949-b21c-469d-a2bc-f5763af186c6
BEGIN:VCALENDAR
VERSION:2.0
PRODID:ICALENDAR-RS
CALSCALE:GREGORIAN
BEGIN:VEVENT
CLASS:PUBLIC
CREATED:20240522T091304Z
DESCRIPTION:Public holiday
[...]

$ curl http://127.0.0.1:3000/calendar/00069420-74d2-4ba8-85d6-4fc679810c02
BEGIN:VCALENDAR
VERSION:2.0
PRODID:ICALENDAR-RS
CALSCALE:GREGORIAN
END:VCALENDAR

$ curl http://127.0.0.1:3000/calendar/non-uuid
Invalid URL: Cannot parse `id` with value `non-uuid`: UUID parsing
failed: invalid character: expected an optional prefix of `urn:uuid:`
followed by [0-9a-fA-F-], found `n` at 1

---

For these tests to work, you'll need to have $DATABASE_URL set to your
database, and you'll have to be running the code. The easiest way to do
that is with devenv and the nilla shell provided here...

$ devenv up
[...wait for TUI showing postgres running...]

[...in a separate terminal...]
$ nilla shell
nilla$ sqlx database reset
nilla$ cat test-data/merge-holidays-moon-phases.sql | psql $DATABASE_URL
nilla$ cargo leptos watch

a.starrysky.fyi 7c4f8b3f 9b78d4f8

verified
+1
.gitignore
··· 5 .sass-cache 6 /debug 7 /target
··· 5 .sass-cache 6 /debug 7 /target 8 + /test-data/private-*
+672 -4
Cargo.lock
··· 18 checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" 19 20 [[package]] 21 name = "any_spawner" 22 version = "0.3.0" 23 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 228 name = "calpoll" 229 version = "0.1.0" 230 dependencies = [ 231 "axum", 232 "console_error_panic_hook", 233 "leptos", 234 "leptos_axum", 235 "leptos_meta", 236 "leptos_router", 237 "sqlx", 238 "tokio", 239 "wasm-bindgen", 240 ] 241 ··· 262 checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" 263 264 [[package]] 265 name = "codee" 266 version = "0.3.3" 267 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 463 ] 464 465 [[package]] 466 name = "derive-where" 467 version = "1.6.0" 468 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 767 checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" 768 dependencies = [ 769 "cfg-if", 770 "libc", 771 "wasi", 772 ] 773 774 [[package]] ··· 824 version = "1.3.0" 825 source = "registry+https://github.com/rust-lang/crates.io-index" 826 checksum = "17e2ac29387b1aa07a1e448f7bb4f35b500787971e965b02842b900afa5c8f6f" 827 828 [[package]] 829 name = "hashbrown" ··· 989 "bytes", 990 "futures-channel", 991 "futures-core", 992 "http", 993 "http-body", 994 "httparse", ··· 998 "pin-utils", 999 "smallvec", 1000 "tokio", 1001 ] 1002 1003 [[package]] ··· 1006 source = "registry+https://github.com/rust-lang/crates.io-index" 1007 checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" 1008 dependencies = [ 1009 "bytes", 1010 "futures-core", 1011 "http", 1012 "http-body", 1013 "hyper", 1014 "pin-project-lite", 1015 "tokio", 1016 "tower-service", 1017 ] 1018 1019 [[package]] ··· 1149 ] 1150 1151 [[package]] 1152 name = "itertools" 1153 version = "0.14.0" 1154 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1471 checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" 1472 1473 [[package]] 1474 name = "manyhow" 1475 version = "0.11.4" 1476 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1583 checksum = "60993920e071b0c9b66f14e2b32740a4e27ffc82854dcd72035887f336a09a28" 1584 1585 [[package]] 1586 name = "num-bigint-dig" 1587 version = "0.8.4" 1588 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1598 "smallvec", 1599 "zeroize", 1600 ] 1601 1602 [[package]] 1603 name = "num-integer" ··· 1731 "libc", 1732 "redox_syscall", 1733 "smallvec", 1734 - "windows-link", 1735 ] 1736 1737 [[package]] ··· 1760 version = "2.3.2" 1761 source = "registry+https://github.com/rust-lang/crates.io-index" 1762 checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" 1763 1764 [[package]] 1765 name = "pin-project" ··· 1830 ] 1831 1832 [[package]] 1833 name = "ppv-lite86" 1834 version = "0.2.21" 1835 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1904 ] 1905 1906 [[package]] 1907 name = "quote" 1908 version = "1.0.41" 1909 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2091 checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" 2092 2093 [[package]] 2094 name = "rsa" 2095 version = "0.9.8" 2096 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2154 ] 2155 2156 [[package]] 2157 name = "rustversion" 2158 version = "1.0.22" 2159 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2415 "digest", 2416 "rand_core 0.6.4", 2417 ] 2418 2419 [[package]] 2420 name = "slab" ··· 2506 "native-tls", 2507 "once_cell", 2508 "percent-encoding", 2509 "serde", 2510 "serde_json", 2511 "sha2", ··· 2516 "tracing", 2517 "url", 2518 "uuid", 2519 ] 2520 2521 [[package]] ··· 2713 version = "1.0.2" 2714 source = "registry+https://github.com/rust-lang/crates.io-index" 2715 checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" 2716 2717 [[package]] 2718 name = "synstructure" ··· 2726 ] 2727 2728 [[package]] 2729 name = "tachys" 2730 version = "0.2.10" 2731 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2822 ] 2823 2824 [[package]] 2825 name = "tinystr" 2826 version = "0.8.1" 2827 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2873 ] 2874 2875 [[package]] 2876 name = "tokio-stream" 2877 version = "0.1.17" 2878 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2970 "http-body-util", 2971 "http-range-header", 2972 "httpdate", 2973 "mime", 2974 "mime_guess", 2975 "percent-encoding", 2976 "pin-project-lite", 2977 "tokio", 2978 "tokio-util", 2979 "tower-layer", 2980 "tower-service", 2981 "tracing", ··· 3024 dependencies = [ 3025 "once_cell", 3026 ] 3027 3028 [[package]] 3029 name = "tungstenite" ··· 3114 checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" 3115 3116 [[package]] 3117 name = "url" 3118 version = "2.5.7" 3119 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3151 dependencies = [ 3152 "getrandom 0.3.4", 3153 "js-sys", 3154 "wasm-bindgen", 3155 ] 3156 ··· 3174 dependencies = [ 3175 "same-file", 3176 "winapi-util", 3177 ] 3178 3179 [[package]] ··· 3317 ] 3318 3319 [[package]] 3320 name = "whoami" 3321 version = "1.6.1" 3322 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3334 dependencies = [ 3335 "windows-sys 0.61.2", 3336 ] 3337 3338 [[package]] 3339 name = "windows-link" ··· 3342 checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" 3343 3344 [[package]] 3345 name = "windows-sys" 3346 version = "0.48.0" 3347 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3352 3353 [[package]] 3354 name = "windows-sys" 3355 version = "0.60.2" 3356 source = "registry+https://github.com/rust-lang/crates.io-index" 3357 checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" ··· 3365 source = "registry+https://github.com/rust-lang/crates.io-index" 3366 checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" 3367 dependencies = [ 3368 - "windows-link", 3369 ] 3370 3371 [[package]] ··· 3385 3386 [[package]] 3387 name = "windows-targets" 3388 version = "0.53.5" 3389 source = "registry+https://github.com/rust-lang/crates.io-index" 3390 checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" 3391 dependencies = [ 3392 - "windows-link", 3393 "windows_aarch64_gnullvm 0.53.1", 3394 "windows_aarch64_msvc 0.53.1", 3395 "windows_i686_gnu 0.53.1", 3396 - "windows_i686_gnullvm", 3397 "windows_i686_msvc 0.53.1", 3398 "windows_x86_64_gnu 0.53.1", 3399 "windows_x86_64_gnullvm 0.53.1", ··· 3405 version = "0.48.5" 3406 source = "registry+https://github.com/rust-lang/crates.io-index" 3407 checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 3408 3409 [[package]] 3410 name = "windows_aarch64_gnullvm" ··· 3420 3421 [[package]] 3422 name = "windows_aarch64_msvc" 3423 version = "0.53.1" 3424 source = "registry+https://github.com/rust-lang/crates.io-index" 3425 checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" ··· 3432 3433 [[package]] 3434 name = "windows_i686_gnu" 3435 version = "0.53.1" 3436 source = "registry+https://github.com/rust-lang/crates.io-index" 3437 checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" 3438 3439 [[package]] 3440 name = "windows_i686_gnullvm" ··· 3450 3451 [[package]] 3452 name = "windows_i686_msvc" 3453 version = "0.53.1" 3454 source = "registry+https://github.com/rust-lang/crates.io-index" 3455 checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" ··· 3462 3463 [[package]] 3464 name = "windows_x86_64_gnu" 3465 version = "0.53.1" 3466 source = "registry+https://github.com/rust-lang/crates.io-index" 3467 checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" ··· 3474 3475 [[package]] 3476 name = "windows_x86_64_gnullvm" 3477 version = "0.53.1" 3478 source = "registry+https://github.com/rust-lang/crates.io-index" 3479 checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" ··· 3483 version = "0.48.5" 3484 source = "registry+https://github.com/rust-lang/crates.io-index" 3485 checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 3486 3487 [[package]] 3488 name = "windows_x86_64_msvc"
··· 18 checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" 19 20 [[package]] 21 + name = "android_system_properties" 22 + version = "0.1.5" 23 + source = "registry+https://github.com/rust-lang/crates.io-index" 24 + checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 25 + dependencies = [ 26 + "libc", 27 + ] 28 + 29 + [[package]] 30 name = "any_spawner" 31 version = "0.3.0" 32 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 237 name = "calpoll" 238 version = "0.1.0" 239 dependencies = [ 240 + "anyhow", 241 "axum", 242 "console_error_panic_hook", 243 + "icalendar", 244 "leptos", 245 "leptos_axum", 246 "leptos_meta", 247 "leptos_router", 248 + "reqwest", 249 "sqlx", 250 "tokio", 251 + "uuid", 252 "wasm-bindgen", 253 ] 254 ··· 275 checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" 276 277 [[package]] 278 + name = "cfg_aliases" 279 + version = "0.2.1" 280 + source = "registry+https://github.com/rust-lang/crates.io-index" 281 + checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" 282 + 283 + [[package]] 284 + name = "chrono" 285 + version = "0.4.42" 286 + source = "registry+https://github.com/rust-lang/crates.io-index" 287 + checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" 288 + dependencies = [ 289 + "iana-time-zone", 290 + "js-sys", 291 + "num-traits", 292 + "wasm-bindgen", 293 + "windows-link 0.2.1", 294 + ] 295 + 296 + [[package]] 297 + name = "chrono-tz" 298 + version = "0.10.4" 299 + source = "registry+https://github.com/rust-lang/crates.io-index" 300 + checksum = "a6139a8597ed92cf816dfb33f5dd6cf0bb93a6adc938f11039f371bc5bcd26c3" 301 + dependencies = [ 302 + "chrono", 303 + "phf", 304 + ] 305 + 306 + [[package]] 307 name = "codee" 308 version = "0.3.3" 309 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 505 ] 506 507 [[package]] 508 + name = "deranged" 509 + version = "0.5.4" 510 + source = "registry+https://github.com/rust-lang/crates.io-index" 511 + checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" 512 + dependencies = [ 513 + "powerfmt", 514 + ] 515 + 516 + [[package]] 517 name = "derive-where" 518 version = "1.6.0" 519 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 818 checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" 819 dependencies = [ 820 "cfg-if", 821 + "js-sys", 822 "libc", 823 "wasi", 824 + "wasm-bindgen", 825 ] 826 827 [[package]] ··· 877 version = "1.3.0" 878 source = "registry+https://github.com/rust-lang/crates.io-index" 879 checksum = "17e2ac29387b1aa07a1e448f7bb4f35b500787971e965b02842b900afa5c8f6f" 880 + 881 + [[package]] 882 + name = "h2" 883 + version = "0.4.12" 884 + source = "registry+https://github.com/rust-lang/crates.io-index" 885 + checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" 886 + dependencies = [ 887 + "atomic-waker", 888 + "bytes", 889 + "fnv", 890 + "futures-core", 891 + "futures-sink", 892 + "http", 893 + "indexmap", 894 + "slab", 895 + "tokio", 896 + "tokio-util", 897 + "tracing", 898 + ] 899 900 [[package]] 901 name = "hashbrown" ··· 1061 "bytes", 1062 "futures-channel", 1063 "futures-core", 1064 + "h2", 1065 "http", 1066 "http-body", 1067 "httparse", ··· 1071 "pin-utils", 1072 "smallvec", 1073 "tokio", 1074 + "want", 1075 + ] 1076 + 1077 + [[package]] 1078 + name = "hyper-rustls" 1079 + version = "0.27.7" 1080 + source = "registry+https://github.com/rust-lang/crates.io-index" 1081 + checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" 1082 + dependencies = [ 1083 + "http", 1084 + "hyper", 1085 + "hyper-util", 1086 + "rustls", 1087 + "rustls-pki-types", 1088 + "tokio", 1089 + "tokio-rustls", 1090 + "tower-service", 1091 + "webpki-roots 1.0.3", 1092 + ] 1093 + 1094 + [[package]] 1095 + name = "hyper-tls" 1096 + version = "0.6.0" 1097 + source = "registry+https://github.com/rust-lang/crates.io-index" 1098 + checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" 1099 + dependencies = [ 1100 + "bytes", 1101 + "http-body-util", 1102 + "hyper", 1103 + "hyper-util", 1104 + "native-tls", 1105 + "tokio", 1106 + "tokio-native-tls", 1107 + "tower-service", 1108 ] 1109 1110 [[package]] ··· 1113 source = "registry+https://github.com/rust-lang/crates.io-index" 1114 checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" 1115 dependencies = [ 1116 + "base64", 1117 "bytes", 1118 + "futures-channel", 1119 "futures-core", 1120 + "futures-util", 1121 "http", 1122 "http-body", 1123 "hyper", 1124 + "ipnet", 1125 + "libc", 1126 + "percent-encoding", 1127 "pin-project-lite", 1128 + "socket2", 1129 + "system-configuration", 1130 "tokio", 1131 "tower-service", 1132 + "tracing", 1133 + "windows-registry", 1134 + ] 1135 + 1136 + [[package]] 1137 + name = "iana-time-zone" 1138 + version = "0.1.64" 1139 + source = "registry+https://github.com/rust-lang/crates.io-index" 1140 + checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" 1141 + dependencies = [ 1142 + "android_system_properties", 1143 + "core-foundation-sys", 1144 + "iana-time-zone-haiku", 1145 + "js-sys", 1146 + "log", 1147 + "wasm-bindgen", 1148 + "windows-core", 1149 + ] 1150 + 1151 + [[package]] 1152 + name = "iana-time-zone-haiku" 1153 + version = "0.1.2" 1154 + source = "registry+https://github.com/rust-lang/crates.io-index" 1155 + checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" 1156 + dependencies = [ 1157 + "cc", 1158 + ] 1159 + 1160 + [[package]] 1161 + name = "icalendar" 1162 + version = "0.17.5" 1163 + source = "registry+https://github.com/rust-lang/crates.io-index" 1164 + checksum = "f25bc68d1c3113be52919708c870cabe55ba0646b9dade87913fe565aa956a3b" 1165 + dependencies = [ 1166 + "chrono", 1167 + "chrono-tz", 1168 + "iso8601", 1169 + "nom", 1170 + "nom-language", 1171 + "serde", 1172 + "time", 1173 + "uuid", 1174 ] 1175 1176 [[package]] ··· 1306 ] 1307 1308 [[package]] 1309 + name = "ipnet" 1310 + version = "2.11.0" 1311 + source = "registry+https://github.com/rust-lang/crates.io-index" 1312 + checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" 1313 + 1314 + [[package]] 1315 + name = "iri-string" 1316 + version = "0.7.8" 1317 + source = "registry+https://github.com/rust-lang/crates.io-index" 1318 + checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" 1319 + dependencies = [ 1320 + "memchr", 1321 + "serde", 1322 + ] 1323 + 1324 + [[package]] 1325 + name = "iso8601" 1326 + version = "0.6.3" 1327 + source = "registry+https://github.com/rust-lang/crates.io-index" 1328 + checksum = "e1082f0c48f143442a1ac6122f67e360ceee130b967af4d50996e5154a45df46" 1329 + dependencies = [ 1330 + "nom", 1331 + ] 1332 + 1333 + [[package]] 1334 name = "itertools" 1335 version = "0.14.0" 1336 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1653 checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" 1654 1655 [[package]] 1656 + name = "lru-slab" 1657 + version = "0.1.2" 1658 + source = "registry+https://github.com/rust-lang/crates.io-index" 1659 + checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" 1660 + 1661 + [[package]] 1662 name = "manyhow" 1663 version = "0.11.4" 1664 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1771 checksum = "60993920e071b0c9b66f14e2b32740a4e27ffc82854dcd72035887f336a09a28" 1772 1773 [[package]] 1774 + name = "nom" 1775 + version = "8.0.0" 1776 + source = "registry+https://github.com/rust-lang/crates.io-index" 1777 + checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" 1778 + dependencies = [ 1779 + "memchr", 1780 + ] 1781 + 1782 + [[package]] 1783 + name = "nom-language" 1784 + version = "0.1.0" 1785 + source = "registry+https://github.com/rust-lang/crates.io-index" 1786 + checksum = "2de2bc5b451bfedaef92c90b8939a8fff5770bdcc1fafd6239d086aab8fa6b29" 1787 + dependencies = [ 1788 + "nom", 1789 + ] 1790 + 1791 + [[package]] 1792 name = "num-bigint-dig" 1793 version = "0.8.4" 1794 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1804 "smallvec", 1805 "zeroize", 1806 ] 1807 + 1808 + [[package]] 1809 + name = "num-conv" 1810 + version = "0.1.0" 1811 + source = "registry+https://github.com/rust-lang/crates.io-index" 1812 + checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" 1813 1814 [[package]] 1815 name = "num-integer" ··· 1943 "libc", 1944 "redox_syscall", 1945 "smallvec", 1946 + "windows-link 0.2.1", 1947 ] 1948 1949 [[package]] ··· 1972 version = "2.3.2" 1973 source = "registry+https://github.com/rust-lang/crates.io-index" 1974 checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" 1975 + 1976 + [[package]] 1977 + name = "phf" 1978 + version = "0.12.1" 1979 + source = "registry+https://github.com/rust-lang/crates.io-index" 1980 + checksum = "913273894cec178f401a31ec4b656318d95473527be05c0752cc41cdc32be8b7" 1981 + dependencies = [ 1982 + "phf_shared", 1983 + ] 1984 + 1985 + [[package]] 1986 + name = "phf_shared" 1987 + version = "0.12.1" 1988 + source = "registry+https://github.com/rust-lang/crates.io-index" 1989 + checksum = "06005508882fb681fd97892ecff4b7fd0fee13ef1aa569f8695dae7ab9099981" 1990 + dependencies = [ 1991 + "siphasher", 1992 + ] 1993 1994 [[package]] 1995 name = "pin-project" ··· 2060 ] 2061 2062 [[package]] 2063 + name = "powerfmt" 2064 + version = "0.2.0" 2065 + source = "registry+https://github.com/rust-lang/crates.io-index" 2066 + checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" 2067 + 2068 + [[package]] 2069 name = "ppv-lite86" 2070 version = "0.2.21" 2071 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2140 ] 2141 2142 [[package]] 2143 + name = "quinn" 2144 + version = "0.11.9" 2145 + source = "registry+https://github.com/rust-lang/crates.io-index" 2146 + checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" 2147 + dependencies = [ 2148 + "bytes", 2149 + "cfg_aliases", 2150 + "pin-project-lite", 2151 + "quinn-proto", 2152 + "quinn-udp", 2153 + "rustc-hash", 2154 + "rustls", 2155 + "socket2", 2156 + "thiserror 2.0.17", 2157 + "tokio", 2158 + "tracing", 2159 + "web-time", 2160 + ] 2161 + 2162 + [[package]] 2163 + name = "quinn-proto" 2164 + version = "0.11.13" 2165 + source = "registry+https://github.com/rust-lang/crates.io-index" 2166 + checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" 2167 + dependencies = [ 2168 + "bytes", 2169 + "getrandom 0.3.4", 2170 + "lru-slab", 2171 + "rand 0.9.2", 2172 + "ring", 2173 + "rustc-hash", 2174 + "rustls", 2175 + "rustls-pki-types", 2176 + "slab", 2177 + "thiserror 2.0.17", 2178 + "tinyvec", 2179 + "tracing", 2180 + "web-time", 2181 + ] 2182 + 2183 + [[package]] 2184 + name = "quinn-udp" 2185 + version = "0.5.14" 2186 + source = "registry+https://github.com/rust-lang/crates.io-index" 2187 + checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" 2188 + dependencies = [ 2189 + "cfg_aliases", 2190 + "libc", 2191 + "once_cell", 2192 + "socket2", 2193 + "tracing", 2194 + "windows-sys 0.60.2", 2195 + ] 2196 + 2197 + [[package]] 2198 name = "quote" 2199 version = "1.0.41" 2200 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2382 checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" 2383 2384 [[package]] 2385 + name = "reqwest" 2386 + version = "0.12.24" 2387 + source = "registry+https://github.com/rust-lang/crates.io-index" 2388 + checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" 2389 + dependencies = [ 2390 + "base64", 2391 + "bytes", 2392 + "encoding_rs", 2393 + "futures-core", 2394 + "h2", 2395 + "http", 2396 + "http-body", 2397 + "http-body-util", 2398 + "hyper", 2399 + "hyper-rustls", 2400 + "hyper-tls", 2401 + "hyper-util", 2402 + "js-sys", 2403 + "log", 2404 + "mime", 2405 + "native-tls", 2406 + "percent-encoding", 2407 + "pin-project-lite", 2408 + "quinn", 2409 + "rustls", 2410 + "rustls-pki-types", 2411 + "serde", 2412 + "serde_json", 2413 + "serde_urlencoded", 2414 + "sync_wrapper", 2415 + "tokio", 2416 + "tokio-native-tls", 2417 + "tokio-rustls", 2418 + "tower", 2419 + "tower-http", 2420 + "tower-service", 2421 + "url", 2422 + "wasm-bindgen", 2423 + "wasm-bindgen-futures", 2424 + "web-sys", 2425 + "webpki-roots 1.0.3", 2426 + ] 2427 + 2428 + [[package]] 2429 + name = "ring" 2430 + version = "0.17.14" 2431 + source = "registry+https://github.com/rust-lang/crates.io-index" 2432 + checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" 2433 + dependencies = [ 2434 + "cc", 2435 + "cfg-if", 2436 + "getrandom 0.2.16", 2437 + "libc", 2438 + "untrusted", 2439 + "windows-sys 0.52.0", 2440 + ] 2441 + 2442 + [[package]] 2443 name = "rsa" 2444 version = "0.9.8" 2445 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2503 ] 2504 2505 [[package]] 2506 + name = "rustls" 2507 + version = "0.23.34" 2508 + source = "registry+https://github.com/rust-lang/crates.io-index" 2509 + checksum = "6a9586e9ee2b4f8fab52a0048ca7334d7024eef48e2cb9407e3497bb7cab7fa7" 2510 + dependencies = [ 2511 + "once_cell", 2512 + "ring", 2513 + "rustls-pki-types", 2514 + "rustls-webpki", 2515 + "subtle", 2516 + "zeroize", 2517 + ] 2518 + 2519 + [[package]] 2520 + name = "rustls-pki-types" 2521 + version = "1.12.0" 2522 + source = "registry+https://github.com/rust-lang/crates.io-index" 2523 + checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" 2524 + dependencies = [ 2525 + "web-time", 2526 + "zeroize", 2527 + ] 2528 + 2529 + [[package]] 2530 + name = "rustls-webpki" 2531 + version = "0.103.7" 2532 + source = "registry+https://github.com/rust-lang/crates.io-index" 2533 + checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf" 2534 + dependencies = [ 2535 + "ring", 2536 + "rustls-pki-types", 2537 + "untrusted", 2538 + ] 2539 + 2540 + [[package]] 2541 name = "rustversion" 2542 version = "1.0.22" 2543 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2799 "digest", 2800 "rand_core 0.6.4", 2801 ] 2802 + 2803 + [[package]] 2804 + name = "siphasher" 2805 + version = "1.0.1" 2806 + source = "registry+https://github.com/rust-lang/crates.io-index" 2807 + checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" 2808 2809 [[package]] 2810 name = "slab" ··· 2896 "native-tls", 2897 "once_cell", 2898 "percent-encoding", 2899 + "rustls", 2900 "serde", 2901 "serde_json", 2902 "sha2", ··· 2907 "tracing", 2908 "url", 2909 "uuid", 2910 + "webpki-roots 0.26.11", 2911 ] 2912 2913 [[package]] ··· 3105 version = "1.0.2" 3106 source = "registry+https://github.com/rust-lang/crates.io-index" 3107 checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" 3108 + dependencies = [ 3109 + "futures-core", 3110 + ] 3111 3112 [[package]] 3113 name = "synstructure" ··· 3121 ] 3122 3123 [[package]] 3124 + name = "system-configuration" 3125 + version = "0.6.1" 3126 + source = "registry+https://github.com/rust-lang/crates.io-index" 3127 + checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" 3128 + dependencies = [ 3129 + "bitflags", 3130 + "core-foundation", 3131 + "system-configuration-sys", 3132 + ] 3133 + 3134 + [[package]] 3135 + name = "system-configuration-sys" 3136 + version = "0.6.0" 3137 + source = "registry+https://github.com/rust-lang/crates.io-index" 3138 + checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" 3139 + dependencies = [ 3140 + "core-foundation-sys", 3141 + "libc", 3142 + ] 3143 + 3144 + [[package]] 3145 name = "tachys" 3146 version = "0.2.10" 3147 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3238 ] 3239 3240 [[package]] 3241 + name = "time" 3242 + version = "0.3.44" 3243 + source = "registry+https://github.com/rust-lang/crates.io-index" 3244 + checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" 3245 + dependencies = [ 3246 + "deranged", 3247 + "num-conv", 3248 + "powerfmt", 3249 + "serde", 3250 + "time-core", 3251 + ] 3252 + 3253 + [[package]] 3254 + name = "time-core" 3255 + version = "0.1.6" 3256 + source = "registry+https://github.com/rust-lang/crates.io-index" 3257 + checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" 3258 + 3259 + [[package]] 3260 name = "tinystr" 3261 version = "0.8.1" 3262 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3308 ] 3309 3310 [[package]] 3311 + name = "tokio-native-tls" 3312 + version = "0.3.1" 3313 + source = "registry+https://github.com/rust-lang/crates.io-index" 3314 + checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" 3315 + dependencies = [ 3316 + "native-tls", 3317 + "tokio", 3318 + ] 3319 + 3320 + [[package]] 3321 + name = "tokio-rustls" 3322 + version = "0.26.4" 3323 + source = "registry+https://github.com/rust-lang/crates.io-index" 3324 + checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" 3325 + dependencies = [ 3326 + "rustls", 3327 + "tokio", 3328 + ] 3329 + 3330 + [[package]] 3331 name = "tokio-stream" 3332 version = "0.1.17" 3333 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3425 "http-body-util", 3426 "http-range-header", 3427 "httpdate", 3428 + "iri-string", 3429 "mime", 3430 "mime_guess", 3431 "percent-encoding", 3432 "pin-project-lite", 3433 "tokio", 3434 "tokio-util", 3435 + "tower", 3436 "tower-layer", 3437 "tower-service", 3438 "tracing", ··· 3481 dependencies = [ 3482 "once_cell", 3483 ] 3484 + 3485 + [[package]] 3486 + name = "try-lock" 3487 + version = "0.2.5" 3488 + source = "registry+https://github.com/rust-lang/crates.io-index" 3489 + checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 3490 3491 [[package]] 3492 name = "tungstenite" ··· 3577 checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" 3578 3579 [[package]] 3580 + name = "untrusted" 3581 + version = "0.9.0" 3582 + source = "registry+https://github.com/rust-lang/crates.io-index" 3583 + checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 3584 + 3585 + [[package]] 3586 name = "url" 3587 version = "2.5.7" 3588 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3620 dependencies = [ 3621 "getrandom 0.3.4", 3622 "js-sys", 3623 + "serde", 3624 "wasm-bindgen", 3625 ] 3626 ··· 3644 dependencies = [ 3645 "same-file", 3646 "winapi-util", 3647 + ] 3648 + 3649 + [[package]] 3650 + name = "want" 3651 + version = "0.3.1" 3652 + source = "registry+https://github.com/rust-lang/crates.io-index" 3653 + checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 3654 + dependencies = [ 3655 + "try-lock", 3656 ] 3657 3658 [[package]] ··· 3796 ] 3797 3798 [[package]] 3799 + name = "web-time" 3800 + version = "1.1.0" 3801 + source = "registry+https://github.com/rust-lang/crates.io-index" 3802 + checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" 3803 + dependencies = [ 3804 + "js-sys", 3805 + "wasm-bindgen", 3806 + ] 3807 + 3808 + [[package]] 3809 + name = "webpki-roots" 3810 + version = "0.26.11" 3811 + source = "registry+https://github.com/rust-lang/crates.io-index" 3812 + checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" 3813 + dependencies = [ 3814 + "webpki-roots 1.0.3", 3815 + ] 3816 + 3817 + [[package]] 3818 + name = "webpki-roots" 3819 + version = "1.0.3" 3820 + source = "registry+https://github.com/rust-lang/crates.io-index" 3821 + checksum = "32b130c0d2d49f8b6889abc456e795e82525204f27c42cf767cf0d7734e089b8" 3822 + dependencies = [ 3823 + "rustls-pki-types", 3824 + ] 3825 + 3826 + [[package]] 3827 name = "whoami" 3828 version = "1.6.1" 3829 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3841 dependencies = [ 3842 "windows-sys 0.61.2", 3843 ] 3844 + 3845 + [[package]] 3846 + name = "windows-core" 3847 + version = "0.62.2" 3848 + source = "registry+https://github.com/rust-lang/crates.io-index" 3849 + checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" 3850 + dependencies = [ 3851 + "windows-implement", 3852 + "windows-interface", 3853 + "windows-link 0.2.1", 3854 + "windows-result 0.4.1", 3855 + "windows-strings 0.5.1", 3856 + ] 3857 + 3858 + [[package]] 3859 + name = "windows-implement" 3860 + version = "0.60.2" 3861 + source = "registry+https://github.com/rust-lang/crates.io-index" 3862 + checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" 3863 + dependencies = [ 3864 + "proc-macro2", 3865 + "quote", 3866 + "syn", 3867 + ] 3868 + 3869 + [[package]] 3870 + name = "windows-interface" 3871 + version = "0.59.3" 3872 + source = "registry+https://github.com/rust-lang/crates.io-index" 3873 + checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" 3874 + dependencies = [ 3875 + "proc-macro2", 3876 + "quote", 3877 + "syn", 3878 + ] 3879 + 3880 + [[package]] 3881 + name = "windows-link" 3882 + version = "0.1.3" 3883 + source = "registry+https://github.com/rust-lang/crates.io-index" 3884 + checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" 3885 3886 [[package]] 3887 name = "windows-link" ··· 3890 checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" 3891 3892 [[package]] 3893 + name = "windows-registry" 3894 + version = "0.5.3" 3895 + source = "registry+https://github.com/rust-lang/crates.io-index" 3896 + checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" 3897 + dependencies = [ 3898 + "windows-link 0.1.3", 3899 + "windows-result 0.3.4", 3900 + "windows-strings 0.4.2", 3901 + ] 3902 + 3903 + [[package]] 3904 + name = "windows-result" 3905 + version = "0.3.4" 3906 + source = "registry+https://github.com/rust-lang/crates.io-index" 3907 + checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" 3908 + dependencies = [ 3909 + "windows-link 0.1.3", 3910 + ] 3911 + 3912 + [[package]] 3913 + name = "windows-result" 3914 + version = "0.4.1" 3915 + source = "registry+https://github.com/rust-lang/crates.io-index" 3916 + checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" 3917 + dependencies = [ 3918 + "windows-link 0.2.1", 3919 + ] 3920 + 3921 + [[package]] 3922 + name = "windows-strings" 3923 + version = "0.4.2" 3924 + source = "registry+https://github.com/rust-lang/crates.io-index" 3925 + checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" 3926 + dependencies = [ 3927 + "windows-link 0.1.3", 3928 + ] 3929 + 3930 + [[package]] 3931 + name = "windows-strings" 3932 + version = "0.5.1" 3933 + source = "registry+https://github.com/rust-lang/crates.io-index" 3934 + checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" 3935 + dependencies = [ 3936 + "windows-link 0.2.1", 3937 + ] 3938 + 3939 + [[package]] 3940 name = "windows-sys" 3941 version = "0.48.0" 3942 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3947 3948 [[package]] 3949 name = "windows-sys" 3950 + version = "0.52.0" 3951 + source = "registry+https://github.com/rust-lang/crates.io-index" 3952 + checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 3953 + dependencies = [ 3954 + "windows-targets 0.52.6", 3955 + ] 3956 + 3957 + [[package]] 3958 + name = "windows-sys" 3959 version = "0.60.2" 3960 source = "registry+https://github.com/rust-lang/crates.io-index" 3961 checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" ··· 3969 source = "registry+https://github.com/rust-lang/crates.io-index" 3970 checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" 3971 dependencies = [ 3972 + "windows-link 0.2.1", 3973 ] 3974 3975 [[package]] ··· 3989 3990 [[package]] 3991 name = "windows-targets" 3992 + version = "0.52.6" 3993 + source = "registry+https://github.com/rust-lang/crates.io-index" 3994 + checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 3995 + dependencies = [ 3996 + "windows_aarch64_gnullvm 0.52.6", 3997 + "windows_aarch64_msvc 0.52.6", 3998 + "windows_i686_gnu 0.52.6", 3999 + "windows_i686_gnullvm 0.52.6", 4000 + "windows_i686_msvc 0.52.6", 4001 + "windows_x86_64_gnu 0.52.6", 4002 + "windows_x86_64_gnullvm 0.52.6", 4003 + "windows_x86_64_msvc 0.52.6", 4004 + ] 4005 + 4006 + [[package]] 4007 + name = "windows-targets" 4008 version = "0.53.5" 4009 source = "registry+https://github.com/rust-lang/crates.io-index" 4010 checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" 4011 dependencies = [ 4012 + "windows-link 0.2.1", 4013 "windows_aarch64_gnullvm 0.53.1", 4014 "windows_aarch64_msvc 0.53.1", 4015 "windows_i686_gnu 0.53.1", 4016 + "windows_i686_gnullvm 0.53.1", 4017 "windows_i686_msvc 0.53.1", 4018 "windows_x86_64_gnu 0.53.1", 4019 "windows_x86_64_gnullvm 0.53.1", ··· 4025 version = "0.48.5" 4026 source = "registry+https://github.com/rust-lang/crates.io-index" 4027 checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 4028 + 4029 + [[package]] 4030 + name = "windows_aarch64_gnullvm" 4031 + version = "0.52.6" 4032 + source = "registry+https://github.com/rust-lang/crates.io-index" 4033 + checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 4034 4035 [[package]] 4036 name = "windows_aarch64_gnullvm" ··· 4046 4047 [[package]] 4048 name = "windows_aarch64_msvc" 4049 + version = "0.52.6" 4050 + source = "registry+https://github.com/rust-lang/crates.io-index" 4051 + checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 4052 + 4053 + [[package]] 4054 + name = "windows_aarch64_msvc" 4055 version = "0.53.1" 4056 source = "registry+https://github.com/rust-lang/crates.io-index" 4057 checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" ··· 4064 4065 [[package]] 4066 name = "windows_i686_gnu" 4067 + version = "0.52.6" 4068 + source = "registry+https://github.com/rust-lang/crates.io-index" 4069 + checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 4070 + 4071 + [[package]] 4072 + name = "windows_i686_gnu" 4073 version = "0.53.1" 4074 source = "registry+https://github.com/rust-lang/crates.io-index" 4075 checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" 4076 + 4077 + [[package]] 4078 + name = "windows_i686_gnullvm" 4079 + version = "0.52.6" 4080 + source = "registry+https://github.com/rust-lang/crates.io-index" 4081 + checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 4082 4083 [[package]] 4084 name = "windows_i686_gnullvm" ··· 4094 4095 [[package]] 4096 name = "windows_i686_msvc" 4097 + version = "0.52.6" 4098 + source = "registry+https://github.com/rust-lang/crates.io-index" 4099 + checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 4100 + 4101 + [[package]] 4102 + name = "windows_i686_msvc" 4103 version = "0.53.1" 4104 source = "registry+https://github.com/rust-lang/crates.io-index" 4105 checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" ··· 4112 4113 [[package]] 4114 name = "windows_x86_64_gnu" 4115 + version = "0.52.6" 4116 + source = "registry+https://github.com/rust-lang/crates.io-index" 4117 + checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 4118 + 4119 + [[package]] 4120 + name = "windows_x86_64_gnu" 4121 version = "0.53.1" 4122 source = "registry+https://github.com/rust-lang/crates.io-index" 4123 checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" ··· 4130 4131 [[package]] 4132 name = "windows_x86_64_gnullvm" 4133 + version = "0.52.6" 4134 + source = "registry+https://github.com/rust-lang/crates.io-index" 4135 + checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 4136 + 4137 + [[package]] 4138 + name = "windows_x86_64_gnullvm" 4139 version = "0.53.1" 4140 source = "registry+https://github.com/rust-lang/crates.io-index" 4141 checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" ··· 4145 version = "0.48.5" 4146 source = "registry+https://github.com/rust-lang/crates.io-index" 4147 checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 4148 + 4149 + [[package]] 4150 + name = "windows_x86_64_msvc" 4151 + version = "0.52.6" 4152 + source = "registry+https://github.com/rust-lang/crates.io-index" 4153 + checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 4154 4155 [[package]] 4156 name = "windows_x86_64_msvc"
+10 -2
Cargo.toml
··· 15 leptos_meta = { version = "0.8.0" } 16 tokio = { version = "1", features = ["rt-multi-thread"], optional = true } 17 wasm-bindgen = { version = "=0.2.100", optional = true } 18 - sqlx = { version = "0.8.6", features = ["runtime-tokio", "tls-native-tls", "postgres", "uuid", "macros"] } 19 20 [features] 21 hydrate = [ ··· 25 ] 26 ssr = [ 27 "dep:axum", 28 - "dep:tokio", 29 "dep:leptos_axum", 30 "leptos/ssr", 31 "leptos_meta/ssr", 32 "leptos_router/ssr",
··· 15 leptos_meta = { version = "0.8.0" } 16 tokio = { version = "1", features = ["rt-multi-thread"], optional = true } 17 wasm-bindgen = { version = "=0.2.100", optional = true } 18 + sqlx = { version = "0.8.6", features = ["runtime-tokio", "tls-native-tls", "postgres", "uuid", "macros", "tls-rustls-ring-webpki"], optional = true } 19 + uuid = { version = "1.18.1", features = ["js", "serde", "v4"], optional = true } 20 + anyhow = "1.0.100" 21 + reqwest = { version = "0.12.24", features = ["rustls-tls-webpki-roots", "charset", "http2"], optional = true } 22 + icalendar = { version = "0.17.5", features = ["parser", "serde", "chrono-tz", "time",], optional = true } 23 24 [features] 25 hydrate = [ ··· 29 ] 30 ssr = [ 31 "dep:axum", 32 + "dep:icalendar", 33 "dep:leptos_axum", 34 + "dep:reqwest", 35 + "dep:sqlx", 36 + "dep:tokio", 37 + "dep:uuid", 38 "leptos/ssr", 39 "leptos_meta/ssr", 40 "leptos_router/ssr",
+26
migrations/20251026145212_add-calendars.sql
···
··· 1 + CREATE TABLE "subscriptions" ( 2 + "id" uuid PRIMARY KEY, 3 + "url" varchar NOT NULL 4 + ); 5 + 6 + CREATE TABLE "calendars" ( 7 + "id" uuid PRIMARY KEY, 8 + "user" uuid NOT NULL 9 + ); 10 + 11 + CREATE TABLE "users" ( 12 + "id" uuid PRIMARY KEY 13 + ); 14 + 15 + CREATE TABLE "calendars_subscriptions" ( 16 + "calendars_id" uuid, 17 + "subscriptions_id" uuid, 18 + PRIMARY KEY ("calendars_id", "subscriptions_id") 19 + ); 20 + 21 + ALTER TABLE "calendars_subscriptions" ADD FOREIGN KEY ("calendars_id") REFERENCES "calendars" ("id"); 22 + 23 + ALTER TABLE "calendars_subscriptions" ADD FOREIGN KEY ("subscriptions_id") REFERENCES "subscriptions" ("id"); 24 + 25 + 26 + ALTER TABLE "calendars" ADD CONSTRAINT "user_calendars" FOREIGN KEY ("user") REFERENCES "users" ("id");
+56 -2
src/calendar.rs
··· 1 use axum::extract::Path; 2 3 - pub(crate) async fn route(Path(_path): Path<String>) -> String { 4 - "hello world!".to_string() 5 }
··· 1 + use std::ops::DerefMut; 2 + 3 use axum::extract::Path; 4 + use leptos::prelude::ServerFnError; 5 + use leptos::server; 6 + use tokio::task::JoinSet; 7 + use uuid::Uuid; 8 + 9 + use crate::STATE; 10 11 + pub(crate) async fn route( 12 + Path(id): Path<Uuid> 13 + ) -> String { 14 + events_by_calendar(id).await.unwrap() 15 + } 16 + 17 + #[server] 18 + async fn events_by_calendar(id: Uuid) -> anyhow::Result<String, ServerFnError> { 19 + let state = STATE.get().unwrap(); 20 + 21 + println!("{:?}", id); 22 + 23 + let subscription_urls = sqlx::query!( 24 + "SELECT url FROM subscriptions 25 + JOIN calendars_subscriptions on subscriptions.id = calendars_subscriptions.subscriptions_id 26 + JOIN calendars on calendars.id = calendars_subscriptions.calendars_id 27 + WHERE calendars.id = $1", 28 + id 29 + ).fetch_all(state.sqlx_connection.lock().await.deref_mut()).await?; 30 + 31 + println!("{:#?}", subscription_urls); 32 + 33 + let mut requests = JoinSet::new(); 34 + 35 + for url in subscription_urls { 36 + requests.spawn((async || { 37 + let result = state.reqwest_client.get(url.url).send().await; 38 + 39 + let Ok(response) = result else { 40 + return None 41 + }; 42 + 43 + response.text().await.ok() 44 + })()); 45 + } 46 + 47 + let results = requests.join_all().await; 48 + let icals = results.iter().filter_map(|ical| ical.to_owned()); 49 + 50 + let calendars: Vec<icalendar::Calendar> = icals.map(|ical| ical.parse::<icalendar::Calendar>()).filter_map(|calendar| calendar.ok()).collect(); 51 + 52 + let mut merged = icalendar::Calendar::new(); 53 + 54 + for calendar in calendars { 55 + merged.extend(calendar.components); 56 + } 57 + 58 + Ok(merged.to_string()) 59 }
+28
src/main.rs
··· 1 mod calendar; 2 3 #[cfg(feature = "ssr")] 4 #[tokio::main] 5 async fn main() { 6 use axum::{routing::get, Router}; 7 use leptos::logging::log; 8 use leptos::prelude::*; 9 use leptos_axum::{generate_route_list, LeptosRoutes}; 10 use calpoll::app::*; 11 12 let conf = get_configuration(None).unwrap(); 13 let addr = conf.leptos_options.site_addr;
··· 1 + use std::sync::OnceLock; 2 + use sqlx::PgConnection; 3 + use tokio::sync::Mutex; 4 + 5 mod calendar; 6 + 7 + #[cfg(feature = "ssr")] 8 + #[derive(Debug)] 9 + pub struct State { 10 + sqlx_connection: Mutex<PgConnection>, 11 + reqwest_client: reqwest::Client, 12 + } 13 + 14 + #[cfg(feature = "ssr")] 15 + static STATE: OnceLock<State> = OnceLock::new(); 16 17 #[cfg(feature = "ssr")] 18 #[tokio::main] 19 async fn main() { 20 + use std::env; 21 + 22 use axum::{routing::get, Router}; 23 use leptos::logging::log; 24 use leptos::prelude::*; 25 use leptos_axum::{generate_route_list, LeptosRoutes}; 26 use calpoll::app::*; 27 + use sqlx::Connection; 28 + 29 + let connection = 30 + PgConnection::connect( 31 + env::var("DATABASE_URL") 32 + .expect("Please ensure you set your database URL in the $DATABASE_URL environment variable") 33 + .as_str()).await.unwrap(); 34 + 35 + STATE.set(State { 36 + sqlx_connection: Mutex::new(connection), 37 + reqwest_client: reqwest::Client::new(), 38 + }).unwrap(); 39 40 let conf = get_configuration(None).unwrap(); 41 let addr = conf.leptos_options.site_addr;
+9
test-data/merge-holidays-moon-phases.sql
···
··· 1 + INSERT INTO users ("id") VALUES ('11cd80d6-cf3d-4d93-9d47-4a383eaf1a10'); 2 + 3 + INSERT INTO calendars ("id", "user") VALUES ('32da8949-b21c-469d-a2bc-f5763af186c6', '11cd80d6-cf3d-4d93-9d47-4a383eaf1a10'); 4 + 5 + INSERT INTO subscriptions ("id", "url") VALUES ('797de795-0ae5-443c-91d1-1d68f9d44889', 'https://calendar.google.com/calendar/ical/en.uk%23holiday%40group.v.calendar.google.com/public/basic.ics'); 6 + INSERT INTO subscriptions ("id", "url") VALUES ('53d15eed-9db4-40ac-a5b1-b6df114847b2', 'https://calendar.google.com/calendar/ical/ht3jlfaac5lfd6263ulfh4tql8%40group.calendar.google.com/public/basic.ics'); 7 + 8 + INSERT INTO calendars_subscriptions ("calendars_id", "subscriptions_id") VALUES ('32da8949-b21c-469d-a2bc-f5763af186c6', '797de795-0ae5-443c-91d1-1d68f9d44889'); 9 + INSERT INTO calendars_subscriptions ("calendars_id", "subscriptions_id") VALUES ('32da8949-b21c-469d-a2bc-f5763af186c6', '53d15eed-9db4-40ac-a5b1-b6df114847b2');