From d4bdc677a9bf10b24469249983fafe02db55a5ba Mon Sep 17 00:00:00 2001 From: lonelyhentxi Date: Sat, 10 May 2025 02:34:11 +0800 Subject: [PATCH] feat: more task system --- Cargo.lock | 898 ++++++++---------- Cargo.toml | 4 +- apps/recorder/src/app/builder.rs | 34 +- .../src/app/config/default_mixin.toml | 2 + apps/recorder/src/app/config/mod.rs | 6 +- apps/recorder/src/app/context.rs | 12 +- apps/recorder/src/bin/migrate_down.rs | 16 + apps/recorder/src/database/service.rs | 35 +- apps/recorder/src/extract/mikan/mod.rs | 1 + apps/recorder/src/extract/mikan/web.rs | 129 +-- .../mikan/mikan_scrape_season_subscription.rs | 5 + apps/recorder/src/graphql/mikan/mod.rs | 2 +- apps/recorder/src/graphql/schema_root.rs | 8 +- apps/recorder/src/lib.rs | 3 +- apps/recorder/src/message/config.rs | 4 + apps/recorder/src/message/mod.rs | 5 + apps/recorder/src/message/service.rs | 12 + apps/recorder/src/migrations/defs.rs | 12 + .../src/migrations/m20220101_000001_init.rs | 32 +- .../m20240224_082543_add_downloads.rs | 11 +- ...240225_060853_subscriber_add_downloader.rs | 103 -- .../src/migrations/m20241231_000001_auth.rs | 3 +- .../m20250501_021523_credential_3rd.rs | 15 +- .../m20250508_022044_subscriber_tasks.rs | 81 ++ apps/recorder/src/migrations/mod.rs | 4 +- apps/recorder/src/models/mod.rs | 1 + apps/recorder/src/models/subscriber_tasks.rs | 153 +++ apps/recorder/src/models/subscribers.rs | 10 + apps/recorder/src/models/subscriptions.rs | 2 - apps/recorder/src/{tasks => task}/config.rs | 0 apps/recorder/src/task/core.rs | 81 ++ apps/recorder/src/task/mikan/mod.rs | 3 + .../task/mikan/scrape_season_subscription.rs | 45 + apps/recorder/src/task/mod.rs | 13 + apps/recorder/src/task/registry.rs | 33 + apps/recorder/src/task/service.rs | 77 ++ apps/recorder/src/tasks/mikan/mod.rs | 6 - .../tasks/mikan/scrape_season_subscription.rs | 87 -- apps/recorder/src/tasks/mod.rs | 6 - apps/recorder/src/tasks/service.rs | 41 - apps/recorder/src/test_utils/app.rs | 11 +- apps/webui/src/infra/graphql/gql/graphql.ts | 6 + justfile | 3 + 43 files changed, 1180 insertions(+), 835 deletions(-) create mode 100644 apps/recorder/src/bin/migrate_down.rs create mode 100644 apps/recorder/src/graphql/mikan/mikan_scrape_season_subscription.rs create mode 100644 apps/recorder/src/message/config.rs create mode 100644 apps/recorder/src/message/mod.rs create mode 100644 apps/recorder/src/message/service.rs delete mode 100644 apps/recorder/src/migrations/m20240225_060853_subscriber_add_downloader.rs create mode 100644 apps/recorder/src/migrations/m20250508_022044_subscriber_tasks.rs create mode 100644 apps/recorder/src/models/subscriber_tasks.rs rename apps/recorder/src/{tasks => task}/config.rs (100%) create mode 100644 apps/recorder/src/task/core.rs create mode 100644 apps/recorder/src/task/mikan/mod.rs create mode 100644 apps/recorder/src/task/mikan/scrape_season_subscription.rs create mode 100644 apps/recorder/src/task/mod.rs create mode 100644 apps/recorder/src/task/registry.rs create mode 100644 apps/recorder/src/task/service.rs delete mode 100644 apps/recorder/src/tasks/mikan/mod.rs delete mode 100644 apps/recorder/src/tasks/mikan/scrape_season_subscription.rs delete mode 100644 apps/recorder/src/tasks/mod.rs delete mode 100644 apps/recorder/src/tasks/service.rs diff --git a/Cargo.lock b/Cargo.lock index 5059b8f..f7ef287 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -68,22 +68,22 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", "once_cell", "version_check", ] [[package]] name = "ahash" -version = "0.8.11" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", - "getrandom 0.2.15", + "getrandom 0.3.3", "once_cell", "version_check", - "zerocopy 0.7.35", + "zerocopy", ] [[package]] @@ -189,9 +189,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.97" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "apalis" @@ -304,14 +304,14 @@ checksum = "affbba0d438add06462a0371997575927bc05052f7ec486e7a4ca405c956c3d7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] name = "async-compression" -version = "0.4.22" +version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a194f9d963d8099596278594b3107448656ba73831c9d8c783e613ce86da64" +checksum = "b37fc50485c4f3f736a4fb14199f6d5f5ba008d7f28fe710306c92780f004c07" dependencies = [ "brotli", "flate2", @@ -392,7 +392,7 @@ dependencies = [ "proc-macro2", "quote", "strum", - "syn 2.0.100", + "syn 2.0.101", "thiserror 1.0.69", ] @@ -450,7 +450,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -461,7 +461,7 @@ checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -483,7 +483,7 @@ dependencies = [ "derive_builder", "diligent-date-parser", "never", - "quick-xml 0.37.4", + "quick-xml", ] [[package]] @@ -509,9 +509,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "axum" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de45108900e1f9b9242f7f2e254aa3e2c029c921c258fe9e6b4217eeebd54288" +checksum = "021e862c184ae977658b36c4500f7feac3221ca5da43e3f25bd04ab6c79a29b5" dependencies = [ "axum-core", "axum-macros", @@ -595,7 +595,7 @@ checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -604,16 +604,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", "instant", "rand 0.8.5", ] [[package]] name = "backon" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "970d91570c01a8a5959b36ad7dd1c30642df24b6b3068710066f6809f7033bb7" +checksum = "fd0b50b1b78dbadd44ab18b3c794e496f3a139abb9fbc27d9c94c4eebbb96496" dependencies = [ "fastrand", "gloo-timers", @@ -622,9 +622,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.74" +version = "0.3.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" dependencies = [ "addr2line", "cfg-if", @@ -714,9 +714,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" dependencies = [ "serde", ] @@ -821,14 +821,14 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] name = "brotli" -version = "7.0.0" +version = "8.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" +checksum = "9991eea70ea4f293524138648e41ee89b0b2b12ddef3b255effa43c8056e0e0d" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -837,9 +837,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "4.0.2" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74fa05ad7d803d413eb8380983b092cbbaf9a85f151b871360e7b00cd7060b37" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -847,9 +847,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.11.3" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0" +checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" dependencies = [ "memchr", "regex-automata 0.4.9", @@ -886,9 +886,9 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.22.0" +version = "1.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540" +checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c" [[package]] name = "byteorder" @@ -923,7 +923,7 @@ dependencies = [ "serde_derive", "serde_json", "sha1", - "sha2 0.10.8", + "sha2 0.10.9", "ssri", "tempfile", "thiserror 1.0.69", @@ -934,9 +934,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.18" +version = "1.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c" +checksum = "5f4ac86a9e5bc1e2b3449ab9d7d3a6a405e3d1bb28d7b9be8614f55846ae3766" dependencies = [ "jobserver", "libc", @@ -991,9 +991,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.40" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ "android-tzdata", "iana-time-zone", @@ -1039,9 +1039,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.35" +version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944" +checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000" dependencies = [ "clap_builder", "clap_derive", @@ -1049,9 +1049,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.35" +version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9" +checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120" dependencies = [ "anstream", "anstyle", @@ -1068,7 +1068,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -1254,9 +1254,9 @@ dependencies = [ [[package]] name = "crc" -version = "3.2.1" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" dependencies = [ "crc-catalog", ] @@ -1278,9 +1278,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.14" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" dependencies = [ "crossbeam-utils", ] @@ -1405,14 +1405,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] name = "ctor" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e9666f4a9a948d4f1dff0c08a4512b0f7c86414b23960104c243c10d79f4c3" +checksum = "a4735f265ba6a1188052ca32d461028a7d1125868be18e287e756019da7607b5" dependencies = [ "ctor-proc-macro", "dtor", @@ -1457,7 +1457,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -1481,7 +1481,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -1492,7 +1492,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -1525,9 +1525,9 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010" +checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" [[package]] name = "data-url" @@ -1540,9 +1540,9 @@ dependencies = [ [[package]] name = "der" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ "const-oid", "pem-rfc7468", @@ -1577,7 +1577,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -1587,25 +1587,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] name = "derive_more" -version = "0.99.19" +version = "0.99.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da29a38df43d6f156149c9b43ded5e018ddff2a855cf2cfd62e8cd7d079c69f" +checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] name = "deunicode" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc55fe0d1f6c107595572ec8b107c0999bb1a2e0b75e37429a4fb0d6474a0e7d" +checksum = "abd57806937c9cc163efc8ea3910e00a62e2aeb0b8119f1793a978088f8f6b04" [[package]] name = "digest" @@ -1666,14 +1666,14 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] name = "docker_credential" -version = "1.3.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31951f49556e34d90ed28342e1df7e1cb7a229c4cab0aecc627b5d91edd41d07" +checksum = "1d89dfcba45b4afad7450a99b39e751590463e45c04728cf555d36bb66940de8" dependencies = [ "base64 0.21.7", "serde", @@ -1749,9 +1749,9 @@ dependencies = [ [[package]] name = "dtor" -version = "0.0.5" +version = "0.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222ef136a1c687d4aa0395c175f2c4586e379924c352fd02f7870cf7de783c23" +checksum = "97cbdf2ad6846025e8e25df05171abfb30e3ababa12ee0a0e44b9bbe570633a8" dependencies = [ "dtor-proc-macro", ] @@ -1801,7 +1801,7 @@ dependencies = [ "curve25519-dalek", "ed25519", "serde", - "sha2 0.10.8", + "sha2 0.10.9", "subtle", "zeroize", ] @@ -1865,9 +1865,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" +checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" dependencies = [ "libc", "windows-sys 0.59.0", @@ -1884,6 +1884,17 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "etcetera" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26c7b13d0780cb82722fd59f6f57f925e143427e4a75313a6c77243bf5326ae6" +dependencies = [ + "cfg-if", + "home", + "windows-sys 0.59.0", +] + [[package]] name = "event-listener" version = "5.4.0" @@ -2165,7 +2176,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -2228,15 +2239,16 @@ dependencies = [ [[package]] name = "generator" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6bd114ceda131d3b1d665eba35788690ad37f5916457286b32ab6fd3c438dd" +checksum = "d18470a76cb7f8ff746cf1f7470914f900252ec36bbc40b569d74b1258446827" dependencies = [ + "cc", "cfg-if", "libc", "log", "rustversion", - "windows 0.58.0", + "windows 0.61.1", ] [[package]] @@ -2270,9 +2282,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "js-sys", @@ -2283,9 +2295,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "js-sys", @@ -2336,7 +2348,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf760ebf69878d9fd8f110c89703d90ce35095324d1f1edcb595c63945ee757" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "ignore", "walkdir", ] @@ -2364,7 +2376,7 @@ dependencies = [ "futures-sink", "futures-timer", "futures-util", - "getrandom 0.3.2", + "getrandom 0.3.3", "no-std-compat", "nonzero_ext", "parking_lot 0.12.3", @@ -2389,9 +2401,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.8" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2" +checksum = "a9421a676d1b147b16b82c9225157dc629087ef8ec4d5e2960f9437a90dac0a5" dependencies = [ "atomic-waker", "bytes", @@ -2437,9 +2449,9 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" dependencies = [ "allocator-api2", "equivalent", @@ -2452,7 +2464,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" dependencies = [ - "hashbrown 0.15.2", + "hashbrown 0.15.3", ] [[package]] @@ -2729,7 +2741,7 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots", + "webpki-roots 0.26.11", ] [[package]] @@ -2795,7 +2807,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.61.0", + "windows-core", ] [[package]] @@ -2809,21 +2821,22 @@ dependencies = [ [[package]] name = "icu_collections" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" dependencies = [ "displaydoc", + "potential_utf", "yoke", "zerofrom", "zerovec", ] [[package]] -name = "icu_locid" -version = "1.5.0" +name = "icu_locale_core" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" dependencies = [ "displaydoc", "litemap", @@ -2832,31 +2845,11 @@ dependencies = [ "zerovec", ] -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" - [[package]] name = "icu_normalizer" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" dependencies = [ "displaydoc", "icu_collections", @@ -2864,67 +2857,54 @@ dependencies = [ "icu_properties", "icu_provider", "smallvec", - "utf16_iter", - "utf8_iter", - "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" -version = "1.5.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] name = "icu_properties" -version = "1.5.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +checksum = "2549ca8c7241c82f59c80ba2a6f415d931c5b58d24fb8412caa1a1f02c49139a" dependencies = [ "displaydoc", "icu_collections", - "icu_locid_transform", + "icu_locale_core", "icu_properties_data", "icu_provider", - "tinystr", + "potential_utf", + "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "1.5.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" +checksum = "8197e866e47b68f8f7d95249e172903bec06004b18b2937f1095d40a0c57de04" [[package]] name = "icu_provider" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" dependencies = [ "displaydoc", - "icu_locid", - "icu_provider_macros", + "icu_locale_core", "stable_deref_trait", "tinystr", "writeable", "yoke", "zerofrom", + "zerotrie", "zerovec", ] -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - [[package]] name = "ident_case" version = "1.0.1" @@ -2954,9 +2934,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", @@ -2996,7 +2976,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", - "hashbrown 0.15.2", + "hashbrown 0.15.3", "serde", ] @@ -3008,7 +2988,7 @@ checksum = "6c38228f24186d9cc68c729accb4d413be9eaed6ad07ff79e0270d9e56f3de13" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -3048,16 +3028,14 @@ dependencies = [ [[package]] name = "insta" -version = "1.42.2" +version = "1.43.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50259abbaa67d11d2bcafc7ba1d094ed7a0c70e3ce893f0d0997f73558cb3084" +checksum = "154934ea70c58054b556dd430b99a98c2a7ff5309ac9891597e339b5c28f4371" dependencies = [ "console", - "linked-hash-map", "once_cell", "pest", "pest_derive", - "pin-project", "regex", "serde", "similar", @@ -3132,7 +3110,7 @@ version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", "libc", ] @@ -3322,9 +3300,9 @@ dependencies = [ [[package]] name = "kqueue" -version = "1.0.8" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" +checksum = "eac30106d7dce88daf4a3fcb4879ea939476d5074a9b7ddd0fb97fa4bed5596a" dependencies = [ "kqueue-sys", "libc", @@ -3362,15 +3340,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.171" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libm" -version = "0.2.11" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libredox" @@ -3378,9 +3356,9 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "libc", - "redox_syscall 0.5.11", + "redox_syscall 0.5.12", ] [[package]] @@ -3589,7 +3567,7 @@ dependencies = [ "futures", "httparse", "network-interface", - "quick-xml 0.37.4", + "quick-xml", "reqwest", "serde", "tokio", @@ -3614,14 +3592,14 @@ version = "1.0.0-alpha.66" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a73ffa17de66534e4b527232f44aa0a89fad22c4f4e0735f9be35494f058e54" dependencies = [ - "ahash 0.8.11", - "bitflags 2.9.0", + "ahash 0.8.12", + "bitflags 2.9.1", "const-str", "cssparser 0.33.0", "cssparser-color", "dashmap 5.5.3", "data-encoding", - "getrandom 0.2.15", + "getrandom 0.2.16", "indexmap 2.9.0", "itertools 0.10.5", "lazy_static", @@ -3647,23 +3625,17 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" - [[package]] name = "linux-raw-sys" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "litemap" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "litrs" @@ -3707,7 +3679,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" dependencies = [ "cfg-if", - "generator 0.8.4", + "generator 0.8.5", "scoped-tls", "tracing", "tracing-subscriber", @@ -3719,9 +3691,15 @@ version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "hashbrown 0.15.2", + "hashbrown 0.15.3", ] +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "mac" version = "0.1.1" @@ -3756,7 +3734,7 @@ checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -3844,7 +3822,7 @@ checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -3865,9 +3843,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ "adler2", ] @@ -4036,7 +4014,7 @@ version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c533b4c39709f9ba5005d8002048266593c1cfaf3c5f0739d5b8ab0c6c504009" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "filetime", "fsevent-sys", "inotify", @@ -4173,14 +4151,14 @@ checksum = "51e219e79014df21a225b1860a479e2dcd7cbd9130f4defd4bd0e191ea31d67d" dependencies = [ "base64 0.22.1", "chrono", - "getrandom 0.2.15", + "getrandom 0.2.16", "http", "rand 0.8.5", "reqwest", "serde", "serde_json", "serde_path_to_error", - "sha2 0.10.8", + "sha2 0.10.9", "thiserror 1.0.69", "url", ] @@ -4208,9 +4186,9 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "opendal" -version = "0.53.0" +version = "0.53.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5ebd1183902124c6b3ee0a9383683513dd8cca3d25a5d065593f969a44f979e" +checksum = "11ff9e9656d1cb3c58582ea18e6d9e71076a7ab2614207821d1242d7da2daed5" dependencies = [ "anyhow", "async-trait", @@ -4219,12 +4197,13 @@ dependencies = [ "bytes", "chrono", "futures", - "getrandom 0.2.15", + "getrandom 0.2.16", "http", + "http-body", "log", "md-5", "percent-encoding", - "quick-xml 0.36.2", + "quick-xml", "reqwest", "serde", "serde_json", @@ -4257,7 +4236,7 @@ dependencies = [ "serde_path_to_error", "serde_plain", "serde_with", - "sha2 0.10.8", + "sha2 0.10.9", "subtle", "thiserror 1.0.69", "url", @@ -4269,7 +4248,7 @@ version = "0.10.72" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "cfg-if", "foreign-types", "libc", @@ -4286,7 +4265,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -4297,9 +4276,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.107" +version = "0.9.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07" +checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847" dependencies = [ "cc", "libc", @@ -4352,7 +4331,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -4376,7 +4355,7 @@ dependencies = [ "ecdsa", "elliptic-curve", "primeorder", - "sha2 0.10.8", + "sha2 0.10.9", ] [[package]] @@ -4388,7 +4367,7 @@ dependencies = [ "ecdsa", "elliptic-curve", "primeorder", - "sha2 0.10.8", + "sha2 0.10.9", ] [[package]] @@ -4397,7 +4376,7 @@ version = "0.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54fd03f1ad26cb6b3ec1b7414fa78a3bd639e7dbb421b1a60513c96ce886a196" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "cssparser 0.33.0", "log", "phf", @@ -4470,7 +4449,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.11", + "redox_syscall 0.5.12", "smallvec", "windows-targets 0.52.6", ] @@ -4497,7 +4476,7 @@ dependencies = [ "regex", "regex-syntax 0.8.5", "structmeta", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -4552,7 +4531,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -4611,7 +4590,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -4622,7 +4601,7 @@ checksum = "7f9f832470494906d1fca5329f8ab5791cc60beb230c74815dff541cbd2b5ca0" dependencies = [ "once_cell", "pest", - "sha2 0.10.8", + "sha2 0.10.9", ] [[package]] @@ -4674,7 +4653,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -4703,7 +4682,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -4774,6 +4753,15 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -4786,7 +4774,7 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy 0.8.24", + "zerocopy", ] [[package]] @@ -4832,14 +4820,14 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] @@ -4852,7 +4840,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", "version_check", "yansi", ] @@ -4930,19 +4918,9 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.36.2" +version = "0.37.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "quick-xml" -version = "0.37.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4ce8c88de324ff838700f36fb6ab86c96df0e3c4ab6ef3a9b2044465cce1369" +checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" dependencies = [ "encoding_rs", "memchr", @@ -4951,9 +4929,9 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.7" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3bd15a6f2967aef83887dcb9fec0014580467e33720d073560cf015a5683012" +checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8" dependencies = [ "bytes", "cfg_aliases", @@ -4971,12 +4949,13 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.10" +version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b820744eb4dc9b57a3398183639c511b5a26d2ed702cedd3febaa1393caa22cc" +checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e" dependencies = [ "bytes", - "getrandom 0.3.2", + "getrandom 0.3.3", + "lru-slab", "rand 0.9.1", "ring", "rustc-hash 2.1.1", @@ -4991,9 +4970,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "541d0f57c6ec747a90738a52741d3221f7960e8ac2f0ff4b1a63680e033b4ab5" +checksum = "ee4e529991f949c5e25755532370b8af5d114acae52326361d68d47af64aa842" dependencies = [ "cfg_aliases", "libc", @@ -5084,7 +5063,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", ] [[package]] @@ -5093,7 +5072,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", ] [[package]] @@ -5102,7 +5081,7 @@ version = "11.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6df7ab838ed27997ba19a4664507e6f82b41fe6e20be42929332156e5e85146" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", ] [[package]] @@ -5219,11 +5198,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" +checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", ] [[package]] @@ -5232,7 +5211,7 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", "libredox", "thiserror 1.0.69", ] @@ -5359,7 +5338,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots", + "webpki-roots 0.26.11", "windows-registry", ] @@ -5387,7 +5366,7 @@ dependencies = [ "anyhow", "async-trait", "futures", - "getrandom 0.2.15", + "getrandom 0.2.16", "http", "hyper", "parking_lot 0.11.2", @@ -5408,7 +5387,7 @@ checksum = "d75b0eee96990cfb4c09545847385e89b2d2d2e571143d55264a05d77c713780" dependencies = [ "anyhow", "async-trait", - "getrandom 0.2.15", + "getrandom 0.2.16", "http", "matchit", "reqwest", @@ -5457,7 +5436,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.15", + "getrandom 0.2.16", "libc", "untrusted", "windows-sys 0.52.0", @@ -5530,7 +5509,7 @@ dependencies = [ "atom_syndication", "derive_builder", "never", - "quick-xml 0.37.4", + "quick-xml", ] [[package]] @@ -5559,7 +5538,7 @@ dependencies = [ "regex", "relative-path", "rustc_version", - "syn 2.0.100", + "syn 2.0.101", "unicode-ident", ] @@ -5608,11 +5587,11 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "errno", "libc", "linux-raw-sys", @@ -5621,9 +5600,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.25" +version = "0.23.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "822ee9188ac4ec04a2f0531e55d035fb2de73f18b41a63c70c2712503b6fb13c" +checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" dependencies = [ "once_cell", "ring", @@ -5656,18 +5635,19 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" dependencies = [ "web-time", + "zeroize", ] [[package]] name = "rustls-webpki" -version = "0.103.1" +version = "0.103.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" +checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" dependencies = [ "ring", "rustls-pki-types", @@ -5697,9 +5677,9 @@ dependencies = [ [[package]] name = "scc" -version = "2.3.3" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea091f6cac2595aa38993f04f4ee692ed43757035c36e67c180b6828356385b1" +checksum = "22b2d775fb28f245817589471dd49c5edf64237f4a19d10ce9a92ff4651a27f4" dependencies = [ "sdd", ] @@ -5756,14 +5736,14 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] name = "sea-orm" -version = "1.1.8" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "013d6c9e421b9c44c6eb6ebbee283b2a2c90eab2682088c4a2449706a42d117f" +checksum = "f7cf58b28bcf1e053539c38afbb60d963ac8e1db87f6109db7b0eff4cbeaefb3" dependencies = [ "async-stream", "async-trait", @@ -5790,9 +5770,9 @@ dependencies = [ [[package]] name = "sea-orm-cli" -version = "1.1.8" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba295ef27c085889da408eca3634a6b04093257126e57087e0fd744ebad8f67" +checksum = "0885ce200adaa527c696f6114f1a014c74801fa9c62a2b1bccfdec9af381108c" dependencies = [ "chrono", "clap", @@ -5807,24 +5787,24 @@ dependencies = [ [[package]] name = "sea-orm-macros" -version = "1.1.8" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31feeff3ad5e999c64b2b8fd30933b2871911567c4d62dcf70b3effd970c7891" +checksum = "cac37512fde1f5b9ef71ec773cfabb90ad3b68c27e53131ff38763c247fcbb2d" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "proc-macro-crate", "proc-macro2", "quote", "sea-bae", - "syn 2.0.100", + "syn 2.0.101", "unicode-ident", ] [[package]] name = "sea-orm-migration" -version = "1.1.8" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d90a9cc4881a3fd2cbff38dffe0cff40d61169c246aa572849288f83a29c5b19" +checksum = "13f81e0ae079274b7eaa7b0234ae57b4a4f51619f53f3996d47580b378e0b26b" dependencies = [ "async-trait", "clap", @@ -5838,9 +5818,9 @@ dependencies = [ [[package]] name = "sea-query" -version = "0.32.3" +version = "0.32.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5a24d8b9fcd2674a6c878a3d871f4f1380c6c43cc3718728ac96864d888458e" +checksum = "5506de3a33d9ee4ee161c5847acb87fe4f82ced6649afc9eabeb8df6f40ba94a" dependencies = [ "bigdecimal", "chrono", @@ -5879,15 +5859,15 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", "thiserror 2.0.12", ] [[package]] name = "sea-schema" -version = "0.16.1" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef5dd7848c993f3789d09a2616484c72c9330cae2b048df59d8c9b8c0343e95" +checksum = "2239ff574c04858ca77485f112afea1a15e53135d3097d0c86509cef1def1338" dependencies = [ "futures", "sea-query", @@ -5903,7 +5883,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -5947,7 +5927,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "core-foundation 0.9.4", "core-foundation-sys", "libc", @@ -5960,7 +5940,7 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "core-foundation 0.10.0", "core-foundation-sys", "libc", @@ -5983,7 +5963,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd568a4c9bb598e291a08244a5c1f5a8a6650bee243b5b0f8dbb3d9cc1d87fe8" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "cssparser 0.34.0", "derive_more", "fxhash", @@ -6029,7 +6009,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -6071,7 +6051,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -6131,7 +6111,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -6169,7 +6149,7 @@ checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -6218,9 +6198,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", @@ -6244,9 +6224,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.2" +version = "1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" dependencies = [ "libc", ] @@ -6364,7 +6344,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -6407,9 +6387,9 @@ dependencies = [ [[package]] name = "sqlx" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4410e73b3c0d8442c5f99b425d7a435b5ee0ae4167b3196771dd3f7a01be745f" +checksum = "f3c3a85280daca669cfd3bcb68a337882a8bc57ec882f72c5d13a430613a738e" dependencies = [ "sqlx-core", "sqlx-macros", @@ -6420,10 +6400,11 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a007b6936676aa9ab40207cde35daab0a04b823be8ae004368c0793b96a61e0" +checksum = "f743f2a3cea30a58cd479013f75550e879009e3a02f616f18ca699335aa248c3" dependencies = [ + "base64 0.22.1", "bigdecimal", "bytes", "chrono", @@ -6435,7 +6416,7 @@ dependencies = [ "futures-intrusive", "futures-io", "futures-util", - "hashbrown 0.15.2", + "hashbrown 0.15.3", "hashlink", "indexmap 2.9.0", "log", @@ -6444,10 +6425,9 @@ dependencies = [ "percent-encoding", "rust_decimal", "rustls", - "rustls-pemfile", "serde", "serde_json", - "sha2 0.10.8", + "sha2 0.10.9", "smallvec", "thiserror 2.0.12", "time", @@ -6456,27 +6436,27 @@ dependencies = [ "tracing", "url", "uuid", - "webpki-roots", + "webpki-roots 0.26.11", ] [[package]] name = "sqlx-macros" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3112e2ad78643fef903618d78cf0aec1cb3134b019730edb039b69eaf531f310" +checksum = "7f4200e0fde19834956d4252347c12a083bdcb237d7a1a1446bffd8768417dce" dependencies = [ "proc-macro2", "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] name = "sqlx-macros-core" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e9f90acc5ab146a99bf5061a7eb4976b573f560bc898ef3bf8435448dd5e7ad" +checksum = "882ceaa29cade31beca7129b6beeb05737f44f82dbe2a9806ecea5a7093d00b7" dependencies = [ "dotenvy", "either", @@ -6487,12 +6467,12 @@ dependencies = [ "quote", "serde", "serde_json", - "sha2 0.10.8", + "sha2 0.10.9", "sqlx-core", "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.100", + "syn 2.0.101", "tempfile", "tokio", "url", @@ -6500,14 +6480,14 @@ dependencies = [ [[package]] name = "sqlx-mysql" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4560278f0e00ce64938540546f59f590d60beee33fffbd3b9cd47851e5fff233" +checksum = "0afdd3aa7a629683c2d750c2df343025545087081ab5942593a5288855b1b7a7" dependencies = [ "atoi", "base64 0.22.1", "bigdecimal", - "bitflags 2.9.0", + "bitflags 2.9.1", "byteorder", "bytes", "chrono", @@ -6534,7 +6514,7 @@ dependencies = [ "rust_decimal", "serde", "sha1", - "sha2 0.10.8", + "sha2 0.10.9", "smallvec", "sqlx-core", "stringprep", @@ -6547,19 +6527,19 @@ dependencies = [ [[package]] name = "sqlx-postgres" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5b98a57f363ed6764d5b3a12bfedf62f07aa16e1856a7ddc2a0bb190a959613" +checksum = "a0bedbe1bbb5e2615ef347a5e9d8cd7680fb63e77d9dafc0f29be15e53f1ebe6" dependencies = [ "atoi", "base64 0.22.1", "bigdecimal", - "bitflags 2.9.0", + "bitflags 2.9.1", "byteorder", "chrono", "crc", "dotenvy", - "etcetera", + "etcetera 0.8.0", "futures-channel", "futures-core", "futures-util", @@ -6577,7 +6557,7 @@ dependencies = [ "rust_decimal", "serde", "serde_json", - "sha2 0.10.8", + "sha2 0.10.9", "smallvec", "sqlx-core", "stringprep", @@ -6590,9 +6570,9 @@ dependencies = [ [[package]] name = "sqlx-sqlite" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f85ca71d3a5b24e64e1d08dd8fe36c6c95c339a896cc33068148906784620540" +checksum = "c26083e9a520e8eb87a06b12347679b142dc2ea29e6e409f805644a7a979a5bc" dependencies = [ "atoi", "chrono", @@ -6608,6 +6588,7 @@ dependencies = [ "serde", "serde_urlencoded", "sqlx-core", + "thiserror 2.0.12", "time", "tracing", "url", @@ -6626,7 +6607,7 @@ dependencies = [ "miette", "serde", "sha-1", - "sha2 0.10.8", + "sha2 0.10.9", "thiserror 1.0.69", "xxhash-rust", ] @@ -6700,7 +6681,7 @@ dependencies = [ "proc-macro2", "quote", "structmeta-derive", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -6711,7 +6692,7 @@ checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -6733,7 +6714,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -6755,9 +6736,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.100" +version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", @@ -6775,13 +6756,13 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -6790,7 +6771,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "core-foundation 0.9.4", "system-configuration-sys", ] @@ -6819,12 +6800,12 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.19.1" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ "fastrand", - "getrandom 0.3.2", + "getrandom 0.3.3", "once_cell", "rustix", "windows-sys 0.59.0", @@ -6865,9 +6846,9 @@ dependencies = [ [[package]] name = "testcontainers" -version = "0.23.3" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a4f01f39bb10fc2a5ab23eb0d888b1e2bb168c157f61a1b98e6c501c639c74" +checksum = "23bb7577dca13ad86a78e8271ef5d322f37229ec83b8d98da6d996c588a1ddb1" dependencies = [ "async-trait", "bollard", @@ -6875,7 +6856,7 @@ dependencies = [ "bytes", "docker_credential", "either", - "etcetera", + "etcetera 0.10.0", "futures", "log", "memchr", @@ -6908,9 +6889,9 @@ dependencies = [ [[package]] name = "testcontainers-modules" -version = "0.11.6" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d43ed4e8f58424c3a2c6c56dbea6643c3c23e8666a34df13c54f0a184e6c707" +checksum = "7f29549c522bd43086d038c421ed69cdf88bc66387acf3aa92b26f965fa95ec2" dependencies = [ "testcontainers", ] @@ -6951,7 +6932,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -6962,7 +6943,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -7008,9 +6989,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.7.6" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" dependencies = [ "displaydoc", "zerovec", @@ -7033,9 +7014,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.44.2" +version = "1.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" +checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" dependencies = [ "backtrace", "bytes", @@ -7057,7 +7038,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -7133,9 +7114,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.14" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" dependencies = [ "bytes", "futures-core", @@ -7147,9 +7128,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.20" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" dependencies = [ "serde", "serde_spanned", @@ -7159,26 +7140,33 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.24" +version = "0.22.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" dependencies = [ "indexmap 2.9.0", "serde", "serde_spanned", "toml_datetime", + "toml_write", "winnow", ] +[[package]] +name = "toml_write" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" + [[package]] name = "tower" version = "0.5.2" @@ -7198,13 +7186,13 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.2" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403fa3b783d4b626a8ad51d766ab03cb6d2dbfc46b1c5d4448395e6628dc9697" +checksum = "0fdb0c213ca27a9f57ab69ddb290fd80d970922355b83ae380b395d3986b8a2e" dependencies = [ "async-compression", "base64 0.22.1", - "bitflags 2.9.0", + "bitflags 2.9.1", "bytes", "futures-core", "futures-util", @@ -7268,7 +7256,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -7381,7 +7369,7 @@ checksum = "3c36781cc0e46a83726d9879608e4cf6c2505237e263a8eb8c24502989cfdb28" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -7392,7 +7380,7 @@ checksum = "60d8d828da2a3d759d3519cdf29a5bac49c77d039ad36d0782edadbf9cd5415b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -7567,12 +7555,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - [[package]] name = "utf8-width" version = "0.1.7" @@ -7608,7 +7590,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", "js-sys", "serde", "wasm-bindgen", @@ -7700,7 +7682,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", "wasm-bindgen-shared", ] @@ -7735,7 +7717,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -7799,9 +7781,18 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.8" +version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.0", +] + +[[package]] +name = "webpki-roots" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2853738d1cc4f2da3a225c18ec6c3721abb31961096e9dbf5ab35fa88b19cfdb" dependencies = [ "rustls-pki-types", ] @@ -7812,7 +7803,7 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6994d13118ab492c3c80c1f81928718159254c53c472bf9ce36f8dae4add02a7" dependencies = [ - "redox_syscall 0.5.11", + "redox_syscall 0.5.12", "wasite", ] @@ -7856,16 +7847,6 @@ dependencies = [ "windows-targets 0.48.5", ] -[[package]] -name = "windows" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" -dependencies = [ - "windows-core 0.58.0", - "windows-targets 0.52.6", -] - [[package]] name = "windows" version = "0.61.1" @@ -7873,7 +7854,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419" dependencies = [ "windows-collections", - "windows-core 0.61.0", + "windows-core", "windows-future", "windows-link", "windows-numerics", @@ -7885,54 +7866,31 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" dependencies = [ - "windows-core 0.61.0", + "windows-core", ] [[package]] name = "windows-core" -version = "0.58.0" +version = "0.61.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +checksum = "46ec44dc15085cea82cf9c78f85a9114c463a369786585ad2882d1ff0b0acf40" dependencies = [ - "windows-implement 0.58.0", - "windows-interface 0.58.0", - "windows-result 0.2.0", - "windows-strings 0.1.0", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-core" -version = "0.61.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" -dependencies = [ - "windows-implement 0.60.0", - "windows-interface 0.59.1", + "windows-implement", + "windows-interface", "windows-link", - "windows-result 0.3.2", - "windows-strings 0.4.0", + "windows-result", + "windows-strings 0.4.1", ] [[package]] name = "windows-future" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" dependencies = [ - "windows-core 0.61.0", + "windows-core", "windows-link", -] - -[[package]] -name = "windows-implement" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", + "windows-threading", ] [[package]] @@ -7943,18 +7901,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", -] - -[[package]] -name = "windows-interface" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -7965,7 +7912,7 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -7980,7 +7927,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" dependencies = [ - "windows-core 0.61.0", + "windows-core", "windows-link", ] @@ -7990,39 +7937,20 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" dependencies = [ - "windows-result 0.3.2", + "windows-result", "windows-strings 0.3.1", "windows-targets 0.53.0", ] [[package]] name = "windows-result" -version = "0.2.0" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-result" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +checksum = "4b895b5356fc36103d0f64dd1e94dfa7ac5633f1c9dd6e80fe9ec4adef69e09d" dependencies = [ "windows-link", ] -[[package]] -name = "windows-strings" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" -dependencies = [ - "windows-result 0.2.0", - "windows-targets 0.52.6", -] - [[package]] name = "windows-strings" version = "0.3.1" @@ -8034,9 +7962,9 @@ dependencies = [ [[package]] name = "windows-strings" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +checksum = "2a7ab927b2637c19b3dbe0965e75d8f2d30bdd697a1516191cad2ec4df8fb28a" dependencies = [ "windows-link", ] @@ -8115,6 +8043,15 @@ dependencies = [ "windows_x86_64_msvc 0.53.0", ] +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -8255,9 +8192,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winnow" -version = "0.7.6" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10" +checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" dependencies = [ "memchr", ] @@ -8268,20 +8205,14 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", ] -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - [[package]] name = "writeable" -version = "0.5.5" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "wyz" @@ -8316,9 +8247,9 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "yoke" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" dependencies = [ "serde", "stable_deref_trait", @@ -8328,54 +8259,34 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", "synstructure", ] [[package]] name = "zerocopy" -version = "0.7.35" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" dependencies = [ - "zerocopy-derive 0.7.35", -] - -[[package]] -name = "zerocopy" -version = "0.8.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" -dependencies = [ - "zerocopy-derive 0.8.24", + "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.35" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -8395,7 +8306,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", "synstructure", ] @@ -8406,10 +8317,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" [[package]] -name = "zerovec" -version = "0.10.4" +name = "zerotrie" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" dependencies = [ "yoke", "zerofrom", @@ -8418,13 +8340,13 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.10.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 9d5739a..f875b7e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,8 +13,8 @@ moka = "0.12" futures = "0.3" quirks_path = "0.1" snafu = { version = "0.8", features = ["futures"] } -testcontainers = { version = "0.23.3" } -testcontainers-modules = { version = "0.11.4" } +testcontainers = { version = "0.24" } +testcontainers-modules = { version = "0.12" } testcontainers-ext = { version = "0.1.0", features = ["tracing"] } serde = { version = "1", features = ["derive"] } tokio = { version = "1", features = ["macros", "fs", "rt-multi-thread"] } diff --git a/apps/recorder/src/app/builder.rs b/apps/recorder/src/app/builder.rs index 72a679f..4a7e797 100644 --- a/apps/recorder/src/app/builder.rs +++ b/apps/recorder/src/app/builder.rs @@ -67,19 +67,9 @@ impl AppBuilder { } pub async fn build(self) -> RecorderResult { - AppConfig::load_dotenv( - &self.environment, - &self.working_dir, - self.dotenv_file.as_deref(), - ) - .await?; + self.load_env().await?; - let config = AppConfig::load_config( - &self.environment, - &self.working_dir, - self.config_file.as_deref(), - ) - .await?; + let config = self.load_config().await?; let app_context = AppContext::new(self.environment.clone(), config, self.working_dir.clone()).await?; @@ -90,6 +80,26 @@ impl AppBuilder { }) } + pub async fn load_env(&self) -> RecorderResult<()> { + AppConfig::load_dotenv( + &self.environment, + &self.working_dir, + self.dotenv_file.as_deref(), + ) + .await?; + Ok(()) + } + + pub async fn load_config(&self) -> RecorderResult { + let config = AppConfig::load_config( + &self.environment, + &self.working_dir, + self.config_file.as_deref(), + ) + .await?; + Ok(config) + } + pub fn working_dir(self, working_dir: String) -> Self { let mut ret = self; ret.working_dir = working_dir; diff --git a/apps/recorder/src/app/config/default_mixin.toml b/apps/recorder/src/app/config/default_mixin.toml index 7faedc0..2ad992d 100644 --- a/apps/recorder/src/app/config/default_mixin.toml +++ b/apps/recorder/src/app/config/default_mixin.toml @@ -20,3 +20,5 @@ complexity_limit = inf [crypto] [task] + +[message] diff --git a/apps/recorder/src/app/config/mod.rs b/apps/recorder/src/app/config/mod.rs index 232a29b..3dac85a 100644 --- a/apps/recorder/src/app/config/mod.rs +++ b/apps/recorder/src/app/config/mod.rs @@ -11,7 +11,8 @@ use super::env::Environment; use crate::{ auth::AuthConfig, cache::CacheConfig, crypto::CryptoConfig, database::DatabaseConfig, errors::RecorderResult, extract::mikan::MikanConfig, graphql::GraphQLConfig, - logger::LoggerConfig, storage::StorageConfig, tasks::TaskConfig, web::WebServerConfig, + logger::LoggerConfig, message::MessageConfig, storage::StorageConfig, task::TaskConfig, + web::WebServerConfig, }; const DEFAULT_CONFIG_MIXIN: &str = include_str!("./default_mixin.toml"); @@ -28,7 +29,8 @@ pub struct AppConfig { pub graphql: GraphQLConfig, pub logger: LoggerConfig, pub database: DatabaseConfig, - pub tasks: TaskConfig, + pub task: TaskConfig, + pub message: MessageConfig, } impl AppConfig { diff --git a/apps/recorder/src/app/context.rs b/apps/recorder/src/app/context.rs index cc7aade..6ed5155 100644 --- a/apps/recorder/src/app/context.rs +++ b/apps/recorder/src/app/context.rs @@ -12,8 +12,9 @@ use crate::{ extract::mikan::MikanClient, graphql::GraphQLService, logger::LoggerService, + message::MessageService, storage::{StorageService, StorageServiceTrait}, - tasks::TaskService, + task::TaskService, }; pub trait AppContextTrait: Send + Sync + Debug { @@ -29,6 +30,7 @@ pub trait AppContextTrait: Send + Sync + Debug { fn environment(&self) -> &Environment; fn crypto(&self) -> &CryptoService; fn task(&self) -> &TaskService; + fn message(&self) -> &MessageService; } pub struct AppContext { @@ -43,6 +45,7 @@ pub struct AppContext { crypto: CryptoService, working_dir: String, environment: Environment, + message: MessageService, task: OnceCell, } @@ -58,6 +61,7 @@ impl AppContext { let cache = CacheService::from_config(config.cache).await?; let db = DatabaseService::from_config(config.database).await?; let storage = StorageService::from_config(config.storage).await?; + let message = MessageService::from_config(config.message).await?; let auth = AuthService::from_conf(config.auth).await?; let mikan = MikanClient::from_config(config.mikan).await?; let crypto = CryptoService::from_config(config.crypto).await?; @@ -75,12 +79,13 @@ impl AppContext { working_dir: working_dir.to_string(), graphql, crypto, + message, task: OnceCell::new(), }); ctx.task .get_or_try_init(async || { - TaskService::from_config_and_ctx(config.tasks, ctx.clone()).await + TaskService::from_config_and_ctx(config.task, ctx.clone()).await }) .await?; @@ -131,4 +136,7 @@ impl AppContextTrait for AppContext { fn task(&self) -> &TaskService { self.task.get().expect("task should be set") } + fn message(&self) -> &MessageService { + &self.message + } } diff --git a/apps/recorder/src/bin/migrate_down.rs b/apps/recorder/src/bin/migrate_down.rs new file mode 100644 index 0000000..2a042e8 --- /dev/null +++ b/apps/recorder/src/bin/migrate_down.rs @@ -0,0 +1,16 @@ +use recorder::{app::AppBuilder, database::DatabaseService, errors::RecorderResult}; + +#[tokio::main] +async fn main() -> RecorderResult<()> { + let builder = AppBuilder::from_main_cli(None).await?; + + builder.load_env().await?; + let mut database_config = builder.load_config().await?.database; + database_config.auto_migrate = false; + + let database_service = DatabaseService::from_config(database_config).await?; + + database_service.migrate_down().await?; + + Ok(()) +} diff --git a/apps/recorder/src/database/service.rs b/apps/recorder/src/database/service.rs index b12fb98..519449e 100644 --- a/apps/recorder/src/database/service.rs +++ b/apps/recorder/src/database/service.rs @@ -52,19 +52,34 @@ impl DatabaseService { // .await?; // } - if config.auto_migrate { - Migrator::up(&db, None).await?; - { - let pool = db.get_postgres_connection_pool(); - PostgresStorage::setup(pool).await?; - } - } - - Ok(Self { + let me = Self { connection: db, #[cfg(all(test, feature = "testcontainers"))] container: None, - }) + }; + + if config.auto_migrate { + me.migrate_up().await?; + } + + Ok(me) + } + + pub async fn migrate_up(&self) -> RecorderResult<()> { + Migrator::up(&self.connection, None).await?; + { + let pool = &self.get_postgres_connection_pool(); + PostgresStorage::setup(pool).await?; + } + Ok(()) + } + + pub async fn migrate_down(&self) -> RecorderResult<()> { + Migrator::down(&self.connection, None).await?; + { + let _pool = &self.get_postgres_connection_pool(); + } + Ok(()) } } diff --git a/apps/recorder/src/extract/mikan/mod.rs b/apps/recorder/src/extract/mikan/mod.rs index 5c02481..ce99fba 100644 --- a/apps/recorder/src/extract/mikan/mod.rs +++ b/apps/recorder/src/extract/mikan/mod.rs @@ -29,6 +29,7 @@ pub use web::{ extract_mikan_episode_meta_from_episode_homepage_html, scrape_mikan_bangumi_meta_from_bangumi_homepage_url, scrape_mikan_bangumi_meta_list_from_season_flow_url, + scrape_mikan_bangumi_meta_stream_from_season_flow_url, scrape_mikan_episode_meta_from_episode_homepage_url, scrape_mikan_poster_data_from_image_url, scrape_mikan_poster_meta_from_image_url, }; diff --git a/apps/recorder/src/extract/mikan/web.rs b/apps/recorder/src/extract/mikan/web.rs index ecf0be5..6934270 100644 --- a/apps/recorder/src/extract/mikan/web.rs +++ b/apps/recorder/src/extract/mikan/web.rs @@ -1,7 +1,9 @@ use std::{borrow::Cow, fmt, sync::Arc}; +use async_stream::try_stream; use bytes::Bytes; use fetch::{html::fetch_html, image::fetch_image}; +use futures::{Stream, TryStreamExt, pin_mut}; use html_escape::decode_html_entities; use scraper::{Html, Selector}; use serde::{Deserialize, Serialize}; @@ -24,7 +26,7 @@ use crate::{ storage::{StorageContentCategory, StorageServiceTrait}, }; -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Eq)] pub struct MikanBangumiIndexMeta { pub homepage: Url, pub origin_poster_src: Option, @@ -32,13 +34,13 @@ pub struct MikanBangumiIndexMeta { pub mikan_bangumi_id: String, } -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Eq)] pub struct MikanFansubMeta { pub mikan_fansub_id: String, pub fansub: String, } -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Eq)] pub struct MikanBangumiMeta { pub homepage: Url, pub origin_poster_src: Option, @@ -675,66 +677,83 @@ pub fn extract_mikan_bangumi_meta_from_expand_subscribed_fragment( } } +pub fn scrape_mikan_bangumi_meta_stream_from_season_flow_url( + ctx: Arc, + mikan_season_flow_url: Url, + credential_id: i32, +) -> impl Stream> { + try_stream! { + let mikan_client = ctx.mikan() + .fork_with_credential(ctx.clone(), credential_id) + .await?; + + let mikan_base_url = mikan_client.base_url(); + let content = fetch_html(&mikan_client, mikan_season_flow_url.clone()).await?; + let mut bangumi_indices_meta = { + let html = Html::parse_document(&content); + extract_mikan_bangumi_index_meta_list_from_season_flow_fragment(&html, mikan_base_url) + }; + + if bangumi_indices_meta.is_empty() && !mikan_client.has_login().await? { + mikan_client.login().await?; + let content = fetch_html(&mikan_client, mikan_season_flow_url).await?; + let html = Html::parse_document(&content); + bangumi_indices_meta = + extract_mikan_bangumi_index_meta_list_from_season_flow_fragment(&html, mikan_base_url); + } + + + mikan_client + .sync_credential_cookies(ctx.clone(), credential_id) + .await?; + + for bangumi_index in bangumi_indices_meta { + let bangumi_title = bangumi_index.bangumi_title.clone(); + let bangumi_expand_subscribed_fragment_url = build_mikan_bangumi_expand_subscribed_url( + mikan_base_url.clone(), + &bangumi_index.mikan_bangumi_id, + ); + let bangumi_expand_subscribed_fragment = + fetch_html(&mikan_client, bangumi_expand_subscribed_fragment_url).await?; + + let bangumi_meta = { + let html = Html::parse_document(&bangumi_expand_subscribed_fragment); + + extract_mikan_bangumi_meta_from_expand_subscribed_fragment( + &html, + bangumi_index, + mikan_base_url.clone(), + ) + .with_whatever_context::<_, String, RecorderError>(|| { + format!("failed to extract mikan bangumi fansub of title = {bangumi_title}") + }) + }?; + + yield bangumi_meta; + } + + mikan_client + .sync_credential_cookies(ctx, credential_id) + .await?; + } +} + #[instrument(err, skip_all, fields(mikan_season_flow_url = mikan_season_flow_url.as_str(), credential_id = credential_id))] pub async fn scrape_mikan_bangumi_meta_list_from_season_flow_url( - mikan_client: &MikanClient, + _mikan_client: &MikanClient, ctx: Arc, mikan_season_flow_url: Url, credential_id: i32, ) -> RecorderResult> { - let mikan_client = mikan_client - .fork_with_credential(ctx.clone(), credential_id) - .await?; + let stream = scrape_mikan_bangumi_meta_stream_from_season_flow_url( + ctx, + mikan_season_flow_url, + credential_id, + ); - let mikan_base_url = mikan_client.base_url(); - let content = fetch_html(&mikan_client, mikan_season_flow_url.clone()).await?; - let mut bangumi_indices_meta = { - let html = Html::parse_document(&content); - extract_mikan_bangumi_index_meta_list_from_season_flow_fragment(&html, mikan_base_url) - }; + pin_mut!(stream); - if bangumi_indices_meta.is_empty() && !mikan_client.has_login().await? { - mikan_client.login().await?; - let content = fetch_html(&mikan_client, mikan_season_flow_url).await?; - let html = Html::parse_document(&content); - bangumi_indices_meta = - extract_mikan_bangumi_index_meta_list_from_season_flow_fragment(&html, mikan_base_url); - } - - let mut bangumi_metas = vec![]; - - mikan_client - .sync_credential_cookies(ctx.clone(), credential_id) - .await?; - - for bangumi_index in bangumi_indices_meta { - let bangumi_title = bangumi_index.bangumi_title.clone(); - let bangumi_expand_subscribed_fragment_url = build_mikan_bangumi_expand_subscribed_url( - mikan_base_url.clone(), - &bangumi_index.mikan_bangumi_id, - ); - let bangumi_expand_subscribed_fragment = - fetch_html(&mikan_client, bangumi_expand_subscribed_fragment_url).await?; - - let bangumi_meta = { - let html = Html::parse_document(&bangumi_expand_subscribed_fragment); - - extract_mikan_bangumi_meta_from_expand_subscribed_fragment( - &html, - bangumi_index, - mikan_base_url.clone(), - ) - .with_whatever_context::<_, String, RecorderError>(|| { - format!("failed to extract mikan bangumi fansub of title = {bangumi_title}") - }) - }?; - - bangumi_metas.push(bangumi_meta); - } - - mikan_client - .sync_credential_cookies(ctx, credential_id) - .await?; + let bangumi_metas = stream.try_collect().await?; Ok(bangumi_metas) } diff --git a/apps/recorder/src/graphql/mikan/mikan_scrape_season_subscription.rs b/apps/recorder/src/graphql/mikan/mikan_scrape_season_subscription.rs new file mode 100644 index 0000000..90058ff --- /dev/null +++ b/apps/recorder/src/graphql/mikan/mikan_scrape_season_subscription.rs @@ -0,0 +1,5 @@ +use async_graphql::{Context, dynamic::SchemaBuilder}; + +pub fn register_mikan_scrape_season_subscription_mutation(builder: SchemaBuilder) { + +} diff --git a/apps/recorder/src/graphql/mikan/mod.rs b/apps/recorder/src/graphql/mikan/mod.rs index 8b13789..cdc8462 100644 --- a/apps/recorder/src/graphql/mikan/mod.rs +++ b/apps/recorder/src/graphql/mikan/mod.rs @@ -1 +1 @@ - +mod mikan_scrape_season_subscription; diff --git a/apps/recorder/src/graphql/schema_root.rs b/apps/recorder/src/graphql/schema_root.rs index 23e1710..f57600d 100644 --- a/apps/recorder/src/graphql/schema_root.rs +++ b/apps/recorder/src/graphql/schema_root.rs @@ -111,6 +111,10 @@ pub fn schema( &mut context, &subscription_episode::Column::SubscriberId, ); + restrict_subscriber_for_entity::( + &mut context, + &subscriber_tasks::Column::SubscriberId, + ); for column in subscribers::Column::iter() { if !matches!(column, subscribers::Column::Id) { restrict_filter_input_for_entity::( @@ -151,7 +155,8 @@ pub fn schema( episodes, subscription_bangumi, subscription_episode, - subscriptions + subscriptions, + subscriber_tasks, ] ); @@ -160,6 +165,7 @@ pub fn schema( builder.register_enumeration::(); builder.register_enumeration::(); builder.register_enumeration::(); + builder.register_enumeration::(); } let schema = builder.schema_builder(); diff --git a/apps/recorder/src/lib.rs b/apps/recorder/src/lib.rs index 57dde78..4f791dd 100644 --- a/apps/recorder/src/lib.rs +++ b/apps/recorder/src/lib.rs @@ -20,10 +20,11 @@ pub mod errors; pub mod extract; pub mod graphql; pub mod logger; +pub mod message; pub mod migrations; pub mod models; pub mod storage; -pub mod tasks; +pub mod task; #[cfg(test)] pub mod test_utils; pub mod web; diff --git a/apps/recorder/src/message/config.rs b/apps/recorder/src/message/config.rs new file mode 100644 index 0000000..ad6d6a7 --- /dev/null +++ b/apps/recorder/src/message/config.rs @@ -0,0 +1,4 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub struct MessageConfig {} diff --git a/apps/recorder/src/message/mod.rs b/apps/recorder/src/message/mod.rs new file mode 100644 index 0000000..0c9dd2f --- /dev/null +++ b/apps/recorder/src/message/mod.rs @@ -0,0 +1,5 @@ +mod config; +mod service; + +pub use config::MessageConfig; +pub use service::MessageService; diff --git a/apps/recorder/src/message/service.rs b/apps/recorder/src/message/service.rs new file mode 100644 index 0000000..a206fff --- /dev/null +++ b/apps/recorder/src/message/service.rs @@ -0,0 +1,12 @@ +use super::MessageConfig; +use crate::errors::RecorderResult; + +pub struct MessageService { + pub config: MessageConfig, +} + +impl MessageService { + pub async fn from_config(config: MessageConfig) -> RecorderResult { + Ok(Self { config }) + } +} diff --git a/apps/recorder/src/migrations/defs.rs b/apps/recorder/src/migrations/defs.rs index 7a63908..dd53b7c 100644 --- a/apps/recorder/src/migrations/defs.rs +++ b/apps/recorder/src/migrations/defs.rs @@ -150,6 +150,18 @@ pub enum Credential3rd { UserAgent, } +#[derive(DeriveIden)] +pub enum SubscriberTasks { + Table, + Id, + SubscriberId, + TaskType, + Request, + Result, + Error, + Yields, +} + macro_rules! create_postgres_enum_for_active_enum { ($manager: expr, $active_enum: expr, $($enum_value:expr),+) => { { diff --git a/apps/recorder/src/migrations/m20220101_000001_init.rs b/apps/recorder/src/migrations/m20220101_000001_init.rs index 3062833..d4e087b 100644 --- a/apps/recorder/src/migrations/m20220101_000001_init.rs +++ b/apps/recorder/src/migrations/m20220101_000001_init.rs @@ -338,7 +338,12 @@ impl MigrationTrait for Migration { .await?; manager - .drop_table(Table::drop().table(SubscriptionEpisode::Table).to_owned()) + .drop_table( + Table::drop() + .if_exists() + .table(SubscriptionEpisode::Table) + .to_owned(), + ) .await?; manager @@ -346,7 +351,7 @@ impl MigrationTrait for Migration { .await?; manager - .drop_table(Table::drop().table(Episodes::Table).to_owned()) + .drop_table(Table::drop().if_exists().table(Episodes::Table).to_owned()) .await?; manager @@ -360,7 +365,12 @@ impl MigrationTrait for Migration { .await?; manager - .drop_table(Table::drop().table(SubscriptionBangumi::Table).to_owned()) + .drop_table( + Table::drop() + .if_exists() + .table(SubscriptionBangumi::Table) + .to_owned(), + ) .await?; manager @@ -368,7 +378,7 @@ impl MigrationTrait for Migration { .await?; manager - .drop_table(Table::drop().table(Bangumi::Table).to_owned()) + .drop_table(Table::drop().if_exists().table(Bangumi::Table).to_owned()) .await?; manager @@ -379,7 +389,12 @@ impl MigrationTrait for Migration { .await?; manager - .drop_table(Table::drop().table(Subscriptions::Table).to_owned()) + .drop_table( + Table::drop() + .if_exists() + .table(Subscriptions::Table) + .to_owned(), + ) .await?; manager @@ -387,7 +402,12 @@ impl MigrationTrait for Migration { .await?; manager - .drop_table(Table::drop().table(Subscribers::Table).to_owned()) + .drop_table( + Table::drop() + .if_exists() + .table(Subscribers::Table) + .to_owned(), + ) .await?; manager diff --git a/apps/recorder/src/migrations/m20240224_082543_add_downloads.rs b/apps/recorder/src/migrations/m20240224_082543_add_downloads.rs index fb3994d..986731a 100644 --- a/apps/recorder/src/migrations/m20240224_082543_add_downloads.rs +++ b/apps/recorder/src/migrations/m20240224_082543_add_downloads.rs @@ -88,7 +88,7 @@ impl MigrationTrait for Migration { .col(enumeration( Downloads::Status, DownloadStatusEnum, - DownloadMime::iden_values(), + DownloadStatus::iden_values(), )) .col(enumeration( Downloads::Mime, @@ -158,7 +158,7 @@ impl MigrationTrait for Migration { .await?; manager - .drop_table(Table::drop().table(Downloads::Table).to_owned()) + .drop_table(Table::drop().if_exists().table(Downloads::Table).to_owned()) .await?; manager @@ -174,7 +174,12 @@ impl MigrationTrait for Migration { .await?; manager - .drop_table(Table::drop().table(Downloaders::Table).to_owned()) + .drop_table( + Table::drop() + .if_exists() + .table(Downloaders::Table) + .to_owned(), + ) .await?; manager diff --git a/apps/recorder/src/migrations/m20240225_060853_subscriber_add_downloader.rs b/apps/recorder/src/migrations/m20240225_060853_subscriber_add_downloader.rs deleted file mode 100644 index fa41e4a..0000000 --- a/apps/recorder/src/migrations/m20240225_060853_subscriber_add_downloader.rs +++ /dev/null @@ -1,103 +0,0 @@ -use sea_orm_migration::{prelude::*, schema::*}; - -use super::defs::table_auto_z; -use crate::{ - migrations::defs::{CustomSchemaManagerExt, Downloaders, GeneralIds, Subscribers}, - models::downloaders::{DownloaderCategory, DownloaderCategoryEnum}, -}; - -#[derive(DeriveMigrationName)] -pub struct Migration; - -#[async_trait::async_trait] -impl MigrationTrait for Migration { - async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - create_postgres_enum_for_active_enum!( - manager, - DownloaderCategoryEnum, - DownloaderCategory::QBittorrent - ) - .await?; - - manager - .create_table( - table_auto_z(Downloaders::Table) - .col(pk_auto(Downloaders::Id)) - .col(text(Downloaders::Endpoint)) - .col(string_null(Downloaders::Username)) - .col(string_null(Downloaders::Password)) - .col(enumeration( - Downloaders::Category, - DownloaderCategoryEnum, - DownloaderCategory::iden_values(), - )) - .col(text(Downloaders::SavePath)) - .col(integer(Downloaders::SubscriberId)) - .foreign_key( - ForeignKey::create() - .name("fk_downloader_subscriber_id") - .from_tbl(Downloaders::Table) - .from_col(Downloaders::SubscriberId) - .to_tbl(Subscribers::Table) - .to_col(Subscribers::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Restrict), - ) - .to_owned(), - ) - .await?; - - manager - .create_postgres_auto_update_ts_trigger_for_col( - Downloaders::Table, - GeneralIds::UpdatedAt, - ) - .await?; - - manager - .alter_table( - Table::alter() - .table(Subscribers::Table) - .add_column_if_not_exists(integer_null(Subscribers::DownloaderId)) - .add_foreign_key( - TableForeignKey::new() - .name("fk_subscribers_downloader_id") - .from_tbl(Subscribers::Table) - .from_col(Subscribers::DownloaderId) - .to_tbl(Downloaders::Table) - .to_col(Downloaders::Id) - .on_delete(ForeignKeyAction::SetNull) - .on_update(ForeignKeyAction::Restrict), - ) - .to_owned(), - ) - .await?; - Ok(()) - } - - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .alter_table( - Table::alter() - .table(Subscribers::Table) - .drop_foreign_key(Alias::new("fk_subscribers_downloader_id")) - .drop_column(Subscribers::DownloaderId) - .to_owned(), - ) - .await?; - - manager - .drop_postgres_auto_update_ts_trigger_for_col(Downloaders::Table, GeneralIds::UpdatedAt) - .await?; - - manager - .drop_table(Table::drop().table(Downloaders::Table).to_owned()) - .await?; - - manager - .drop_postgres_enum_for_active_enum(DownloaderCategoryEnum) - .await?; - - Ok(()) - } -} diff --git a/apps/recorder/src/migrations/m20241231_000001_auth.rs b/apps/recorder/src/migrations/m20241231_000001_auth.rs index 1d8eb2b..2029da9 100644 --- a/apps/recorder/src/migrations/m20241231_000001_auth.rs +++ b/apps/recorder/src/migrations/m20241231_000001_auth.rs @@ -52,6 +52,7 @@ impl MigrationTrait for Migration { manager .create_index( Index::create() + .if_not_exists() .name("idx_auth_pid_auth_type") .unique() .table(Auth::Table) @@ -102,7 +103,7 @@ impl MigrationTrait for Migration { .await?; manager - .drop_table(Table::drop().table(Auth::Table).to_owned()) + .drop_table(Table::drop().if_exists().table(Auth::Table).to_owned()) .await?; manager diff --git a/apps/recorder/src/migrations/m20250501_021523_credential_3rd.rs b/apps/recorder/src/migrations/m20250501_021523_credential_3rd.rs index c299e42..b718621 100644 --- a/apps/recorder/src/migrations/m20250501_021523_credential_3rd.rs +++ b/apps/recorder/src/migrations/m20250501_021523_credential_3rd.rs @@ -48,6 +48,7 @@ impl MigrationTrait for Migration { manager .create_index( Index::create() + .if_not_exists() .name("idx_credential_3rd_credential_type") .table(Credential3rd::Table) .col(Credential3rd::CredentialType) @@ -95,7 +96,19 @@ impl MigrationTrait for Migration { .await?; manager - .drop_table(Table::drop().table(Credential3rd::Table).to_owned()) + .drop_postgres_auto_update_ts_trigger_for_col( + Credential3rd::Table, + GeneralIds::UpdatedAt, + ) + .await?; + + manager + .drop_table( + Table::drop() + .if_exists() + .table(Credential3rd::Table) + .to_owned(), + ) .await?; manager diff --git a/apps/recorder/src/migrations/m20250508_022044_subscriber_tasks.rs b/apps/recorder/src/migrations/m20250508_022044_subscriber_tasks.rs new file mode 100644 index 0000000..4d59b98 --- /dev/null +++ b/apps/recorder/src/migrations/m20250508_022044_subscriber_tasks.rs @@ -0,0 +1,81 @@ +use sea_orm_migration::{ + prelude::*, + schema::{array, enumeration, integer, json_binary, json_binary_null, pk_auto}, +}; + +use super::defs::{SubscriberTasks, Subscribers, table_auto_z}; +use crate::models::subscriber_tasks::{SubscriberTaskType, SubscriberTaskTypeEnum}; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .create_table( + table_auto_z(SubscriberTasks::Table) + .col(pk_auto(SubscriberTasks::Id)) + .col(integer(SubscriberTasks::SubscriberId)) + .col(enumeration( + SubscriberTasks::TaskType, + SubscriberTaskTypeEnum, + SubscriberTaskType::iden_values(), + )) + .col(json_binary(SubscriberTasks::Request)) + .col(json_binary_null(SubscriberTasks::Result)) + .col(json_binary_null(SubscriberTasks::Error)) + .col( + array(SubscriberTasks::Yields, ColumnType::JsonBinary) + .default(SimpleExpr::Custom(String::from("ARRAY[]::jsonb[]"))), + ) + .foreign_key( + ForeignKey::create() + .name("fk_subscriber_tasks_subscriber_id") + .from_tbl(SubscriberTasks::Table) + .from_col(SubscriberTasks::SubscriberId) + .to_tbl(Subscribers::Table) + .to_col(Subscribers::Id) + .on_delete(ForeignKeyAction::Cascade) + .on_update(ForeignKeyAction::Cascade), + ) + .to_owned(), + ) + .await?; + + manager + .create_index( + Index::create() + .if_not_exists() + .name("idx_subscriber_tasks_task_type") + .table(SubscriberTasks::Table) + .col(SubscriberTasks::TaskType) + .to_owned(), + ) + .await?; + Ok(()) + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .drop_index( + Index::drop() + .if_exists() + .name("idx_subscriber_tasks_task_type") + .table(SubscriberTasks::Table) + .to_owned(), + ) + .await?; + + manager + .drop_table( + Table::drop() + .if_exists() + .table(SubscriberTasks::Table) + .to_owned(), + ) + .await?; + + Ok(()) + } +} diff --git a/apps/recorder/src/migrations/mod.rs b/apps/recorder/src/migrations/mod.rs index 89d4bce..daca141 100644 --- a/apps/recorder/src/migrations/mod.rs +++ b/apps/recorder/src/migrations/mod.rs @@ -5,9 +5,9 @@ pub use sea_orm_migration::prelude::*; pub mod defs; pub mod m20220101_000001_init; pub mod m20240224_082543_add_downloads; -pub mod m20240225_060853_subscriber_add_downloader; pub mod m20241231_000001_auth; pub mod m20250501_021523_credential_3rd; +pub mod m20250508_022044_subscriber_tasks; pub struct Migrator; @@ -17,9 +17,9 @@ impl MigratorTrait for Migrator { vec![ Box::new(m20220101_000001_init::Migration), Box::new(m20240224_082543_add_downloads::Migration), - Box::new(m20240225_060853_subscriber_add_downloader::Migration), Box::new(m20241231_000001_auth::Migration), Box::new(m20250501_021523_credential_3rd::Migration), + Box::new(m20250508_022044_subscriber_tasks::Migration), ] } } diff --git a/apps/recorder/src/models/mod.rs b/apps/recorder/src/models/mod.rs index 4fd1ce7..3ef7b58 100644 --- a/apps/recorder/src/models/mod.rs +++ b/apps/recorder/src/models/mod.rs @@ -5,6 +5,7 @@ pub mod downloaders; pub mod downloads; pub mod episodes; pub mod query; +pub mod subscriber_tasks; pub mod subscribers; pub mod subscription_bangumi; pub mod subscription_episode; diff --git a/apps/recorder/src/models/subscriber_tasks.rs b/apps/recorder/src/models/subscriber_tasks.rs new file mode 100644 index 0000000..793debc --- /dev/null +++ b/apps/recorder/src/models/subscriber_tasks.rs @@ -0,0 +1,153 @@ +use std::sync::Arc; + +use sea_orm::{ActiveValue, FromJsonQueryResult, JsonValue, TryIntoModel, prelude::*}; +use serde::{Deserialize, Serialize}; + +pub use crate::task::{SubscriberTaskType, SubscriberTaskTypeEnum}; +use crate::{app::AppContextTrait, errors::RecorderResult, task::SubscriberTask}; + +#[derive(Debug, Clone, Serialize, Deserialize, FromJsonQueryResult, PartialEq, Eq)] +pub struct SubscriberTaskErrorSnapshot { + pub message: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize, DeriveEntityModel, PartialEq, Eq)] +#[sea_orm(table_name = "subscriber_tasks")] +pub struct Model { + #[sea_orm(default_expr = "Expr::current_timestamp()")] + pub created_at: DateTimeUtc, + #[sea_orm(default_expr = "Expr::current_timestamp()")] + pub updated_at: DateTimeUtc, + #[sea_orm(primary_key)] + pub id: i32, + pub subscriber_id: i32, + pub task_type: SubscriberTaskType, + pub request: JsonValue, + pub yields: Vec, + pub result: Option, + pub error: Option, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::subscribers::Entity", + from = "Column::SubscriberId", + to = "super::subscribers::Column::Id" + )] + Subscriber, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Subscriber.def() + } +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelatedEntity)] +pub enum RelatedEntity { + #[sea_orm(entity = "super::subscribers::Entity")] + Subscriber, +} + +impl ActiveModelBehavior for ActiveModel {} + +impl Model { + pub async fn update_result( + ctx: Arc, + task_id: i32, + result: R, + ) -> RecorderResult<()> + where + R: Serialize, + { + let db = ctx.db(); + + let result_value = serde_json::to_value(result)?; + + Entity::update_many() + .filter(Column::Id.eq(task_id)) + .set(ActiveModel { + result: ActiveValue::Set(Some(result_value)), + ..Default::default() + }) + .exec(db) + .await?; + + Ok(()) + } + + pub async fn update_error( + ctx: Arc, + task_id: i32, + error: SubscriberTaskErrorSnapshot, + ) -> RecorderResult<()> { + let db = ctx.db(); + + let error_value = serde_json::to_value(&error)?; + + Entity::update_many() + .filter(Column::Id.eq(task_id)) + .set(ActiveModel { + error: ActiveValue::Set(Some(error_value)), + ..Default::default() + }) + .exec(db) + .await?; + + Ok(()) + } + + pub async fn append_yield( + ctx: Arc, + task_id: i32, + item: Y, + ) -> RecorderResult<()> + where + Y: Serialize, + { + let db = ctx.db(); + + let yield_value = serde_json::to_value(item)?; + + Entity::update_many() + .filter(Column::Id.eq(task_id)) + .col_expr( + Column::Yields, + Expr::cust_with_values("array_append($1)", [yield_value]), + ) + .exec(db) + .await?; + + Ok(()) + } + + pub async fn add_subscriber_task( + ctx: Arc, + subscriber_id: i32, + task_type: SubscriberTaskType, + request: JsonValue, + ) -> RecorderResult { + let am = ActiveModel { + subscriber_id: ActiveValue::Set(subscriber_id), + task_type: ActiveValue::Set(task_type.clone()), + request: ActiveValue::Set(request.clone()), + ..Default::default() + }; + + let db = ctx.db(); + + let model = am.insert(db).await?.try_into_model()?; + + let task_value: SubscriberTask = serde_json::from_value(serde_json::json!({ + "id": model.id, + "subscriber_id": model.subscriber_id.clone(), + "task_type": model.task_type.clone(), + "request": model.request.clone(), + }))?; + + ctx.task().add_subscriber_task(task_value).await?; + + Ok(model) + } +} diff --git a/apps/recorder/src/models/subscribers.rs b/apps/recorder/src/models/subscribers.rs index 843c8a9..ee5d62d 100644 --- a/apps/recorder/src/models/subscribers.rs +++ b/apps/recorder/src/models/subscribers.rs @@ -39,6 +39,8 @@ pub enum Relation { Episode, #[sea_orm(has_many = "super::auth::Entity")] Auth, + #[sea_orm(has_many = "super::subscriber_tasks::Entity")] + SubscriberTasks, } impl Related for Entity { @@ -71,6 +73,12 @@ impl Related for Entity { } } +impl Related for Entity { + fn to() -> RelationDef { + Relation::SubscriberTasks.def() + } +} + #[derive(Copy, Clone, Debug, EnumIter, DeriveRelatedEntity)] pub enum RelatedEntity { #[sea_orm(entity = "super::subscriptions::Entity")] @@ -81,6 +89,8 @@ pub enum RelatedEntity { Bangumi, #[sea_orm(entity = "super::episodes::Entity")] Episode, + #[sea_orm(entity = "super::subscriber_tasks::Entity")] + SubscriberTasks, } #[derive(Debug, Deserialize, Serialize)] diff --git a/apps/recorder/src/models/subscriptions.rs b/apps/recorder/src/models/subscriptions.rs index 1921758..3c5179f 100644 --- a/apps/recorder/src/models/subscriptions.rs +++ b/apps/recorder/src/models/subscriptions.rs @@ -147,8 +147,6 @@ pub enum RelatedEntity { SubscriptionEpisode, #[sea_orm(entity = "super::subscription_bangumi::Entity")] SubscriptionBangumi, - #[sea_orm(entity = "super::credential_3rd::Entity")] - Credential3rd, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] diff --git a/apps/recorder/src/tasks/config.rs b/apps/recorder/src/task/config.rs similarity index 100% rename from apps/recorder/src/tasks/config.rs rename to apps/recorder/src/task/config.rs diff --git a/apps/recorder/src/task/core.rs b/apps/recorder/src/task/core.rs new file mode 100644 index 0000000..e4dbc66 --- /dev/null +++ b/apps/recorder/src/task/core.rs @@ -0,0 +1,81 @@ +use std::sync::Arc; + +use futures::{Stream, TryStreamExt, pin_mut}; +use serde::{Serialize, de::DeserializeOwned}; + +use crate::{ + app::AppContextTrait, + errors::RecorderResult, + models::subscriber_tasks::{self, SubscriberTaskErrorSnapshot}, +}; + +pub const SUBSCRIBER_TASK_APALIS_NAME: &str = "subscriber_task"; + +#[async_trait::async_trait] +pub trait SubscriberAsyncTaskTrait: Serialize + DeserializeOwned + Sized { + type Result: Serialize + DeserializeOwned + Send; + + async fn run_async( + self, + ctx: Arc, + id: i32, + ) -> RecorderResult; + + async fn run(self, ctx: Arc, id: i32) -> RecorderResult<()> { + match self.run_async(ctx.clone(), id).await { + Ok(result) => { + subscriber_tasks::Model::update_result(ctx, id, result).await?; + } + Err(e) => { + let error_snapshot = SubscriberTaskErrorSnapshot { + message: e.to_string(), + }; + + subscriber_tasks::Model::update_error(ctx, id, error_snapshot).await?; + + return Err(e); + } + } + + Ok(()) + } +} + +#[async_trait::async_trait] +pub trait SubscriberStreamTaskTrait: Serialize + DeserializeOwned + Sized { + type Yield: Serialize + DeserializeOwned + Send; + + fn run_stream( + self, + ctx: Arc, + ) -> impl Stream> + Send; + + async fn run(self, ctx: Arc, id: i32) -> RecorderResult<()> { + let stream = self.run_stream(ctx.clone()); + + pin_mut!(stream); + + loop { + match stream.try_next().await { + Ok(Some(result)) => { + subscriber_tasks::Model::append_yield(ctx.clone(), id, result).await?; + } + Ok(None) => { + subscriber_tasks::Model::update_result(ctx, id, ()).await?; + break; + } + Err(e) => { + let error_snapshot = SubscriberTaskErrorSnapshot { + message: e.to_string(), + }; + + subscriber_tasks::Model::update_error(ctx, id, error_snapshot).await?; + + return Err(e); + } + } + } + + Ok(()) + } +} diff --git a/apps/recorder/src/task/mikan/mod.rs b/apps/recorder/src/task/mikan/mod.rs new file mode 100644 index 0000000..4b407eb --- /dev/null +++ b/apps/recorder/src/task/mikan/mod.rs @@ -0,0 +1,3 @@ +mod scrape_season_subscription; + +pub use scrape_season_subscription::MikanScrapeSeasonSubscriptionTask; diff --git a/apps/recorder/src/task/mikan/scrape_season_subscription.rs b/apps/recorder/src/task/mikan/scrape_season_subscription.rs new file mode 100644 index 0000000..72a7af9 --- /dev/null +++ b/apps/recorder/src/task/mikan/scrape_season_subscription.rs @@ -0,0 +1,45 @@ +use std::sync::Arc; + +use futures::Stream; +use sea_orm::FromJsonQueryResult; +use serde::{Deserialize, Serialize}; + +use crate::{ + app::AppContextTrait, + errors::RecorderResult, + extract::mikan::{ + MikanBangumiMeta, MikanSeasonStr, build_mikan_season_flow_url, + scrape_mikan_bangumi_meta_stream_from_season_flow_url, + }, + task::SubscriberStreamTaskTrait, +}; + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, FromJsonQueryResult)] +pub struct MikanScrapeSeasonSubscriptionTask { + pub task_id: i32, + pub year: i32, + pub season_str: MikanSeasonStr, + pub credential_id: i32, + pub subscriber_id: i32, +} + +#[async_trait::async_trait] +impl SubscriberStreamTaskTrait for MikanScrapeSeasonSubscriptionTask { + type Yield = MikanBangumiMeta; + + fn run_stream( + self, + ctx: Arc, + ) -> impl Stream> { + let mikan_base_url = ctx.mikan().base_url().clone(); + + let mikan_season_flow_url = + build_mikan_season_flow_url(mikan_base_url, self.year, self.season_str); + + scrape_mikan_bangumi_meta_stream_from_season_flow_url( + ctx.clone(), + mikan_season_flow_url, + self.credential_id, + ) + } +} diff --git a/apps/recorder/src/task/mod.rs b/apps/recorder/src/task/mod.rs new file mode 100644 index 0000000..6b891b2 --- /dev/null +++ b/apps/recorder/src/task/mod.rs @@ -0,0 +1,13 @@ +mod config; +mod core; +pub mod mikan; +mod registry; +mod service; + +pub use core::{SUBSCRIBER_TASK_APALIS_NAME, SubscriberAsyncTaskTrait, SubscriberStreamTaskTrait}; + +pub use config::TaskConfig; +pub use registry::{ + SubscriberTask, SubscriberTaskPayload, SubscriberTaskType, SubscriberTaskTypeEnum, +}; +pub use service::TaskService; diff --git a/apps/recorder/src/task/registry.rs b/apps/recorder/src/task/registry.rs new file mode 100644 index 0000000..8165d0c --- /dev/null +++ b/apps/recorder/src/task/registry.rs @@ -0,0 +1,33 @@ +use sea_orm::{DeriveActiveEnum, DeriveDisplay, prelude::*}; +use serde::{Deserialize, Serialize}; + +use super::mikan::MikanScrapeSeasonSubscriptionTask; + +#[derive( + Clone, Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, DeriveDisplay, Serialize, Deserialize, +)] +#[sea_orm( + rs_type = "String", + db_type = "String(StringLen::None)", + enum_name = "subscriber_task_type" +)] +#[serde(rename_all = "snake_case")] +pub enum SubscriberTaskType { + #[sea_orm(string_value = "mikan_scrape_season_subscription")] + MikanScrapeSeasonSubscription, +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[serde(tag = "task_type")] +pub enum SubscriberTaskPayload { + #[serde(rename = "mikan_scrape_season_subscription")] + MikanScrapeSeasonSubscription(MikanScrapeSeasonSubscriptionTask), +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +pub struct SubscriberTask { + pub id: i32, + pub subscriber_id: i32, + #[serde(flatten)] + pub payload: SubscriberTaskPayload, +} diff --git a/apps/recorder/src/task/service.rs b/apps/recorder/src/task/service.rs new file mode 100644 index 0000000..d834dbe --- /dev/null +++ b/apps/recorder/src/task/service.rs @@ -0,0 +1,77 @@ +use std::{ops::Deref, sync::Arc}; + +use apalis::prelude::*; +use apalis_sql::postgres::PostgresStorage; +use tokio::sync::RwLock; + +use crate::{ + app::AppContextTrait, + errors::RecorderResult, + task::{ + SUBSCRIBER_TASK_APALIS_NAME, SubscriberStreamTaskTrait, SubscriberTask, + SubscriberTaskPayload, TaskConfig, + }, +}; + +pub struct TaskService { + pub config: TaskConfig, + ctx: Arc, + subscriber_task_storage: Arc>>, +} + +impl TaskService { + pub async fn from_config_and_ctx( + config: TaskConfig, + ctx: Arc, + ) -> RecorderResult { + let pool = ctx.db().get_postgres_connection_pool().clone(); + let subscriber_task_storage = Arc::new(RwLock::new(PostgresStorage::new(pool))); + + Ok(Self { + config, + ctx, + subscriber_task_storage, + }) + } + + async fn run_subscriber_task( + job: SubscriberTask, + data: Data>, + ) -> RecorderResult<()> { + let ctx = data.deref().clone(); + + match job.payload { + SubscriberTaskPayload::MikanScrapeSeasonSubscription(task) => { + task.run(ctx, job.id).await + } + } + } + + pub async fn add_subscriber_task(&self, job: SubscriberTask) -> RecorderResult<()> { + { + let mut storage = self.subscriber_task_storage.write().await; + storage.push(job).await?; + } + + Ok(()) + } + + pub async fn setup(&self) -> RecorderResult<()> { + let monitor = Monitor::new(); + let worker = WorkerBuilder::new(SUBSCRIBER_TASK_APALIS_NAME) + .catch_panic() + .enable_tracing() + .data(self.ctx.clone()) + .backend({ + let storage = self.subscriber_task_storage.read().await; + storage.clone() + }) + .build_fn(Self::run_subscriber_task); + + let monitor = monitor.register(worker); + + monitor.run().await?; + + Ok(()) + } +} diff --git a/apps/recorder/src/tasks/mikan/mod.rs b/apps/recorder/src/tasks/mikan/mod.rs deleted file mode 100644 index 70dbf35..0000000 --- a/apps/recorder/src/tasks/mikan/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -mod scrape_season_subscription; - -pub use scrape_season_subscription::{ - ScrapeMikanSeasonSubscriptionTask, ScrapeMikanSeasonSubscriptionTaskResult, - register_scrape_mikan_season_subscription_task, -}; diff --git a/apps/recorder/src/tasks/mikan/scrape_season_subscription.rs b/apps/recorder/src/tasks/mikan/scrape_season_subscription.rs deleted file mode 100644 index c71fa21..0000000 --- a/apps/recorder/src/tasks/mikan/scrape_season_subscription.rs +++ /dev/null @@ -1,87 +0,0 @@ -use std::{ops::Deref, sync::Arc}; - -use apalis::prelude::*; -use apalis_sql::postgres::PostgresStorage; -use serde::{Deserialize, Serialize}; - -use crate::{ - app::AppContextTrait, - errors::RecorderResult, - extract::mikan::{ - MikanBangumiMeta, MikanSeasonStr, build_mikan_season_flow_url, - scrape_mikan_bangumi_meta_list_from_season_flow_url, - }, -}; - -const TASK_NAME: &str = "mikan_extract_season_subscription"; - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct ScrapeMikanSeasonSubscriptionTask { - pub task_id: i32, - pub year: i32, - pub season_str: MikanSeasonStr, - pub credential_id: i32, - pub subscription_id: i32, - pub subscriber_id: i32, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct ScrapeMikanSeasonSubscriptionTaskResult { - pub task_id: i32, - pub year: i32, - pub season_str: MikanSeasonStr, - pub credential_id: i32, - pub subscription_id: i32, - pub subscriber_id: i32, - pub bangumi_meta_list: Vec, -} - -pub async fn scrape_mikan_season_subscription( - job: ScrapeMikanSeasonSubscriptionTask, - data: Data>, -) -> RecorderResult> { - let ctx = data.deref(); - - let mikan_client = ctx.mikan(); - let mikan_base_url = mikan_client.base_url(); - - let mikan_season_flow_url = - build_mikan_season_flow_url(mikan_base_url.clone(), job.year, job.season_str); - - let bangumi_meta_list = scrape_mikan_bangumi_meta_list_from_season_flow_url( - mikan_client, - ctx.clone(), - mikan_season_flow_url, - job.credential_id, - ) - .await?; - - Ok(GoTo::Done(ScrapeMikanSeasonSubscriptionTaskResult { - bangumi_meta_list, - credential_id: job.credential_id, - season_str: job.season_str, - subscriber_id: job.subscriber_id, - subscription_id: job.subscription_id, - task_id: job.task_id, - year: job.year, - })) -} - -pub fn register_scrape_mikan_season_subscription_task( - monitor: Monitor, - ctx: Arc, -) -> RecorderResult<(Monitor, PostgresStorage>)> { - let pool = ctx.db().get_postgres_connection_pool().clone(); - let storage = PostgresStorage::new(pool); - - let steps = StepBuilder::new().step_fn(scrape_mikan_season_subscription); - - let worker = WorkerBuilder::new(TASK_NAME) - .catch_panic() - .enable_tracing() - .data(ctx) - .backend(storage.clone()) - .build_stepped(steps); - - Ok((monitor.register(worker), storage)) -} diff --git a/apps/recorder/src/tasks/mod.rs b/apps/recorder/src/tasks/mod.rs deleted file mode 100644 index 9c8035b..0000000 --- a/apps/recorder/src/tasks/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub mod config; -pub mod mikan; -pub mod service; - -pub use config::TaskConfig; -pub use service::TaskService; diff --git a/apps/recorder/src/tasks/service.rs b/apps/recorder/src/tasks/service.rs deleted file mode 100644 index 12d4d93..0000000 --- a/apps/recorder/src/tasks/service.rs +++ /dev/null @@ -1,41 +0,0 @@ -use std::{fmt::Debug, sync::Arc}; - -use apalis::prelude::*; -use apalis_sql::postgres::PostgresStorage; -use tokio::sync::Mutex; - -use super::{TaskConfig, mikan::register_scrape_mikan_season_subscription_task}; -use crate::{app::AppContextTrait, errors::RecorderResult}; - -pub struct TaskService { - config: TaskConfig, - #[allow(dead_code)] - monitor: Arc>, - pub scrape_mikan_season_subscription_task_storage: - PostgresStorage>, -} - -impl TaskService { - pub async fn from_config_and_ctx( - config: TaskConfig, - ctx: Arc, - ) -> RecorderResult { - let monitor = Monitor::new(); - let (monitor, scrape_mikan_season_subscription_task_storage) = - register_scrape_mikan_season_subscription_task(monitor, ctx.clone())?; - - Ok(Self { - config, - monitor: Arc::new(Mutex::new(monitor)), - scrape_mikan_season_subscription_task_storage, - }) - } -} - -impl Debug for TaskService { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("TaskService") - .field("config", &self.config) - .finish() - } -} diff --git a/apps/recorder/src/test_utils/app.rs b/apps/recorder/src/test_utils/app.rs index 22b8937..57390ef 100644 --- a/apps/recorder/src/test_utils/app.rs +++ b/apps/recorder/src/test_utils/app.rs @@ -16,7 +16,8 @@ pub struct UnitTestAppContext { graphql: Option, storage: Option, crypto: Option, - tasks: Option, + task: Option, + message: Option, #[builder(default = Some(String::from(env!("CARGO_MANIFEST_DIR"))))] working_dir: Option, #[builder(default = crate::app::Environment::Testing, setter(!strip_option))] @@ -74,7 +75,11 @@ impl AppContextTrait for UnitTestAppContext { self.crypto.as_ref().expect("should set crypto") } - fn task(&self) -> &crate::tasks::TaskService { - self.tasks.as_ref().expect("should set tasks") + fn task(&self) -> &crate::task::TaskService { + self.task.as_ref().expect("should set tasks") + } + + fn message(&self) -> &crate::message::MessageService { + self.message.as_ref().expect("should set message") } } diff --git a/apps/webui/src/infra/graphql/gql/graphql.ts b/apps/webui/src/infra/graphql/gql/graphql.ts index 05ed1d9..3f8d73b 100644 --- a/apps/webui/src/infra/graphql/gql/graphql.ts +++ b/apps/webui/src/infra/graphql/gql/graphql.ts @@ -1189,6 +1189,7 @@ export type Subscriptions = { bangumi: BangumiConnection; category: SubscriptionCategoryEnum; createdAt: Scalars['String']['output']; + credentialId?: Maybe; displayName: Scalars['String']['output']; enabled: Scalars['Boolean']['output']; episode: EpisodesConnection; @@ -1233,6 +1234,7 @@ export type SubscriptionsBasic = { __typename?: 'SubscriptionsBasic'; category: SubscriptionCategoryEnum; createdAt: Scalars['String']['output']; + credentialId?: Maybe; displayName: Scalars['String']['output']; enabled: Scalars['Boolean']['output']; id: Scalars['Int']['output']; @@ -1259,6 +1261,7 @@ export type SubscriptionsFilterInput = { and?: InputMaybe>; category?: InputMaybe; createdAt?: InputMaybe; + credentialId?: InputMaybe; displayName?: InputMaybe; enabled?: InputMaybe; id?: InputMaybe; @@ -1271,6 +1274,7 @@ export type SubscriptionsFilterInput = { export type SubscriptionsInsertInput = { category: SubscriptionCategoryEnum; createdAt?: InputMaybe; + credentialId?: InputMaybe; displayName: Scalars['String']['input']; enabled: Scalars['Boolean']['input']; id?: InputMaybe; @@ -1281,6 +1285,7 @@ export type SubscriptionsInsertInput = { export type SubscriptionsOrderInput = { category?: InputMaybe; createdAt?: InputMaybe; + credentialId?: InputMaybe; displayName?: InputMaybe; enabled?: InputMaybe; id?: InputMaybe; @@ -1292,6 +1297,7 @@ export type SubscriptionsOrderInput = { export type SubscriptionsUpdateInput = { category?: InputMaybe; createdAt?: InputMaybe; + credentialId?: InputMaybe; displayName?: InputMaybe; enabled?: InputMaybe; id?: InputMaybe; diff --git a/justfile b/justfile index e6f3da0..6732936 100644 --- a/justfile +++ b/justfile @@ -19,6 +19,9 @@ dev-proxy: dev-recorder: watchexec -r -w apps/recorder -- cargo run -p recorder --bin recorder_cli -- --environment development +dev-recorder-migrate-down: + cargo run -p recorder --bin migrate_down -- --environment development + dev-deps: docker compose -f devdeps.compose.yaml up