From 4729c1afabadf6065eb51cfa919b3fd48f0a20f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20H=C3=B6lting?= <87192362+moritz-hoelting@users.noreply.github.com> Date: Mon, 15 Dec 2025 21:14:15 +0100 Subject: [PATCH] web api automatically refreshes outdated --- ...ee4173631a63d3a89e6440b3334c546213863.json | 29 + ...2f42b80a311d4a00ee22b97dd1e7b5c91ad39.json | 15 + ...8946bed129746b70f92f66704f02093b2e27c.json | 23 - ...0ffead845478d359af83b70d98ff8d1945f2.json} | 6 +- ...b20ff9f1ff928912d871a708a088f2d011ba7.json | 15 + ...c4367d1a1ea563d1b7845ab099ef6ec1e47a.json} | 21 +- Cargo.lock | 1105 +++++++++-------- Cargo.toml | 15 +- .../20251215165721_allow_refreshes.down.sql | 33 + .../20251215165721_allow_refreshes.up.sql | 51 + scraper/Cargo.toml | 5 +- scraper/src/canteen.rs | 55 +- scraper/src/dish.rs | 21 +- scraper/src/lib.rs | 5 +- scraper/src/main.rs | 22 +- scraper/src/menu.rs | 3 +- scraper/src/refresh.rs | 63 + scraper/src/util.rs | 129 +- shared/Cargo.toml | 13 + {web-api => shared}/src/canteen.rs | 0 shared/src/lib.rs | 24 + web-api/Cargo.toml | 16 +- web-api/src/dish.rs | 3 +- web-api/src/endpoints/menu.rs | 7 +- web-api/src/endpoints/mod.rs | 3 +- web-api/src/lib.rs | 27 +- web-api/src/menu.rs | 56 +- 27 files changed, 1014 insertions(+), 751 deletions(-) create mode 100644 .sqlx/query-2306ceee73b304c3ca88da52837ee4173631a63d3a89e6440b3334c546213863.json create mode 100644 .sqlx/query-474de9870fb2cbfb2cdc37004c82f42b80a311d4a00ee22b97dd1e7b5c91ad39.json delete mode 100644 .sqlx/query-4fdb615a3e155d8394c70f25d2d8946bed129746b70f92f66704f02093b2e27c.json rename .sqlx/{query-b94a6b49fb5e53e361da7a890dd5f62d467293454b01175939e32339ee90fd23.json => query-65858112433addbff921108a5b110ffead845478d359af83b70d98ff8d1945f2.json} (61%) create mode 100644 .sqlx/query-f804f9c634a34945d7aa0cd3162b20ff9f1ff928912d871a708a088f2d011ba7.json rename .sqlx/{query-b5a990f34095b255672e81562dc905e1957d1d33d823dc82ec92b552f5092028.json => query-ffbe520bbd10d79f189bc4cb202fc4367d1a1ea563d1b7845ab099ef6ec1e47a.json} (61%) create mode 100644 migrations/20251215165721_allow_refreshes.down.sql create mode 100644 migrations/20251215165721_allow_refreshes.up.sql create mode 100644 scraper/src/refresh.rs create mode 100644 shared/Cargo.toml rename {web-api => shared}/src/canteen.rs (100%) create mode 100644 shared/src/lib.rs diff --git a/.sqlx/query-2306ceee73b304c3ca88da52837ee4173631a63d3a89e6440b3334c546213863.json b/.sqlx/query-2306ceee73b304c3ca88da52837ee4173631a63d3a89e6440b3334c546213863.json new file mode 100644 index 0000000..e5be1fb --- /dev/null +++ b/.sqlx/query-2306ceee73b304c3ca88da52837ee4173631a63d3a89e6440b3334c546213863.json @@ -0,0 +1,29 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT canteen, max(scraped_at) AS \"scraped_at!\" FROM canteens_scraped WHERE canteen = ANY($1) AND scraped_for = $2 GROUP BY canteen", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "canteen", + "type_info": "Text" + }, + { + "ordinal": 1, + "name": "scraped_at!", + "type_info": "Timestamptz" + } + ], + "parameters": { + "Left": [ + "TextArray", + "Date" + ] + }, + "nullable": [ + false, + null + ] + }, + "hash": "2306ceee73b304c3ca88da52837ee4173631a63d3a89e6440b3334c546213863" +} diff --git a/.sqlx/query-474de9870fb2cbfb2cdc37004c82f42b80a311d4a00ee22b97dd1e7b5c91ad39.json b/.sqlx/query-474de9870fb2cbfb2cdc37004c82f42b80a311d4a00ee22b97dd1e7b5c91ad39.json new file mode 100644 index 0000000..56ed48a --- /dev/null +++ b/.sqlx/query-474de9870fb2cbfb2cdc37004c82f42b80a311d4a00ee22b97dd1e7b5c91ad39.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO canteens_scraped (scraped_for, canteen) VALUES ($1, $2)", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Date", + "Text" + ] + }, + "nullable": [] + }, + "hash": "474de9870fb2cbfb2cdc37004c82f42b80a311d4a00ee22b97dd1e7b5c91ad39" +} diff --git a/.sqlx/query-4fdb615a3e155d8394c70f25d2d8946bed129746b70f92f66704f02093b2e27c.json b/.sqlx/query-4fdb615a3e155d8394c70f25d2d8946bed129746b70f92f66704f02093b2e27c.json deleted file mode 100644 index 8928e6e..0000000 --- a/.sqlx/query-4fdb615a3e155d8394c70f25d2d8946bed129746b70f92f66704f02093b2e27c.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "INSERT INTO meals (date,canteen,name,dish_type,image_src,price_students,price_employees,price_guests,vegan,vegetarian)\n VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10)\n ON CONFLICT (date,canteen,name) DO NOTHING", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Date", - "Text", - "Text", - "Text", - "Text", - "Numeric", - "Numeric", - "Numeric", - "Bool", - "Bool" - ] - }, - "nullable": [] - }, - "hash": "4fdb615a3e155d8394c70f25d2d8946bed129746b70f92f66704f02093b2e27c" -} diff --git a/.sqlx/query-b94a6b49fb5e53e361da7a890dd5f62d467293454b01175939e32339ee90fd23.json b/.sqlx/query-65858112433addbff921108a5b110ffead845478d359af83b70d98ff8d1945f2.json similarity index 61% rename from .sqlx/query-b94a6b49fb5e53e361da7a890dd5f62d467293454b01175939e32339ee90fd23.json rename to .sqlx/query-65858112433addbff921108a5b110ffead845478d359af83b70d98ff8d1945f2.json index 0861ddb..bcb84ab 100644 --- a/.sqlx/query-b94a6b49fb5e53e361da7a890dd5f62d467293454b01175939e32339ee90fd23.json +++ b/.sqlx/query-65858112433addbff921108a5b110ffead845478d359af83b70d98ff8d1945f2.json @@ -1,11 +1,11 @@ { "db_name": "PostgreSQL", - "query": "SELECT DISTINCT date, canteen FROM MEALS WHERE date >= $1 AND date <= $2", + "query": "SELECT DISTINCT scraped_for, canteen FROM canteens_scraped WHERE scraped_for >= $1 AND scraped_for <= $2", "describe": { "columns": [ { "ordinal": 0, - "name": "date", + "name": "scraped_for", "type_info": "Date" }, { @@ -25,5 +25,5 @@ false ] }, - "hash": "b94a6b49fb5e53e361da7a890dd5f62d467293454b01175939e32339ee90fd23" + "hash": "65858112433addbff921108a5b110ffead845478d359af83b70d98ff8d1945f2" } diff --git a/.sqlx/query-f804f9c634a34945d7aa0cd3162b20ff9f1ff928912d871a708a088f2d011ba7.json b/.sqlx/query-f804f9c634a34945d7aa0cd3162b20ff9f1ff928912d871a708a088f2d011ba7.json new file mode 100644 index 0000000..5119b58 --- /dev/null +++ b/.sqlx/query-f804f9c634a34945d7aa0cd3162b20ff9f1ff928912d871a708a088f2d011ba7.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE meals SET is_latest = FALSE WHERE date = $1 AND canteen = $2 AND is_latest = TRUE", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Date", + "Text" + ] + }, + "nullable": [] + }, + "hash": "f804f9c634a34945d7aa0cd3162b20ff9f1ff928912d871a708a088f2d011ba7" +} diff --git a/.sqlx/query-b5a990f34095b255672e81562dc905e1957d1d33d823dc82ec92b552f5092028.json b/.sqlx/query-ffbe520bbd10d79f189bc4cb202fc4367d1a1ea563d1b7845ab099ef6ec1e47a.json similarity index 61% rename from .sqlx/query-b5a990f34095b255672e81562dc905e1957d1d33d823dc82ec92b552f5092028.json rename to .sqlx/query-ffbe520bbd10d79f189bc4cb202fc4367d1a1ea563d1b7845ab099ef6ec1e47a.json index 1ec9d01..38a5df6 100644 --- a/.sqlx/query-b5a990f34095b255672e81562dc905e1957d1d33d823dc82ec92b552f5092028.json +++ b/.sqlx/query-ffbe520bbd10d79f189bc4cb202fc4367d1a1ea563d1b7845ab099ef6ec1e47a.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT name, array_agg(DISTINCT canteen ORDER BY canteen) AS canteens, dish_type, image_src, price_students, price_employees, price_guests, vegan, vegetarian \n FROM meals WHERE date = $1 AND canteen = ANY($2) \n GROUP BY name, dish_type, image_src, price_students, price_employees, price_guests, vegan, vegetarian\n ORDER BY name", + "query": "SELECT name, array_agg(DISTINCT canteen ORDER BY canteen) AS \"canteens!\", dish_type AS \"dish_type: DishType\", image_src, price_students, price_employees, price_guests, vegan, vegetarian \n FROM meals WHERE date = $1 AND canteen = ANY($2) AND is_latest = TRUE\n GROUP BY name, dish_type, image_src, price_students, price_employees, price_guests, vegan, vegetarian\n ORDER BY name", "describe": { "columns": [ { @@ -10,13 +10,24 @@ }, { "ordinal": 1, - "name": "canteens", + "name": "canteens!", "type_info": "TextArray" }, { "ordinal": 2, - "name": "dish_type", - "type_info": "Text" + "name": "dish_type: DishType", + "type_info": { + "Custom": { + "name": "dish_type_enum", + "kind": { + "Enum": [ + "main", + "side", + "dessert" + ] + } + } + } }, { "ordinal": 3, @@ -67,5 +78,5 @@ false ] }, - "hash": "b5a990f34095b255672e81562dc905e1957d1d33d823dc82ec92b552f5092028" + "hash": "ffbe520bbd10d79f189bc4cb202fc4367d1a1ea563d1b7845ab099ef6ec1e47a" } diff --git a/Cargo.lock b/Cargo.lock index 4ac8368..105097e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,7 +27,7 @@ checksum = "daa239b93927be1ff123eebada5a3ff23e89f0124ccb8609234e5103d5a5ae6d" dependencies = [ "actix-utils", "actix-web", - "derive_more 2.0.1", + "derive_more", "futures-util", "log", "once_cell", @@ -36,9 +36,9 @@ dependencies = [ [[package]] name = "actix-governor" -version = "0.8.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a0cb8586d3fa368d00ef643e8ef77f5d3d5dfe5c7b333415a556bc12eb1c41a" +checksum = "6a7ffa43d3e1e92518355ffbc82c146b5f0fe24fba87f19f405270da7a7b3c1e" dependencies = [ "actix-http", "actix-web", @@ -49,9 +49,9 @@ dependencies = [ [[package]] name = "actix-http" -version = "3.11.0" +version = "3.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44dfe5c9e0004c623edc65391dfd51daa201e7e30ebd9c9bedf873048ec32bc2" +checksum = "7926860314cbe2fb5d1f13731e387ab43bd32bca224e82e6e2db85de0a3dba49" dependencies = [ "actix-codec", "actix-rt", @@ -62,12 +62,12 @@ dependencies = [ "brotli", "bytes", "bytestring", - "derive_more 2.0.1", + "derive_more", "encoding_rs", "flate2", - "foldhash", + "foldhash 0.1.5", "futures-core", - "h2 0.3.26", + "h2 0.3.27", "http 0.2.12", "httparse", "httpdate", @@ -77,7 +77,7 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rand 0.9.1", + "rand 0.9.2", "sha1", "smallvec", "tokio", @@ -113,9 +113,9 @@ dependencies = [ [[package]] name = "actix-rt" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eda4e2a6e042aa4e55ac438a2ae052d3b5da0ecf83d7411e1a368946925208" +checksum = "92589714878ca59a7626ea19734f0e07a6a875197eec751bb5d3f99e64998c63" dependencies = [ "futures-core", "tokio", @@ -133,7 +133,7 @@ dependencies = [ "futures-core", "futures-util", "mio", - "socket2", + "socket2 0.5.10", "tokio", "tracing", ] @@ -160,9 +160,9 @@ dependencies = [ [[package]] name = "actix-web" -version = "4.11.0" +version = "4.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a597b77b5c6d6a1e1097fddde329a83665e25c5437c696a3a9a4aa514a614dea" +checksum = "1654a77ba142e37f049637a3e5685f864514af11fcbc51cb51eb6596afe5b8d6" dependencies = [ "actix-codec", "actix-http", @@ -177,9 +177,9 @@ dependencies = [ "bytestring", "cfg-if", "cookie", - "derive_more 2.0.1", + "derive_more", "encoding_rs", - "foldhash", + "foldhash 0.1.5", "futures-core", "futures-util", "impl-more", @@ -195,7 +195,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "smallvec", - "socket2", + "socket2 0.6.1", "time", "tracing", "url", @@ -213,15 +213,6 @@ dependencies = [ "syn", ] -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - [[package]] name = "adler2" version = "2.0.1" @@ -230,9 +221,9 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -258,12 +249,6 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - [[package]] name = "android_system_properties" version = "0.1.5" @@ -275,9 +260,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.98" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "atoi" @@ -300,21 +285,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" -[[package]] -name = "backtrace" -version = "0.3.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - [[package]] name = "base64" version = "0.22.1" @@ -323,15 +293,15 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" +checksum = "0e050f626429857a27ddccb31e0aca21356bfa709c04041aefddac081a8f068a" [[package]] name = "bigdecimal" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a22f228ab7a1b23027ccc6c350b72868017af7ea8356fbdf19f8d991c690013" +checksum = "560f42649de9fa436b73517378a147ec21f6c997a546581df4b4b31677828934" dependencies = [ "autocfg", "libm", @@ -343,11 +313,11 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.9.1" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -361,9 +331,9 @@ dependencies = [ [[package]] name = "brotli" -version = "8.0.1" +version = "8.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9991eea70ea4f293524138648e41ee89b0b2b12ddef3b255effa43c8056e0e0d" +checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -382,9 +352,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.18.1" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "byteorder" @@ -394,25 +364,26 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" [[package]] name = "bytestring" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e465647ae23b2823b0753f50decb2d5a86d2bb2cac04788fafd1f80e45378e5f" +checksum = "113b4343b5f6617e7ad401ced8de3cc8b012e73a594347c307b90db3e9271289" dependencies = [ "bytes", ] [[package]] name = "cc" -version = "1.2.27" +version = "1.2.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" +checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215" dependencies = [ + "find-msvc-tools", "jobserver", "libc", "shlex", @@ -420,9 +391,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.1" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" @@ -432,11 +403,10 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.41" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" dependencies = [ - "android-tzdata", "iana-time-zone", "js-sys", "num-traits", @@ -462,9 +432,9 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "const_format" -version = "0.2.34" +version = "0.2.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126f97965c8ad46d6d9163268ff28432e8f6a1196a55578867832e3049df63dd" +checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" dependencies = [ "const_format_proc_macros", ] @@ -480,6 +450,15 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "cookie" version = "0.16.2" @@ -508,9 +487,9 @@ dependencies = [ [[package]] name = "crc" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" dependencies = [ "crc-catalog", ] @@ -523,9 +502,9 @@ checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crc32fast" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] @@ -547,9 +526,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "typenum", @@ -557,9 +536,9 @@ dependencies = [ [[package]] name = "cssparser" -version = "0.34.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c66d1cd8ed61bf80b38432613a7a2f09401ab8d0501110655f8b341484a3e3" +checksum = "dae61cf9c0abb83bd659dab65b7e4e38d8236824c85f0f804f173567bda257d2" dependencies = [ "cssparser-macros", "dtoa-short", @@ -605,41 +584,32 @@ dependencies = [ [[package]] name = "deranged" -version = "0.4.0" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", ] [[package]] name = "derive_more" -version = "0.99.20" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "derive_more" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +checksum = "10b768e943bed7bf2cab53df09f4bc34bfd217cdb57d971e769874c9a6710618" dependencies = [ "derive_more-impl", ] [[package]] name = "derive_more-impl" -version = "2.0.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +checksum = "6d286bfdaf75e988b4a78e013ecd79c581e06399ab53fbacd2d916c2f904f30b" dependencies = [ + "convert_case", "proc-macro2", "quote", + "rustc_version", "syn", "unicode-xid", ] @@ -731,9 +701,9 @@ dependencies = [ [[package]] name = "event-listener" -version = "5.4.0" +version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" dependencies = [ "concurrent-queue", "parking", @@ -741,10 +711,22 @@ dependencies = [ ] [[package]] -name = "flate2" -version = "1.1.2" +name = "fastrand" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "find-msvc-tools" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" + +[[package]] +name = "flate2" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" dependencies = [ "crc32fast", "miniz_oxide", @@ -774,10 +756,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] -name = "form_urlencoded" -version = "1.2.1" +name = "foldhash" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] @@ -898,15 +886,6 @@ dependencies = [ "slab", ] -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - [[package]] name = "generic-array" version = "0.14.7" @@ -919,9 +898,9 @@ dependencies = [ [[package]] name = "getopts" -version = "0.2.23" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1" +checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df" dependencies = [ "unicode-width", ] @@ -935,48 +914,42 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "js-sys", "libc", "r-efi", - "wasi 0.14.2+wasi-0.2.4", + "wasip2", "wasm-bindgen", ] -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - [[package]] name = "governor" -version = "0.8.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be93b4ec2e4710b04d9264c0c7350cdd62a8c20e5e4ac732552ebb8f0debe8eb" +checksum = "6e23d5986fd4364c2fb7498523540618b4b8d92eec6c36a02e565f66748e2f79" dependencies = [ "cfg-if", "dashmap", "futures-sink", "futures-timer", "futures-util", - "getrandom 0.3.3", - "no-std-compat", + "getrandom 0.3.4", + "hashbrown 0.16.1", "nonzero_ext", "parking_lot", "portable-atomic", "quanta", - "rand 0.9.1", + "rand 0.9.2", "smallvec", "spinning_top", "web-time", @@ -984,9 +957,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" dependencies = [ "bytes", "fnv", @@ -1003,16 +976,16 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.10" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9421a676d1b147b16b82c9225157dc629087ef8ec4d5e2960f9437a90dac0a5" +checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" dependencies = [ "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "http 1.3.1", + "http 1.4.0", "indexmap", "slab", "tokio", @@ -1028,13 +1001,24 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "hashbrown" -version = "0.15.4" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", "equivalent", - "foldhash", + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", ] [[package]] @@ -1043,7 +1027,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" dependencies = [ - "hashbrown 0.15.4", + "hashbrown 0.15.5", ] [[package]] @@ -1078,23 +1062,21 @@ dependencies = [ [[package]] name = "home" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "html5ever" -version = "0.29.1" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b7410cae13cbc75623c98ac4cbfd1f0bedddf3227afc24f370cf0f50a44a11c" +checksum = "6452c4751a24e1b99c3260d505eaeee76a050573e61f30ac2c924ddc7236f01e" dependencies = [ "log", - "mac", "markup5ever", - "match_token", ] [[package]] @@ -1110,12 +1092,11 @@ dependencies = [ [[package]] name = "http" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ "bytes", - "fnv", "itoa", ] @@ -1126,7 +1107,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.3.1", + "http 1.4.0", ] [[package]] @@ -1137,7 +1118,7 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http 1.3.1", + "http 1.4.0", "http-body", "pin-project-lite", ] @@ -1156,19 +1137,21 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "1.6.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" dependencies = [ + "atomic-waker", "bytes", "futures-channel", - "futures-util", - "h2 0.4.10", - "http 1.3.1", + "futures-core", + "h2 0.4.12", + "http 1.4.0", "http-body", "httparse", "itoa", "pin-project-lite", + "pin-utils", "smallvec", "tokio", "want", @@ -1180,7 +1163,7 @@ version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "http 1.3.1", + "http 1.4.0", "hyper", "hyper-util", "rustls", @@ -1188,28 +1171,28 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots 1.0.0", + "webpki-roots 1.0.4", ] [[package]] name = "hyper-util" -version = "0.1.14" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" +checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" dependencies = [ "base64", "bytes", "futures-channel", "futures-core", "futures-util", - "http 1.3.1", + "http 1.4.0", "http-body", "hyper", "ipnet", "libc", "percent-encoding", "pin-project-lite", - "socket2", + "socket2 0.6.1", "tokio", "tower-service", "tracing", @@ -1217,9 +1200,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.63" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1241,9 +1224,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", @@ -1254,9 +1237,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -1267,11 +1250,10 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -1282,42 +1264,38 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.0.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", - "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.0.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" [[package]] name = "icu_provider" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "stable_deref_trait", - "tinystr", "writeable", "yoke", "zerofrom", @@ -1327,9 +1305,9 @@ dependencies = [ [[package]] name = "idna" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ "idna_adapter", "smallvec", @@ -1354,23 +1332,12 @@ checksum = "e8a5a9a0ff0086c7a148acb942baaabeadf9504d10400b5a05645853729b9cd2" [[package]] name = "indexmap" -version = "2.9.0" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" dependencies = [ "equivalent", - "hashbrown 0.15.4", -] - -[[package]] -name = "io-uring" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013" -dependencies = [ - "bitflags", - "cfg-if", - "libc", + "hashbrown 0.16.1", ] [[package]] @@ -1381,9 +1348,9 @@ checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "iri-string" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397" dependencies = [ "memchr", "serde", @@ -1406,19 +1373,19 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jobserver" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "libc", ] [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" dependencies = [ "once_cell", "wasm-bindgen", @@ -1441,9 +1408,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.174" +version = "0.2.178" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" [[package]] name = "libm" @@ -1451,6 +1418,17 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +[[package]] +name = "libredox" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" +dependencies = [ + "bitflags", + "libc", + "redox_syscall", +] + [[package]] name = "libsqlite3-sys" version = "0.30.1" @@ -1463,9 +1441,9 @@ dependencies = [ [[package]] name = "litemap" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "local-channel" @@ -1486,19 +1464,18 @@ checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" [[package]] name = "lock_api" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.27" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "lru-slab" @@ -1514,36 +1491,22 @@ checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" [[package]] name = "markup5ever" -version = "0.14.1" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7a7213d12e1864c0f002f52c2923d4556935a43dec5e71355c2760e0f6e7a18" +checksum = "6c3294c4d74d0742910f8c7b466f44dda9eb2d5742c1e430138df290a1e8451c" dependencies = [ "log", - "phf", - "phf_codegen", - "string_cache", - "string_cache_codegen", "tendril", -] - -[[package]] -name = "match_token" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" -dependencies = [ - "proc-macro2", - "quote", - "syn", + "web_atoms", ] [[package]] name = "matchers" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" dependencies = [ - "regex-automata 0.1.10", + "regex-automata", ] [[package]] @@ -1558,9 +1521,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "mensa-upb-api" @@ -1574,8 +1537,10 @@ dependencies = [ "chrono", "dotenvy", "itertools", + "mensa-upb-scraper", "serde", "serde_json", + "shared", "sqlx", "strum", "tokio", @@ -1596,6 +1561,7 @@ dependencies = [ "num-bigint", "reqwest", "scraper", + "shared", "sqlx", "strum", "tokio", @@ -1616,18 +1582,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", + "simd-adler32", ] [[package]] name = "mio" -version = "1.0.4" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", "log", - "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.59.0", + "wasi", + "windows-sys 0.61.2", ] [[package]] @@ -1636,12 +1603,6 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" -[[package]] -name = "no-std-compat" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" - [[package]] name = "nonzero_ext" version = "0.3.0" @@ -1650,12 +1611,11 @@ checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21" [[package]] name = "nu-ansi-term" -version = "0.46.0" +version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "overload", - "winapi", + "windows-sys 0.61.2", ] [[package]] @@ -1670,11 +1630,10 @@ dependencies = [ [[package]] name = "num-bigint-dig" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" dependencies = [ - "byteorder", "lazy_static", "libm", "num-integer", @@ -1721,27 +1680,12 @@ dependencies = [ "libm", ] -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - [[package]] name = "parking" version = "2.2.1" @@ -1750,9 +1694,9 @@ checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -1760,15 +1704,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.11" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -1782,25 +1726,26 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "phf" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" dependencies = [ "phf_macros", "phf_shared", + "serde", ] [[package]] name = "phf_codegen" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" +checksum = "49aa7f9d80421bca176ca8dbfebe668cc7a2684708594ec9f3c0db0805d5d6e1" dependencies = [ "phf_generator", "phf_shared", @@ -1808,19 +1753,19 @@ dependencies = [ [[package]] name = "phf_generator" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" dependencies = [ + "fastrand", "phf_shared", - "rand 0.8.5", ] [[package]] name = "phf_macros" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" dependencies = [ "phf_generator", "phf_shared", @@ -1831,9 +1776,9 @@ dependencies = [ [[package]] name = "phf_shared" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" dependencies = [ "siphasher", ] @@ -1885,9 +1830,9 @@ checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" [[package]] name = "potential_utf" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] @@ -1915,9 +1860,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] @@ -1932,16 +1877,16 @@ dependencies = [ "libc", "once_cell", "raw-cpuid", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", "web-sys", "winapi", ] [[package]] name = "quinn" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" dependencies = [ "bytes", "cfg_aliases", @@ -1950,7 +1895,7 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls", - "socket2", + "socket2 0.6.1", "thiserror", "tokio", "tracing", @@ -1959,14 +1904,14 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.12" +version = "0.11.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e" +checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" dependencies = [ "bytes", - "getrandom 0.3.3", + "getrandom 0.3.4", "lru-slab", - "rand 0.9.1", + "rand 0.9.2", "ring", "rustc-hash", "rustls", @@ -1980,23 +1925,23 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.12" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee4e529991f949c5e25755532370b8af5d114acae52326361d68d47af64aa842" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2", + "socket2 0.6.1", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] name = "quote" -version = "1.0.40" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] @@ -2020,9 +1965,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", @@ -2063,89 +2008,74 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", ] [[package]] name = "raw-cpuid" -version = "11.5.0" +version = "11.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6df7ab838ed27997ba19a4664507e6f82b41fe6e20be42929332156e5e85146" +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" dependencies = [ "bitflags", ] [[package]] name = "redox_syscall" -version = "0.5.13" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.11.1" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.9", - "regex-syntax 0.8.5", + "regex-automata", + "regex-syntax", ] [[package]] name = "regex-automata" -version = "0.1.10" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", -] - -[[package]] -name = "regex-automata" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.5", + "regex-syntax", ] [[package]] name = "regex-lite" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" +checksum = "8d942b98df5e658f56f20d592c7f868833fe38115e65c33003d8cd224b0155da" [[package]] name = "regex-syntax" -version = "0.6.29" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "reqwest" -version = "0.12.20" +version = "0.12.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabf4c97d9130e2bf606614eb937e86edac8292eaa6f422f995d7e8de1eb1813" +checksum = "3b4c14b2d9afca6a60277086b0cc6a6ae0b568f6f7916c943a8cdc79f8be240f" dependencies = [ "base64", "bytes", "encoding_rs", "futures-core", - "h2 0.4.10", - "http 1.3.1", + "h2 0.4.12", + "http 1.4.0", "http-body", "http-body-util", "hyper", @@ -2172,7 +2102,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 1.0.0", + "webpki-roots 1.0.4", ] [[package]] @@ -2191,9 +2121,9 @@ dependencies = [ [[package]] name = "rsa" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" +checksum = "40a0376c50d0358279d9d643e4bf7b7be212f1f4ff1da9070a7b54d22ef75c88" dependencies = [ "const-oid", "digest", @@ -2209,12 +2139,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "rustc-demangle" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" - [[package]] name = "rustc-hash" version = "2.1.1" @@ -2222,10 +2146,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] -name = "rustls" -version = "0.23.28" +name = "rustc_version" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7160e3e10bf4535308537f3c4e1641468cd0e485175d6163087c0393c7d46643" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustls" +version = "0.23.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" dependencies = [ "once_cell", "ring", @@ -2237,9 +2170,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.12.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +checksum = "708c0f9d5f54ba0272468c1d306a52c495b31fa155e91bc25371e6df7996908c" dependencies = [ "web-time", "zeroize", @@ -2247,9 +2180,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.3" +version = "0.103.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" +checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" dependencies = [ "ring", "rustls-pki-types", @@ -2258,9 +2191,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" @@ -2276,9 +2209,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "scraper" -version = "0.23.1" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "527e65d9d888567588db4c12da1087598d0f6f8b346cc2c5abc91f05fc2dffe2" +checksum = "93cecd86d6259499c844440546d02f55f3e17bd286e529e48d1f9f67e92315cb" dependencies = [ "cssparser", "ego-tree", @@ -2291,37 +2224,53 @@ dependencies = [ [[package]] name = "selectors" -version = "0.26.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd568a4c9bb598e291a08244a5c1f5a8a6650bee243b5b0f8dbb3d9cc1d87fe8" +checksum = "feef350c36147532e1b79ea5c1f3791373e61cbd9a6a2615413b3807bb164fb7" dependencies = [ "bitflags", "cssparser", - "derive_more 0.99.20", - "fxhash", + "derive_more", "log", "new_debug_unreachable", "phf", "phf_codegen", "precomputed-hash", + "rustc-hash", "servo_arc", "smallvec", ] [[package]] -name = "serde" -version = "1.0.219" +name = "semver" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -2330,14 +2279,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] @@ -2354,9 +2304,9 @@ dependencies = [ [[package]] name = "servo_arc" -version = "0.4.1" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "204ea332803bd95a0b60388590d59cf6468ec9becf626e2451f1d26a1d972de4" +checksum = "170fb83ab34de17dc69aa7c67482b22218ddb85da56546f9bd6b929e32a05930" dependencies = [ "stable_deref_trait", ] @@ -2392,6 +2342,15 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shared" +version = "0.1.0" +dependencies = [ + "serde", + "sqlx", + "strum", +] + [[package]] name = "shlex" version = "1.3.0" @@ -2400,9 +2359,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.5" +version = "1.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad" dependencies = [ "libc", ] @@ -2417,6 +2376,12 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "simd-adler32" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" + [[package]] name = "siphasher" version = "1.0.1" @@ -2425,9 +2390,9 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "slab" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "smallvec" @@ -2448,6 +2413,16 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "socket2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + [[package]] name = "spin" version = "0.9.8" @@ -2507,7 +2482,7 @@ dependencies = [ "futures-intrusive", "futures-io", "futures-util", - "hashbrown 0.15.4", + "hashbrown 0.15.5", "hashlink", "indexmap", "log", @@ -2680,15 +2655,15 @@ dependencies = [ [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "string_cache" -version = "0.8.9" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" +checksum = "a18596f8c785a729f2819c0f6a7eae6ebeebdfffbfe4214ae6b087f690e31901" dependencies = [ "new_debug_unreachable", "parking_lot", @@ -2699,9 +2674,9 @@ dependencies = [ [[package]] name = "string_cache_codegen" -version = "0.5.4" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" +checksum = "585635e46db231059f76c5849798146164652513eb9e8ab2685939dd90f29b69" dependencies = [ "phf_generator", "phf_shared", @@ -2722,23 +2697,22 @@ dependencies = [ [[package]] name = "strum" -version = "0.27.1" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" -version = "0.27.1" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" dependencies = [ "heck", "proc-macro2", "quote", - "rustversion", "syn", ] @@ -2750,9 +2724,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.103" +version = "2.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" dependencies = [ "proc-macro2", "quote", @@ -2792,18 +2766,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", @@ -2821,9 +2795,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.41" +version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" dependencies = [ "deranged", "itoa", @@ -2836,15 +2810,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" [[package]] name = "time-macros" -version = "0.2.22" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" dependencies = [ "num-conv", "time-core", @@ -2852,9 +2826,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", @@ -2862,9 +2836,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" dependencies = [ "tinyvec_macros", ] @@ -2877,29 +2851,26 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.46.0" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1140bb80481756a8cbe10541f37433b459c5aa1e727b4c020fbfebdc25bf3ec4" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" dependencies = [ - "backtrace", "bytes", - "io-uring", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", - "slab", - "socket2", + "socket2 0.6.1", "tokio-macros", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", @@ -2908,9 +2879,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ "rustls", "tokio", @@ -2929,9 +2900,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.15" +version = "0.7.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" +checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" dependencies = [ "bytes", "futures-core", @@ -2957,14 +2928,14 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ "bitflags", "bytes", "futures-util", - "http 1.3.1", + "http 1.4.0", "http-body", "iri-string", "pin-project-lite", @@ -2987,9 +2958,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647" dependencies = [ "log", "pin-project-lite", @@ -2999,9 +2970,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", @@ -3010,9 +2981,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c" dependencies = [ "once_cell", "valuable", @@ -3041,14 +3012,14 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.19" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" dependencies = [ "matchers", "nu-ansi-term", "once_cell", - "regex", + "regex-automata", "serde", "serde_json", "sharded-slab", @@ -3068,9 +3039,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicode-bidi" @@ -3080,30 +3051,36 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-normalization" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" dependencies = [ "tinyvec", ] [[package]] name = "unicode-properties" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" [[package]] name = "unicode-xid" @@ -3119,13 +3096,14 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.4" +version = "2.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] [[package]] @@ -3142,9 +3120,9 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.17.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" +checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" dependencies = [ "js-sys", "wasm-bindgen", @@ -3184,12 +3162,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" +name = "wasip2" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen", ] [[package]] @@ -3200,35 +3178,22 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.50" +version = "0.4.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" dependencies = [ "cfg-if", "js-sys", @@ -3239,9 +3204,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3249,31 +3214,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" dependencies = [ + "bumpalo", "proc-macro2", "quote", "syn", - "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.77" +version = "0.3.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" dependencies = [ "js-sys", "wasm-bindgen", @@ -3289,31 +3254,43 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web_atoms" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acd0c322f146d0f8aad130ce6c187953889359584497dac6561204c8e17bb43d" +dependencies = [ + "phf", + "phf_codegen", + "string_cache", + "string_cache_codegen", +] + [[package]] name = "webpki-roots" version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" dependencies = [ - "webpki-roots 1.0.0", + "webpki-roots 1.0.4", ] [[package]] name = "webpki-roots" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2853738d1cc4f2da3a225c18ec6c3721abb31961096e9dbf5ab35fa88b19cfdb" +checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e" dependencies = [ "rustls-pki-types", ] [[package]] name = "whoami" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6994d13118ab492c3c80c1f81928718159254c53c472bf9ce36f8dae4add02a7" +checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" dependencies = [ - "redox_syscall", + "libredox", "wasite", ] @@ -3341,9 +3318,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.61.2" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", @@ -3354,9 +3331,9 @@ dependencies = [ [[package]] name = "windows-implement" -version = "0.60.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", @@ -3365,9 +3342,9 @@ dependencies = [ [[package]] name = "windows-interface" -version = "0.59.1" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", @@ -3376,24 +3353,24 @@ dependencies = [ [[package]] name = "windows-link" -version = "0.1.3" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-result" -version = "0.3.4" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ "windows-link", ] [[package]] name = "windows-strings" -version = "0.4.2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ "windows-link", ] @@ -3418,11 +3395,20 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.59.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.52.6", + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", ] [[package]] @@ -3449,13 +3435,30 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -3468,6 +3471,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -3480,6 +3489,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -3492,12 +3507,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -3510,6 +3537,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -3522,6 +3555,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -3534,6 +3573,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -3547,27 +3592,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] -name = "wit-bindgen-rt" -version = "0.39.0" +name = "windows_x86_64_msvc" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags", -] +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "yoke" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -3575,9 +3622,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", @@ -3587,18 +3634,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.26" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.26" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" dependencies = [ "proc-macro2", "quote", @@ -3628,15 +3675,15 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" [[package]] name = "zerotrie" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", @@ -3645,9 +3692,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.2" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", @@ -3656,9 +3703,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", @@ -3685,9 +3732,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.15+zstd.1.5.7" +version = "2.0.16+zstd.1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" dependencies = [ "cc", "pkg-config", diff --git a/Cargo.toml b/Cargo.toml index ba7f95a..ce20ed7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ [workspace] members = [ "scraper", + "shared", "web-api", ] resolver = "2" @@ -14,12 +15,14 @@ repository = "https://github.com/moritz-hoelting/mensa-upb-api" readme = "README.md" [workspace.dependencies] -anyhow = "1.0.93" -chrono = "0.4.38" +anyhow = "1.0.100" +chrono = "0.4.42" dotenvy = "0.15.7" +futures = "0.3.31" itertools = "0.14.0" +serde = { version = "1.0.228", features = ["derive"] } sqlx = "0.8.2" -strum = "0.27.1" -tokio = "1.46.0" -tracing = "0.1.40" -tracing-subscriber = "0.3.18" \ No newline at end of file +strum = "0.27.2" +tokio = "1.48.0" +tracing = "0.1.43" +tracing-subscriber = "0.3.22" diff --git a/migrations/20251215165721_allow_refreshes.down.sql b/migrations/20251215165721_allow_refreshes.down.sql new file mode 100644 index 0000000..0101b09 --- /dev/null +++ b/migrations/20251215165721_allow_refreshes.down.sql @@ -0,0 +1,33 @@ +-- Add down migration script here + +DROP VIEW IF EXISTS meals_view; + +DROP INDEX IF EXISTS idx_meals_date_canteen_latest; + +DROP INDEX IF EXISTS idx_meals_refreshed_at; + +DELETE FROM meals WHERE is_latest = FALSE; + +ALTER TABLE meals +DROP CONSTRAINT meals_pkey; + +ALTER TABLE meals +DROP COLUMN id; + +ALTER TABLE meals +ADD CONSTRAINT meals_pkey PRIMARY KEY (date, canteen, name); + +ALTER TABLE meals +DROP COLUMN is_latest; + +ALTER TABLE meals +DROP COLUMN refreshed_at; + +ALTER TABLE meals +ALTER COLUMN dish_type +TYPE TEXT +USING dish_type::TEXT; + +DROP TABLE IF EXISTS canteens_scraped; + +DROP TYPE IF EXISTS dish_type_enum; \ No newline at end of file diff --git a/migrations/20251215165721_allow_refreshes.up.sql b/migrations/20251215165721_allow_refreshes.up.sql new file mode 100644 index 0000000..09c620e --- /dev/null +++ b/migrations/20251215165721_allow_refreshes.up.sql @@ -0,0 +1,51 @@ +-- Add up migration script here + +CREATE TABLE canteens_scraped ( + canteen TEXT NOT NULL, + scraped_for DATE NOT NULL, + scraped_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + PRIMARY KEY (canteen, scraped_for, scraped_at) +); + +ALTER TABLE meals +ADD COLUMN id UUID NOT NULL DEFAULT gen_random_uuid(); + +-- Remove existing primary key constraints +DO $$ +DECLARE + r RECORD; +BEGIN + FOR r IN + SELECT conname + FROM pg_constraint + WHERE contype = 'p' + AND conrelid = 'meals'::regclass + LOOP + EXECUTE format('ALTER TABLE meals DROP CONSTRAINT %I', r.conname); + END LOOP; +END $$; + +ALTER TABLE meals +ADD CONSTRAINT meals_pkey PRIMARY KEY (id); + +ALTER TABLE meals +ADD COLUMN is_latest BOOLEAN NOT NULL DEFAULT TRUE; + +ALTER TABLE meals +ADD COLUMN refreshed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(); + +CREATE TYPE dish_type_enum AS ENUM ('main', 'side', 'dessert'); + +ALTER TABLE meals +ALTER COLUMN dish_type +TYPE dish_type_enum +USING dish_type::dish_type_enum; + +CREATE INDEX idx_meals_date_canteen_latest ON meals(date, canteen, is_latest); + +CREATE INDEX idx_meals_refreshed_at ON meals(refreshed_at); + +CREATE VIEW meals_view AS +SELECT id, date, canteen, name, dish_type, image_src, price_students, price_employees, price_guests, vegan, vegetarian +FROM meals +WHERE is_latest = TRUE; \ No newline at end of file diff --git a/scraper/Cargo.toml b/scraper/Cargo.toml index a05b056..a9ca1a9 100644 --- a/scraper/Cargo.toml +++ b/scraper/Cargo.toml @@ -14,11 +14,12 @@ anyhow = { workspace = true } chrono = { workspace = true } const_format = "0.2.33" dotenvy = { workspace = true } -futures = "0.3.31" +futures = { workspace = true } itertools = { workspace = true } num-bigint = "0.4.6" reqwest = { version = "0.12.9", default-features = false, features = ["charset", "rustls-tls", "http2"] } -scraper = "0.23.1" +scraper = "0.25.0" +shared = { path = "../shared" } sqlx = { workspace = true, features = ["runtime-tokio-rustls", "postgres", "migrate", "chrono", "uuid", "bigdecimal"] } strum = { workspace = true, features = ["derive"] } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } diff --git a/scraper/src/canteen.rs b/scraper/src/canteen.rs index 15b2900..6af6fee 100644 --- a/scraper/src/canteen.rs +++ b/scraper/src/canteen.rs @@ -1,24 +1,14 @@ -use std::str::FromStr; - use const_format::concatcp; -use strum::EnumIter; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, EnumIter, Hash)] -pub enum Canteen { - Forum, - Academica, - Picknick, - BonaVista, - GrillCafe, - ZM2, - Basilica, - Atrium, -} +use shared::Canteen; const POST_URL_BASE: &str = "https://www.studierendenwerk-pb.de/gastronomie/speiseplaene/"; -impl Canteen { - pub fn get_url(&self) -> &str { +pub trait CanteenExt { + fn get_url(&self) -> &str; +} + +impl CanteenExt for Canteen { + fn get_url(&self) -> &str { match self { Self::Forum => concatcp!(POST_URL_BASE, "forum/"), Self::Academica => concatcp!(POST_URL_BASE, "mensa-academica/"), @@ -30,35 +20,4 @@ impl Canteen { Self::Atrium => concatcp!(POST_URL_BASE, "mensa-atrium-lippstadt/"), } } - - pub fn get_identifier(&self) -> &str { - match self { - Self::Forum => "forum", - Self::Academica => "academica", - Self::Picknick => "picknick", - Self::BonaVista => "bona-vista", - Self::GrillCafe => "grillcafe", - Self::ZM2 => "zm2", - Self::Basilica => "basilica", - Self::Atrium => "atrium", - } - } -} - -impl FromStr for Canteen { - type Err = String; - - fn from_str(s: &str) -> Result { - match s { - "forum" => Ok(Self::Forum), - "academica" => Ok(Self::Academica), - "picknick" => Ok(Self::Picknick), - "bona-vista" => Ok(Self::BonaVista), - "grillcafe" => Ok(Self::GrillCafe), - "zm2" => Ok(Self::ZM2), - "basilica" => Ok(Self::Basilica), - "atrium" => Ok(Self::Atrium), - invalid => Err(format!("Invalid canteen identifier: {}", invalid)), - } - } } diff --git a/scraper/src/dish.rs b/scraper/src/dish.rs index 3c6a876..2bb8bcf 100644 --- a/scraper/src/dish.rs +++ b/scraper/src/dish.rs @@ -1,7 +1,6 @@ -use std::fmt::Display; - use itertools::Itertools; use scraper::ElementRef; +use shared::DishType; #[derive(Debug, Clone, PartialEq, Eq)] pub struct Dish { @@ -125,21 +124,3 @@ impl PartialOrd for Dish { self.name.partial_cmp(&other.name) } } - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum DishType { - Main, - Side, - Dessert, -} - -impl Display for DishType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let s = match self { - Self::Main => "main", - Self::Side => "side", - Self::Dessert => "dessert", - }; - f.write_str(s) - } -} diff --git a/scraper/src/lib.rs b/scraper/src/lib.rs index 949c0a8..ed57f22 100644 --- a/scraper/src/lib.rs +++ b/scraper/src/lib.rs @@ -1,12 +1,15 @@ mod canteen; mod dish; mod menu; +mod refresh; pub mod util; use std::{error::Error, fmt::Display}; -pub use canteen::Canteen; pub use dish::Dish; +pub use menu::scrape_menu; +pub use refresh::check_refresh; +pub use util::scrape_canteens_at_days; #[derive(Debug, Clone)] struct CustomError(String); diff --git a/scraper/src/main.rs b/scraper/src/main.rs index 64201bc..9e0607a 100644 --- a/scraper/src/main.rs +++ b/scraper/src/main.rs @@ -3,8 +3,9 @@ use std::{collections::HashSet, env}; use anyhow::Result; use chrono::{Duration, Utc}; use itertools::Itertools as _; -use mensa_upb_scraper::{util, Canteen}; -use strum::IntoEnumIterator; +use mensa_upb_scraper::util; +use shared::Canteen; +use strum::IntoEnumIterator as _; #[tokio::main] async fn main() -> Result<()> { @@ -22,7 +23,7 @@ async fn main() -> Result<()> { let end_date = (Utc::now() + Duration::days(6)).date_naive(); let already_scraped = sqlx::query!( - "SELECT DISTINCT date, canteen FROM MEALS WHERE date >= $1 AND date <= $2", + "SELECT DISTINCT scraped_for, canteen FROM canteens_scraped WHERE scraped_for >= $1 AND scraped_for <= $2", start_date, end_date ) @@ -31,7 +32,7 @@ async fn main() -> Result<()> { .into_iter() .map(|r| { ( - r.date, + r.scraped_for, r.canteen.parse::().expect("Invalid db entry"), ) }) @@ -49,15 +50,12 @@ async fn main() -> Result<()> { let date_canteen_combinations = (0..7) .map(|d| (Utc::now() + Duration::days(d)).date_naive()) .cartesian_product(Canteen::iter()) - .filter(|entry| !filter_canteens.contains(&entry.1) && !already_scraped.contains(entry)) + .filter(|entry @ (_, canteen)| { + !filter_canteens.contains(canteen) && !already_scraped.contains(entry) + }) .collect::>(); - util::async_for_each(&date_canteen_combinations, |(date, canteen, menu)| { - let db = db.clone(); - async move { - util::add_menu_to_db(&db, &date, canteen, menu).await; - } - }) - .await; + + util::scrape_canteens_at_days(&db, &date_canteen_combinations).await?; tracing::info!("Finished scraping menu"); diff --git a/scraper/src/menu.rs b/scraper/src/menu.rs index 64e0cf6..e33a48b 100644 --- a/scraper/src/menu.rs +++ b/scraper/src/menu.rs @@ -1,7 +1,8 @@ use anyhow::Result; use chrono::NaiveDate; +use shared::{Canteen, DishType}; -use crate::{dish::DishType, Canteen, CustomError, Dish}; +use crate::{canteen::CanteenExt as _, CustomError, Dish}; #[tracing::instrument] pub async fn scrape_menu(date: &NaiveDate, canteen: Canteen) -> Result> { diff --git a/scraper/src/refresh.rs b/scraper/src/refresh.rs new file mode 100644 index 0000000..e9560ea --- /dev/null +++ b/scraper/src/refresh.rs @@ -0,0 +1,63 @@ +use std::{collections::BTreeSet, str::FromStr}; + +use chrono::{NaiveDate, Utc}; +use shared::Canteen; + +use crate::util; + +pub async fn check_refresh(db: &sqlx::PgPool, date: NaiveDate, canteens: &[Canteen]) -> bool { + let canteens_needing_refresh = match sqlx::query!( + r#"SELECT canteen, max(scraped_at) AS "scraped_at!" FROM canteens_scraped WHERE canteen = ANY($1) AND scraped_for = $2 GROUP BY canteen"#, + &canteens + .iter() + .map(|c| c.get_identifier().to_string()) + .collect::>(), + date + ) + .fetch_all(db) + .await + { + Ok(v) => v.iter().filter_map(|r| if needs_refresh(r.scraped_at, date) { Some(Canteen::from_str(&r.canteen).expect("malformed db canteen entry")) } else { None }).collect::>(), + Err(err) => { + tracing::error!("Error checking for existing scrapes: {}", err); + return false; + } + }; + + if canteens_needing_refresh.is_empty() { + false + } else { + tracing::debug!( + "Refreshing menu for date {} for canteens: {:?}", + date, + canteens_needing_refresh + ); + + if let Err(err) = util::scrape_canteens_at_days( + db, + &canteens_needing_refresh + .iter() + .map(|c| (date, *c)) + .collect::>(), + ) + .await + { + tracing::error!("Error during refresh scrape: {}", err); + return false; + } + + true + } +} + +fn needs_refresh(last_refreshed: chrono::DateTime, date_entry: chrono::NaiveDate) -> bool { + let now = Utc::now(); + + if date_entry == now.naive_local().date() { + now.signed_duration_since(last_refreshed) >= chrono::Duration::hours(8) + } else if date_entry < now.naive_local().date() { + false + } else { + now.signed_duration_since(last_refreshed) >= chrono::Duration::days(2) + } +} diff --git a/scraper/src/util.rs b/scraper/src/util.rs index b742ce9..6854199 100644 --- a/scraper/src/util.rs +++ b/scraper/src/util.rs @@ -1,64 +1,111 @@ -use std::{env, future::Future}; +use std::env; use anyhow::Result; use chrono::NaiveDate; use futures::StreamExt as _; use num_bigint::BigInt; -use sqlx::{postgres::PgPoolOptions, types::BigDecimal, PgPool}; +use shared::{Canteen, DishType}; +use sqlx::{postgres::PgPoolOptions, types::BigDecimal, PgPool, PgTransaction}; -use crate::{menu::scrape_menu, Canteen, Dish}; - -pub async fn async_for_each(date_canteen_combinations: &[(NaiveDate, Canteen)], f: F) -where - F: FnMut((NaiveDate, Canteen, Vec)) -> Fut, - Fut: Future, -{ - futures::stream::iter(date_canteen_combinations) - .then(|(date, canteen)| async move { (*date, *canteen, scrape_menu(date, *canteen).await) }) - .filter_map(|(date, canteen, menu)| async move { menu.ok().map(|menu| (date, canteen, menu)) }) - .for_each(f) - .await; -} +use crate::{scrape_menu, Dish}; pub fn get_db() -> Result { Ok(PgPoolOptions::new() .connect_lazy(&env::var("DATABASE_URL").expect("missing DATABASE_URL env variable"))?) } -#[tracing::instrument(skip(db))] -pub async fn add_meal_to_db(db: &PgPool, date: &NaiveDate, canteen: Canteen, dish: &Dish) -> Result<()> { - let vegan = dish.is_vegan(); +pub async fn scrape_canteens_at_days( + db: &PgPool, + date_canteen_combinations: &[(NaiveDate, Canteen)], +) -> Result<()> { + let (tx, mut rx) = tokio::sync::mpsc::channel::<(NaiveDate, Canteen, Vec)>(128); + + let mut transaction = db.begin().await?; + + for (date, canteen) in date_canteen_combinations { + sqlx::query!( + "UPDATE meals SET is_latest = FALSE WHERE date = $1 AND canteen = $2 AND is_latest = TRUE", + date, + canteen.get_identifier() + ) + .execute(&mut *transaction) + .await + .ok(); + } + + let insert_handle = tokio::spawn(async move { + while let Some((date, canteen, menu)) = rx.recv().await { + add_menu_to_db(&mut transaction, &date, canteen, menu).await?; + } + + transaction.commit().await + }); + + futures::stream::iter(date_canteen_combinations) + .then(|(date, canteen)| async move { (*date, *canteen, scrape_menu(date, *canteen).await) }) + .filter_map( + |(date, canteen, menu)| async move { menu.ok().map(|menu| (date, canteen, menu)) }, + ) + .for_each(|(date, canteen, menu)| { + let tx = tx.clone(); + async move { + tx.send((date, canteen, menu)).await.ok(); + } + }) + .await; + + drop(tx); + + insert_handle.await??; + + Ok(()) +} + +pub async fn add_menu_to_db( + db: &mut PgTransaction<'_>, + date: &NaiveDate, + canteen: Canteen, + menu: Vec, +) -> Result<(), sqlx::Error> { + if menu.is_empty() { + return Ok(()); + } + + let mut query = sqlx::QueryBuilder::new("INSERT INTO meals (date,canteen,name,dish_type,image_src,price_students,price_employees,price_guests,vegan,vegetarian) "); + + query + .push_values(menu, |mut sep, item| { + let vegan = item.is_vegan(); + + sep.push_bind(date) + .push_bind(canteen.get_identifier()) + .push_bind(item.get_name().to_string()) + .push_bind(item.get_type() as DishType) + .push_bind(item.get_image_src().map(str::to_string)) + .push_bind(price_to_bigdecimal(item.get_price_students())) + .push_bind(price_to_bigdecimal(item.get_price_employees())) + .push_bind(price_to_bigdecimal(item.get_price_guests())) + .push_bind(vegan) + .push_bind(vegan || item.is_vegetarian()); + }) + .build() + .execute(&mut **db) + .await?; sqlx::query!( - "INSERT INTO meals (date,canteen,name,dish_type,image_src,price_students,price_employees,price_guests,vegan,vegetarian) - VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10) - ON CONFLICT (date,canteen,name) DO NOTHING", - date, canteen.get_identifier(), dish.get_name(), - dish.get_type().to_string(), dish.get_image_src(), - price_to_bigdecimal(dish.get_price_students()), - price_to_bigdecimal(dish.get_price_employees()), - price_to_bigdecimal(dish.get_price_guests()), - vegan, vegan || dish.is_vegetarian() - ).execute(db).await.inspect_err(|e| { - tracing::error!("error during database insert: {}", e); - })?; + "INSERT INTO canteens_scraped (scraped_for, canteen) VALUES ($1, $2)", + date, + canteen.get_identifier() + ) + .execute(&mut **db) + .await?; tracing::trace!("Insert to DB successfull"); Ok(()) } -pub async fn add_menu_to_db(db: &PgPool, date: &NaiveDate, canteen: Canteen, menu: Vec) { - futures::stream::iter(menu) - .for_each(|dish| async move { - if !dish.get_name().is_empty() { - add_meal_to_db(db, date, canteen, &dish).await.ok(); - } - }) - .await; -} - pub fn price_to_bigdecimal(s: Option<&str>) -> BigDecimal { s.and_then(|p| p.trim_end_matches(" €").replace(',', ".").parse().ok()) - .unwrap_or_else(|| BigDecimal::new(BigInt::from(99999), 2)) + .unwrap_or_else(|| BigDecimal::from_bigint(BigInt::from(99999), 2)) } diff --git a/shared/Cargo.toml b/shared/Cargo.toml new file mode 100644 index 0000000..687aaea --- /dev/null +++ b/shared/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "shared" +version = "0.1.0" +edition = "2024" +license.workspace = true +authors.workspace = true +repository.workspace = true +readme.workspace = true + +[dependencies] +serde = { workspace = true, features = ["derive"] } +strum = { workspace = true, features = ["derive"] } +sqlx = { workspace = true } \ No newline at end of file diff --git a/web-api/src/canteen.rs b/shared/src/canteen.rs similarity index 100% rename from web-api/src/canteen.rs rename to shared/src/canteen.rs diff --git a/shared/src/lib.rs b/shared/src/lib.rs new file mode 100644 index 0000000..e1c7ffc --- /dev/null +++ b/shared/src/lib.rs @@ -0,0 +1,24 @@ +use std::fmt::Display; + +mod canteen; +pub use canteen::Canteen; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, sqlx::Type)] +#[sqlx(type_name = "dish_type_enum")] +#[sqlx(rename_all = "lowercase")] +pub enum DishType { + Main, + Side, + Dessert, +} + +impl Display for DishType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let s = match self { + Self::Main => "main", + Self::Side => "side", + Self::Dessert => "dessert", + }; + f.write_str(s) + } +} diff --git a/web-api/Cargo.toml b/web-api/Cargo.toml index 828af51..231179e 100644 --- a/web-api/Cargo.toml +++ b/web-api/Cargo.toml @@ -10,18 +10,20 @@ edition = "2021" publish = false [dependencies] -actix-cors = "0.7.0" -actix-governor = { version = "0.8.0", features = ["log"] } -actix-web = "4.9.0" +actix-cors = "0.7.1" +actix-governor = { version = "0.10.0", features = ["log"] } +actix-web = "4.12.1" anyhow = { workspace = true } -bigdecimal = { version = "0.4.6", features = ["serde"] } +bigdecimal = { version = "0.4.9", features = ["serde"] } chrono = { workspace = true, features = ["serde"] } dotenvy = { workspace = true } itertools = { workspace = true } -serde = { version = "1.0.215", features = ["derive"] } -serde_json = "1.0.133" +mensa-upb-scraper = { path = "../scraper" } +serde = { workspace = true, features = ["derive"] } +serde_json = "1.0.145" +shared = { path = "../shared" } sqlx = { workspace = true, features = ["runtime-tokio-rustls", "postgres", "migrate", "chrono", "uuid", "bigdecimal"] } strum = { workspace = true, features = ["derive"] } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } -tracing = "0.1.40" +tracing = "0.1.43" tracing-subscriber = { workspace = true, features = ["env-filter"] } diff --git a/web-api/src/dish.rs b/web-api/src/dish.rs index 65b6497..a05c8a3 100644 --- a/web-api/src/dish.rs +++ b/web-api/src/dish.rs @@ -1,7 +1,6 @@ use bigdecimal::BigDecimal; use serde::{Deserialize, Serialize}; - -use crate::Canteen; +use shared::Canteen; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct Dish { diff --git a/web-api/src/endpoints/menu.rs b/web-api/src/endpoints/menu.rs index a6d9942..bade622 100644 --- a/web-api/src/endpoints/menu.rs +++ b/web-api/src/endpoints/menu.rs @@ -5,13 +5,16 @@ use chrono::NaiveDate; use itertools::Itertools as _; use serde::{Deserialize, Serialize}; use serde_json::json; +use shared::Canteen; use sqlx::PgPool; -use crate::{Canteen, Menu}; +use crate::Menu; #[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] struct MenuQuery { date: Option, + no_update: Option, } #[get("/menu/{canteen}")] async fn menu( @@ -31,7 +34,7 @@ async fn menu( .date .unwrap_or_else(|| chrono::Local::now().date_naive()); - let menu = Menu::query(&db, date, &canteens).await; + let menu = Menu::query(&db, date, &canteens, !query.no_update.unwrap_or_default()).await; if let Ok(menu) = menu { HttpResponse::Ok().json(menu) diff --git a/web-api/src/endpoints/mod.rs b/web-api/src/endpoints/mod.rs index 8151381..ce49768 100644 --- a/web-api/src/endpoints/mod.rs +++ b/web-api/src/endpoints/mod.rs @@ -1,10 +1,9 @@ use actix_web::{get, web::ServiceConfig, HttpResponse, Responder}; use itertools::Itertools as _; use serde_json::json; +use shared::Canteen; use strum::IntoEnumIterator as _; -use crate::Canteen; - mod menu; pub fn configure(cfg: &mut ServiceConfig) { diff --git a/web-api/src/lib.rs b/web-api/src/lib.rs index 4e528eb..815bb34 100644 --- a/web-api/src/lib.rs +++ b/web-api/src/lib.rs @@ -1,12 +1,10 @@ -mod canteen; mod dish; pub mod endpoints; mod governor; mod menu; -use std::{error::Error, fmt::Display, sync::LazyLock}; +use std::sync::LazyLock; -pub use canteen::Canteen; pub use dish::{Dish, DishPrices}; pub use governor::get_governor; pub use menu::Menu; @@ -16,26 +14,3 @@ pub(crate) static USE_X_FORWARDED_HOST: LazyLock = LazyLock::new(|| { .map(|val| val == "true") .unwrap_or(false) }); - -#[derive(Debug, Clone)] -struct CustomError(String); - -impl Display for CustomError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) - } -} - -impl Error for CustomError {} - -impl From<&str> for CustomError { - fn from(s: &str) -> Self { - CustomError(s.to_string()) - } -} - -impl From for CustomError { - fn from(s: String) -> Self { - CustomError(s) - } -} diff --git a/web-api/src/menu.rs b/web-api/src/menu.rs index 53321fe..80824fe 100644 --- a/web-api/src/menu.rs +++ b/web-api/src/menu.rs @@ -1,10 +1,11 @@ +use chrono::NaiveDate; +use mensa_upb_scraper::check_refresh; +use serde::{Deserialize, Serialize}; +use shared::{Canteen, DishType}; +use sqlx::PgPool; use std::str::FromStr as _; -use chrono::NaiveDate; -use serde::{Deserialize, Serialize}; -use sqlx::PgPool; - -use crate::{Canteen, Dish, DishPrices}; +use crate::{Dish, DishPrices}; #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct Menu { @@ -15,18 +16,32 @@ pub struct Menu { } impl Menu { - pub async fn query(db: &PgPool, date: NaiveDate, canteens: &[Canteen]) -> sqlx::Result { - let canteens = canteens + pub async fn query( + db: &PgPool, + date: NaiveDate, + canteens: &[Canteen], + allow_refresh: bool, + ) -> sqlx::Result { + let canteens_str = canteens .iter() .map(|c| c.get_identifier().to_string()) .collect::>(); - let result = sqlx::query!("SELECT name, array_agg(DISTINCT canteen ORDER BY canteen) AS canteens, dish_type, image_src, price_students, price_employees, price_guests, vegan, vegetarian - FROM meals WHERE date = $1 AND canteen = ANY($2) + + let query_db = async || { + sqlx::query!(r#"SELECT name, array_agg(DISTINCT canteen ORDER BY canteen) AS "canteens!", dish_type AS "dish_type: DishType", image_src, price_students, price_employees, price_guests, vegan, vegetarian + FROM meals WHERE date = $1 AND canteen = ANY($2) AND is_latest = TRUE GROUP BY name, dish_type, image_src, price_students, price_employees, price_guests, vegan, vegetarian - ORDER BY name", - date, &canteens) + ORDER BY name"#, + date, &canteens_str) .fetch_all(db) - .await?; + .await + }; + + let mut result = query_db().await?; + + if allow_refresh && check_refresh(db, date, canteens).await { + result = query_db().await?; + } let mut main_dishes = Vec::new(); let mut side_dishes = Vec::new(); @@ -36,12 +51,11 @@ impl Menu { let dish = Dish { name: row.name, image_src: row.image_src, - canteens: row.canteens.map_or_else(Vec::new, |canteens| { - canteens - .iter() - .map(|canteen| Canteen::from_str(canteen).expect("Invalid database entry")) - .collect() - }), + canteens: row + .canteens + .iter() + .map(|canteen| Canteen::from_str(canteen).expect("Invalid database entry")) + .collect(), vegan: row.vegan, vegetarian: row.vegetarian, price: DishPrices { @@ -50,11 +64,11 @@ impl Menu { guests: row.price_guests.with_prec(5).with_scale(2), }, }; - if row.dish_type == "main" { + if row.dish_type == DishType::Main { main_dishes.push(dish); - } else if row.dish_type == "side" { + } else if row.dish_type == DishType::Side { side_dishes.push(dish); - } else if row.dish_type == "dessert" { + } else if row.dish_type == DishType::Dessert { desserts.push(dish); } }