From 9211b4b87ac436c0944007d27a83cf15681abdc6 Mon Sep 17 00:00:00 2001 From: mental Date: Wed, 5 Apr 2023 22:41:08 +0100 Subject: [PATCH] dim-web (#537) * dim-web: initial commit * address compiler warnings * dim-web: begin porting warp handlers to axum * dim-web: finish migrating warp routes into axum router * rebase dim-web on master * PR feedback * Update dim-web/src/routes/websocket.rs Co-authored-by: Valerian G. --------- Co-authored-by: Valerian G. --- .vscode/settings.json | 4 +- Cargo.lock | 1239 ++++++++++++++++------------ Cargo.toml | 10 +- dim-database/Cargo.toml | 4 +- dim-database/{src => }/build.rs | 0 dim-database/src/lib.rs | 1 + dim-events/src/lib.rs | 2 + dim-utils/Cargo.toml | 9 + dim-utils/src/lib.rs | 519 ++++++++++++ dim-web/Cargo.toml | 37 + dim-web/build.rs | 11 + dim-web/src/lib.rs | 15 + dim-web/src/routes/mod.rs | 1 + dim-web/src/routes/websocket.rs | 261 ++++++ dim-web/src/tree.rs | 269 ++++++ dim/Cargo.toml | 21 +- dim/src/core.rs | 331 +++++--- dim/src/lib.rs | 11 +- dim/src/main.rs | 4 +- dim/src/routes/dashboard.rs | 16 +- dim/src/routes/mod.rs | 3 +- dim/src/routes/stream.rs | 5 +- dim/src/routes/websocket.rs | 44 + dim/src/scanner/mediafile.rs | 20 +- dim/src/scanner/movie.rs | 6 +- dim/src/scanner/tests/mediafile.rs | 4 +- dim/src/utils.rs | 523 +----------- dim/src/websocket.rs | 234 ------ 28 files changed, 2146 insertions(+), 1458 deletions(-) rename dim-database/{src => }/build.rs (100%) create mode 100644 dim-utils/Cargo.toml create mode 100644 dim-utils/src/lib.rs create mode 100644 dim-web/Cargo.toml create mode 100644 dim-web/build.rs create mode 100644 dim-web/src/lib.rs create mode 100644 dim-web/src/routes/mod.rs create mode 100644 dim-web/src/routes/websocket.rs create mode 100644 dim-web/src/tree.rs create mode 100644 dim/src/routes/websocket.rs delete mode 100644 dim/src/websocket.rs diff --git a/.vscode/settings.json b/.vscode/settings.json index a6cd09893..4268deecf 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,4 @@ { "rust-analyzer.cargo.allFeatures": false, - "rust-analyzer.cargo.features": [] -} + "rust-analyzer.cargo.features": [], +} \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 068f058ba..f258b88ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -56,9 +56,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.18" +version = "0.7.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" dependencies = [ "memchr", ] @@ -116,9 +116,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345fd392ab01f746c717b1357165b76f0b67a60192007b234058c9045fdcf695" +checksum = "942c7cd7ae39e91bde4820d74132e9862e62c2f386c3aa90ccf55949f5bad63a" dependencies = [ "brotli", "futures-core", @@ -153,7 +153,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", "winapi", ] @@ -164,6 +164,58 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "axum" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f8ccfd9221ee7d1f3d4b33e1f8319b3a81ed8f61f2ea40b37b859794b4491" +dependencies = [ + "async-trait", + "axum-core", + "base64 0.21.0", + "bitflags", + "bytes 1.4.0", + "futures-util", + "http", + "http-body", + "hyper", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sha1", + "sync_wrapper", + "tokio", + "tokio-tungstenite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2f958c80c248b34b9a877a643811be8dbca03ca5ba827f2b63baf3a81e5fc4e" +dependencies = [ + "async-trait", + "bytes 1.4.0", + "futures-util", + "http", + "http-body", + "mime", + "rustversion", + "tower-layer", + "tower-service", +] + [[package]] name = "barrage" version = "0.2.3" @@ -172,14 +224,14 @@ checksum = "be5951c75bdabb58753d140dd5802f12ff3a483cb2e16fb5276e111b94b19e87" dependencies = [ "concurrent-queue", "event-listener", - "spin 0.9.3", + "spin 0.9.8", ] [[package]] name = "base64" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" @@ -189,9 +241,9 @@ checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" [[package]] name = "bit_field" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" [[package]] name = "bitflags" @@ -201,9 +253,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "block-buffer" -version = "0.10.2" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array", ] @@ -221,36 +273,14 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "2.3.2" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ad2d4653bf5ca36ae797b1f4bb4dbddb60ce49ca4aed8a2ce4829f60425b80" +checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", ] -[[package]] -name = "bstr" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" -dependencies = [ - "lazy_static", - "memchr", - "regex-automata", - "serde", -] - -[[package]] -name = "buf_redux" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b953a6887648bb07a535631f2bc00fbdb2a2216f135552cb3f534ed136b9c07f" -dependencies = [ - "memchr", - "safemem", -] - [[package]] name = "bumpalo" version = "3.12.0" @@ -259,9 +289,9 @@ checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "bytemuck" -version = "1.12.1" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f5715e491b5a1598fc2bef5a606847b5dc1d48ea625bd3c02c00de8285591da" +checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" [[package]] name = "byteorder" @@ -277,9 +307,9 @@ checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" [[package]] name = "bytes" -version = "1.1.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "bzip2" @@ -308,15 +338,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c" -[[package]] -name = "cast" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a" -dependencies = [ - "rustc_version", -] - [[package]] name = "cast" version = "0.3.0" @@ -329,14 +350,14 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcf0adb3cc1c06945672f8dcc827e42497ac6d0aff49f459ec918132b82a5cbc" dependencies = [ - "spin 0.9.3", + "spin 0.9.8", ] [[package]] name = "cc" -version = "1.0.73" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" dependencies = [ "jobserver", ] @@ -358,7 +379,7 @@ dependencies = [ "num-integer", "num-traits", "serde", - "time 0.1.44", + "time 0.1.45", "wasm-bindgen", "winapi", ] @@ -405,9 +426,9 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "concurrent-queue" -version = "1.2.2" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" +checksum = "af4780a44ab5696ea9e28294517f1fffb421a83a25af521333c838635509db9c" dependencies = [ "cache-padded", ] @@ -420,9 +441,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "cpufeatures" -version = "0.2.2" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +checksum = "280a9f2d8b3a38871a3c8a46fb80db65e5e5ed97da80c4d08bf27fb63e35e181" dependencies = [ "libc", ] @@ -458,7 +479,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" dependencies = [ "atty", - "cast 0.3.0", + "cast", "clap", "criterion-plot", "csv", @@ -481,19 +502,19 @@ dependencies = [ [[package]] name = "criterion-plot" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57" +checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" dependencies = [ - "cast 0.2.7", + "cast", "itertools", ] [[package]] name = "crossbeam-channel" -version = "0.5.5" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c" +checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c" dependencies = [ "cfg-if", "crossbeam-utils", @@ -501,9 +522,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -512,23 +533,22 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.9" +version = "0.9.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07db9d94cbd326813772c968ccd25999e5f8ae22f4f8d1b11effa37ef6ce281d" +checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "memoffset", - "once_cell", + "memoffset 0.8.0", "scopeguard", ] [[package]] name = "crossbeam-queue" -version = "0.3.5" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2" +checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" dependencies = [ "cfg-if", "crossbeam-utils", @@ -536,19 +556,24 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.10" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83" +checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" dependencies = [ "cfg-if", - "once_cell", ] +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "crypto-common" -version = "0.1.3" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", "typenum", @@ -556,13 +581,12 @@ dependencies = [ [[package]] name = "csv" -version = "1.1.6" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" +checksum = "0b015497079b9a9d69c02ad25de6c0a6edef051ea6360a327d0bd05802ef64ad" dependencies = [ - "bstr", "csv-core", - "itoa 0.4.8", + "itoa", "ryu", "serde", ] @@ -659,7 +683,7 @@ dependencies = [ "hashbrown 0.12.3", "lock_api", "once_cell", - "parking_lot_core 0.9.3", + "parking_lot_core 0.9.7", ] [[package]] @@ -670,9 +694,9 @@ checksum = "292babb903a8ffc5e23d17085137a0f33c00a07dfbc6117619c7e6dc7f4111ae" [[package]] name = "digest" -version = "0.10.3" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" dependencies = [ "block-buffer", "crypto-common", @@ -683,7 +707,7 @@ name = "dim" version = "0.4.0-dev" dependencies = [ "async-trait", - "bytes 1.1.0", + "bytes 1.4.0", "cfg-if", "chrono", "criterion", @@ -692,6 +716,8 @@ dependencies = [ "dim-database", "dim-events", "dim-extern-api", + "dim-utils", + "dim-web", "displaydoc", "dominant_color", "fdlimit", @@ -705,7 +731,7 @@ dependencies = [ "lazy_static", "libsqlite3-sys", "nightfall", - "nix 0.23.1", + "nix 0.23.2", "notify", "once_cell", "parking_lot 0.12.1", @@ -723,18 +749,20 @@ dependencies = [ "tempfile", "thiserror", "tokio", + "tokio-stream", + "tokio-tungstenite", "toml", + "tower-http", "tracing", "tracing-appender", "tracing-subscriber", "tracing-tree", "url", - "uuid 1.2.2", + "uuid 1.3.0", "walkdir", "warp", "xmlwriter", - "xtra 0.5.2", - "xtra 0.6.0", + "xtra", "zip", ] @@ -743,7 +771,7 @@ name = "dim-auth" version = "0.4.0-dev" dependencies = [ "aes-gcm", - "base64 0.13.0", + "base64 0.13.1", "displaydoc", "once_cell", "rand", @@ -755,7 +783,7 @@ dependencies = [ name = "dim-database" version = "0.4.0-dev" dependencies = [ - "base64 0.13.0", + "base64 0.13.1", "cfg-if", "dim-auth", "displaydoc", @@ -804,6 +832,46 @@ dependencies = [ "tracing", ] +[[package]] +name = "dim-utils" +version = "0.1.0" +dependencies = [ + "dia-i18n", +] + +[[package]] +name = "dim-web" +version = "0.1.0" +dependencies = [ + "axum", + "chrono", + "dim-database", + "dim-events", + "dim-utils", + "displaydoc", + "futures", + "fuzzy-matcher", + "http", + "hyper", + "nightfall", + "once_cell", + "percent-encoding", + "rust-embed", + "serde", + "serde_derive", + "serde_json", + "sqlx", + "thiserror", + "tokio", + "tower", + "tracing", + "tracing-appender", + "tracing-subscriber", + "tracing-tree", + "uuid 1.3.0", + "warp", +] + [[package]] name = "displaydoc" version = "0.2.3" @@ -812,7 +880,7 @@ checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886" dependencies = [ "proc-macro2", "quote", - "syn 1.0.98", + "syn 1.0.109", ] [[package]] @@ -829,15 +897,15 @@ checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" [[package]] name = "either" -version = "1.6.1" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "encoding_rs" -version = "0.8.31" +version = "0.8.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" dependencies = [ "cfg-if", ] @@ -852,29 +920,51 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 1.0.98", + "syn 1.0.109", "synstructure", ] +[[package]] +name = "errno" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d6a0976c999d473fe89ad888d5a284e55366d9dc9038b1ba2aa15128c4afa0" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.45.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "event-listener" -version = "2.5.2" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "exr" -version = "1.5.0" +version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c26a90d9dd411a3d119d6f55752fb4c134ca243250c32fb9cab7b2561638d2" +checksum = "bdd2162b720141a91a054640662d3edce3d50a944a50ffca5313cd951abb35b4" dependencies = [ "bit_field", "flume", - "half", + "half 2.2.1", "lebe", "miniz_oxide", + "rayon-core", "smallvec", - "threadpool", + "zune-inflate", ] [[package]] @@ -891,9 +981,9 @@ checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" [[package]] name = "fastrand" -version = "1.7.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" dependencies = [ "instant", ] @@ -909,21 +999,21 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.16" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0408e2626025178a6a7f7ffc05a25bc47103229f19c113755de7bf63816290c" +checksum = "8a3de6e8d11b22ff9edc6d916f890800597d60f8b2da1caf2955c274638d6412" dependencies = [ "cfg-if", "libc", - "redox_syscall", - "winapi", + "redox_syscall 0.2.16", + "windows-sys 0.45.0", ] [[package]] name = "flate2" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" +checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" dependencies = [ "crc32fast", "miniz_oxide", @@ -931,15 +1021,15 @@ dependencies = [ [[package]] name = "flume" -version = "0.10.13" +version = "0.10.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ceeb589a3157cac0ab8cc585feb749bd2cea5cb55a6ee802ad72d9fd38303da" +checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" dependencies = [ "futures-core", "futures-sink", "nanorand", "pin-project", - "spin 0.9.3", + "spin 0.9.8", ] [[package]] @@ -950,19 +1040,18 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" dependencies = [ - "matches", "percent-encoding", ] [[package]] name = "fs_extra" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] name = "fsevent-sys" @@ -975,9 +1064,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" dependencies = [ "futures-channel", "futures-core", @@ -990,9 +1079,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", "futures-sink", @@ -1000,15 +1089,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" [[package]] name = "futures-executor" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" dependencies = [ "futures-core", "futures-task", @@ -1017,9 +1106,9 @@ dependencies = [ [[package]] name = "futures-intrusive" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62007592ac46aa7c2b6416f7deb9a8a8f63a01e0f1d6e1787d5630170db2b63e" +checksum = "a604f7a68fbf8103337523b1fadc8ade7361ee3f112f7c680ad179651616aed5" dependencies = [ "futures-core", "lock_api", @@ -1028,32 +1117,32 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" [[package]] name = "futures-macro" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 1.0.98", + "syn 2.0.13", ] [[package]] name = "futures-sink" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" [[package]] name = "futures-task" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" [[package]] name = "futures-timer" @@ -1063,9 +1152,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures-channel", "futures-core", @@ -1090,9 +1179,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.5" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -1100,9 +1189,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" dependencies = [ "cfg-if", "js-sys", @@ -1123,9 +1212,9 @@ dependencies = [ [[package]] name = "gif" -version = "0.11.4" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3edd93c6756b4dfaf2709eafcc345ba2636565295c198a9cfbf75fa5e3e00b06" +checksum = "80792593675e051cf94a4b111980da2ba60d4a83e43e0048c5693baab3977045" dependencies = [ "color_quant", "weezl", @@ -1151,11 +1240,11 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.13" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" +checksum = "5be7b54589b581f624f566bf5d8eb2bab1db736c51528720b6bd36b96b55924d" dependencies = [ - "bytes 1.1.0", + "bytes 1.4.0", "fnv", "futures-core", "futures-sink", @@ -1174,6 +1263,15 @@ version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +[[package]] +name = "half" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b4af3693f1b705df946e9fe5631932443781d0aabb423b62fcd4d73f6d2fd0" +dependencies = [ + "crunchy", +] + [[package]] name = "hashbrown" version = "0.11.2" @@ -1200,18 +1298,18 @@ dependencies = [ [[package]] name = "headers" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cff78e5788be1e0ab65b04d306b2ed5092c815ec97ec70f4ebd5aee158aa55d" +checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584" dependencies = [ - "base64 0.13.0", + "base64 0.13.1", "bitflags", - "bytes 1.1.0", + "bytes 1.4.0", "headers-core", "http", "httpdate", "mime", - "sha-1", + "sha1", ] [[package]] @@ -1234,9 +1332,9 @@ dependencies = [ [[package]] name = "heck" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" dependencies = [ "unicode-segmentation", ] @@ -1250,6 +1348,21 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + [[package]] name = "hex" version = "0.4.3" @@ -1258,13 +1371,13 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "http" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" dependencies = [ - "bytes 1.1.0", + "bytes 1.4.0", "fnv", - "itoa 1.0.2", + "itoa", ] [[package]] @@ -1273,16 +1386,22 @@ version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ - "bytes 1.1.0", + "bytes 1.4.0", "http", "pin-project-lite", ] +[[package]] +name = "http-range-header" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" + [[package]] name = "httparse" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" @@ -1292,11 +1411,11 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "hyper" -version = "0.14.20" +version = "0.14.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac" +checksum = "cc5e554ff619822309ffd57d8734d77cd5ce6238bc956f037ea06c58238c9899" dependencies = [ - "bytes 1.1.0", + "bytes 1.4.0", "futures-channel", "futures-core", "futures-util", @@ -1305,7 +1424,7 @@ dependencies = [ "http-body", "httparse", "httpdate", - "itoa 1.0.2", + "itoa", "pin-project-lite", "socket2", "tokio", @@ -1316,13 +1435,13 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.23.0" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac" +checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" dependencies = [ "http", "hyper", - "rustls 0.20.6", + "rustls 0.20.8", "tokio", "tokio-rustls 0.23.4", ] @@ -1353,20 +1472,19 @@ dependencies = [ [[package]] name = "idna" -version = "0.2.3" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" dependencies = [ - "matches", "unicode-bidi", "unicode-normalization", ] [[package]] name = "image" -version = "0.24.3" +version = "0.24.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e30ca2ecf7666107ff827a8e481de6a132a9b687ed3bb20bb1c144a36c00964" +checksum = "527909aa81e20ac3a44803521443a765550f09b5130c2c2fa1ea59c2f8f50a3a" dependencies = [ "bytemuck", "byteorder", @@ -1377,15 +1495,15 @@ dependencies = [ "num-rational", "num-traits", "png", - "scoped_threadpool", + "qoi", "tiff", ] [[package]] name = "indexmap" -version = "1.9.1" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", @@ -1420,56 +1538,61 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "io-lifetimes" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" +dependencies = [ + "hermit-abi 0.3.1", + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "ipnet" -version = "2.5.0" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" +checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" [[package]] name = "itertools" -version = "0.10.3" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] [[package]] name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - -[[package]] -name = "itoa" -version = "1.0.2" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "jobserver" -version = "0.1.24" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" +checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" dependencies = [ "libc", ] [[package]] name = "jpeg-decoder" -version = "0.2.6" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9478aa10f73e7528198d75109c8be5cd7d15fb530238040148d5f9a22d4c5b3b" +checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e" dependencies = [ "rayon", ] [[package]] name = "js-sys" -version = "0.3.58" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" dependencies = [ "wasm-bindgen", ] @@ -1544,11 +1667,17 @@ dependencies = [ "cc", ] +[[package]] +name = "linux-raw-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" + [[package]] name = "lock_api" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f80bf5aacaf25cbfc8210d1cfb718f2bf3b11c4c54e5afe36c236853a8ec390" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" dependencies = [ "autocfg", "scopeguard", @@ -1582,10 +1711,10 @@ dependencies = [ ] [[package]] -name = "matches" -version = "0.1.9" +name = "matchit" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" +checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" [[package]] name = "memchr" @@ -1602,11 +1731,20 @@ dependencies = [ "autocfg", ] +[[package]] +name = "memoffset" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg", +] + [[package]] name = "mime" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "mime_guess" @@ -1626,23 +1764,23 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.5.3" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" +checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.36.1", + "windows-sys 0.45.0", ] [[package]] @@ -1659,21 +1797,17 @@ dependencies = [ ] [[package]] -name = "multipart" -version = "0.18.0" +name = "multiparty" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00dec633863867f29cb39df64a397cdf4a6354708ddd7759f70c7fb51c5f9182" +checksum = "ed1ec6589a6d4a1e0b33b4c0a3f6ee96dfba88ebdb3da51403fd7cf0a24a4b04" dependencies = [ - "buf_redux", + "bytes 1.4.0", + "futures-core", "httparse", - "log", - "mime", - "mime_guess", - "quick-error", - "rand", - "safemem", - "tempfile", - "twoway", + "memchr", + "pin-project-lite", + "try-lock", ] [[package]] @@ -1708,7 +1842,7 @@ dependencies = [ "tracing", "uuid 0.8.2", "winapi", - "xtra 0.5.2", + "xtra", "xtra_proc", ] @@ -1726,15 +1860,15 @@ dependencies = [ [[package]] name = "nix" -version = "0.23.1" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" +checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c" dependencies = [ "bitflags", "cc", "cfg-if", "libc", - "memoffset", + "memoffset 0.6.5", ] [[package]] @@ -1745,9 +1879,9 @@ checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" [[package]] name = "nom" -version = "7.1.1" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", @@ -1761,9 +1895,9 @@ checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21" [[package]] name = "notify" -version = "5.0.0" +version = "5.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2c66da08abae1c024c01d635253e402341b4060a12e99b31c7594063bf490a" +checksum = "58ea850aa68a06e48fdb069c0ec44d0d64c8dbffa49bf3b6f7f0a901fdea1ba9" dependencies = [ "bitflags", "crossbeam-channel", @@ -1774,7 +1908,7 @@ dependencies = [ "libc", "mio", "walkdir", - "winapi", + "windows-sys 0.42.0", ] [[package]] @@ -1786,6 +1920,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-integer" version = "0.1.45" @@ -1819,28 +1963,19 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "num_threads" -version = "0.1.6" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ + "hermit-abi 0.2.6", "libc", ] [[package]] name = "once_cell" -version = "1.14.0" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "oorandom" @@ -1854,6 +1989,12 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "parking_lot" version = "0.11.2" @@ -1862,7 +2003,7 @@ checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", - "parking_lot_core 0.8.5", + "parking_lot_core 0.8.6", ] [[package]] @@ -1872,66 +2013,66 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.3", + "parking_lot_core 0.9.7", ] [[package]] name = "parking_lot_core" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" dependencies = [ "cfg-if", "instant", "libc", - "redox_syscall", + "redox_syscall 0.2.16", "smallvec", "winapi", ] [[package]] name = "parking_lot_core" -version = "0.9.3" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.2.16", "smallvec", - "windows-sys 0.36.1", + "windows-sys 0.45.0", ] [[package]] name = "paste" -version = "1.0.7" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc" +checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" [[package]] name = "percent-encoding" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pin-project" -version = "1.0.10" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e" +checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.10" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb" +checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" dependencies = [ "proc-macro2", "quote", - "syn 1.0.98", + "syn 1.0.109", ] [[package]] @@ -1948,15 +2089,15 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" [[package]] name = "plotters" -version = "0.3.2" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9428003b84df1496fb9d6eeee9c5f8145cb41ca375eb0dad204328888832811f" +checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97" dependencies = [ "num-traits", "plotters-backend", @@ -1973,18 +2114,18 @@ checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" [[package]] name = "plotters-svg" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0918736323d1baff32ee0eade54984f6f201ad7e97d5cfb5d6ab4a358529615" +checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f" dependencies = [ "plotters-backend", ] [[package]] name = "png" -version = "0.17.6" +version = "0.17.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f0e7f4c94ec26ff209cee506314212639d6c91b80afb82984819fafce9df01c" +checksum = "5d708eaf860a19b19ce538740d2b4bdeeb8337fa53f7738455e706623ad5c638" dependencies = [ "bitflags", "crc32fast", @@ -2012,9 +2153,9 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro-error" @@ -2025,7 +2166,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn 1.0.98", + "syn 1.0.109", "version_check", ] @@ -2058,11 +2199,20 @@ dependencies = [ "cfg-if", "darwin-libproc", "mach", - "nix 0.23.1", + "nix 0.23.2", "once_cell", "thiserror", ] +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + [[package]] name = "quanta" version = "0.9.3" @@ -2079,12 +2229,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - [[package]] name = "quote" version = "1.0.26" @@ -2117,39 +2261,37 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", ] [[package]] name = "raw-cpuid" -version = "10.6.0" +version = "10.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6823ea29436221176fe662da99998ad3b4db2c7f31e7b6f5fe43adccd6320bb" +checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332" dependencies = [ "bitflags", ] [[package]] name = "rayon" -version = "1.5.3" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" dependencies = [ - "autocfg", - "crossbeam-deque", "either", "rayon-core", ] [[package]] name = "rayon-core" -version = "1.9.3" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -2159,18 +2301,27 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.13" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.5.6" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" +checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" dependencies = [ "aho-corasick", "memchr", @@ -2188,18 +2339,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.26" +version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" - -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "reqwest" @@ -2209,7 +2351,7 @@ checksum = "27b71749df584b7f4cac2c426c127a7c785a5106cc98f7a8feb044115f0fa254" dependencies = [ "async-compression", "base64 0.21.0", - "bytes 1.1.0", + "bytes 1.4.0", "encoding_rs", "futures-core", "futures-util", @@ -2225,8 +2367,8 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls 0.20.6", - "rustls-pemfile 1.0.0", + "rustls 0.20.8", + "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", @@ -2238,7 +2380,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 0.22.3", + "webpki-roots 0.22.6", "winreg", ] @@ -2306,7 +2448,7 @@ dependencies = [ "proc-macro2", "quote", "rust-embed-utils", - "syn 1.0.98", + "syn 1.0.109", "walkdir", ] @@ -2320,12 +2462,17 @@ dependencies = [ ] [[package]] -name = "rustc_version" -version = "0.4.0" +name = "rustix" +version = "0.37.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "2aae838e49b3d63e9274e1c01833cc8139d3fec468c3b84688c628f44b1ae11d" dependencies = [ - "semver", + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.45.0", ] [[package]] @@ -2334,7 +2481,7 @@ version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" dependencies = [ - "base64 0.13.0", + "base64 0.13.1", "log", "ring", "sct 0.6.1", @@ -2343,9 +2490,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.20.6" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" dependencies = [ "log", "ring", @@ -2355,27 +2502,18 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9" -dependencies = [ - "base64 0.13.0", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7522c9de787ff061458fe9a829dc790a3f5b22dc571694fc5883f448b94d9a9" +checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" dependencies = [ - "base64 0.13.0", + "base64 0.21.0", ] [[package]] name = "rustversion" -version = "1.0.7" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0a5f7c728f5d284929a1cccb5bc19884422bfe6ef4d6c409da2c41838983fcf" +checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" [[package]] name = "rusty_vainfo" @@ -2388,15 +2526,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" - -[[package]] -name = "safemem" -version = "0.3.3" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" [[package]] name = "same-file" @@ -2409,15 +2541,9 @@ dependencies = [ [[package]] name = "scoped-tls" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" - -[[package]] -name = "scoped_threadpool" -version = "0.1.9" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" [[package]] name = "scopeguard" @@ -2451,12 +2577,6 @@ dependencies = [ "untrusted", ] -[[package]] -name = "semver" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1" - [[package]] name = "serde" version = "1.0.159" @@ -2472,7 +2592,7 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" dependencies = [ - "half", + "half 1.8.2", "serde", ] @@ -2493,11 +2613,20 @@ version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" dependencies = [ - "itoa 1.0.2", + "itoa", "ryu", "serde", ] +[[package]] +name = "serde_path_to_error" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7f05c1d5476066defcdfacce1f52fc3cae3af1d3089727100c02ae92e5abbe0" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -2505,7 +2634,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa 1.0.2", + "itoa", "ryu", "serde", ] @@ -2531,14 +2660,14 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 1.0.98", + "syn 1.0.109", ] [[package]] -name = "sha-1" -version = "0.10.0" +name = "sha1" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" dependencies = [ "cfg-if", "cpufeatures", @@ -2547,9 +2676,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.2" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" dependencies = [ "cfg-if", "cpufeatures", @@ -2567,24 +2696,33 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" dependencies = [ "libc", ] +[[package]] +name = "simd-adler32" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "238abfbb77c1915110ad968465608b68e869e0772622c9656714e73e5a1a522f" + [[package]] name = "slab" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +dependencies = [ + "autocfg", +] [[package]] name = "smallvec" -version = "1.8.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc88c725d61fc6c3132893370cac4a0200e3fedf5da8331c570664b1987f5ca2" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "socket2" @@ -2604,9 +2742,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "spin" -version = "0.9.3" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c530c2b0d0bf8b69304b39fe2001993e267461948b890cd037d8ad4293fa1a0d" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" dependencies = [ "lock_api", ] @@ -2642,7 +2780,7 @@ dependencies = [ "atoi", "bitflags", "byteorder", - "bytes 1.1.0", + "bytes 1.4.0", "crc", "crossbeam-queue", "either", @@ -2656,7 +2794,7 @@ dependencies = [ "hashlink", "hex", "indexmap", - "itoa 1.0.2", + "itoa", "libc", "libsqlite3-sys", "log", @@ -2685,14 +2823,14 @@ checksum = "bc0fba2b0cae21fc00fe6046f8baa4c7fcb49e379f0f592b04696607f69ed2e1" dependencies = [ "dotenv", "either", - "heck 0.4.0", + "heck 0.4.1", "once_cell", "proc-macro2", "quote", "sha2", "sqlx-core", "sqlx-rt", - "syn 1.0.98", + "syn 1.0.109", "url", ] @@ -2744,7 +2882,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 1.0.98", + "syn 1.0.109", ] [[package]] @@ -2755,9 +2893,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.98" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", @@ -2775,6 +2913,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "synstructure" version = "0.12.6" @@ -2783,22 +2927,21 @@ checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ "proc-macro2", "quote", - "syn 1.0.98", + "syn 1.0.109", "unicode-xid", ] [[package]] name = "tempfile" -version = "3.3.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" dependencies = [ "cfg-if", "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi", + "redox_syscall 0.3.5", + "rustix", + "windows-sys 0.45.0", ] [[package]] @@ -2841,27 +2984,19 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.4" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ + "cfg-if", "once_cell", ] -[[package]] -name = "threadpool" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" -dependencies = [ - "num_cpus", -] - [[package]] name = "tiff" -version = "0.7.3" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7259662e32d1e219321eb309d5f9d898b779769d81b76e762c07c8e5d38fcb65" +checksum = "7449334f9ff2baf290d55d73983a7d6fa15e01198faef72af07e2a8db851e471" dependencies = [ "flate2", "jpeg-decoder", @@ -2870,9 +3005,9 @@ dependencies = [ [[package]] name = "time" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" dependencies = [ "libc", "wasi 0.10.0+wasi-snapshot-preview1", @@ -2881,13 +3016,29 @@ dependencies = [ [[package]] name = "time" -version = "0.3.11" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217" +checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" dependencies = [ - "itoa 1.0.2", - "libc", - "num_threads", + "itoa", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" + +[[package]] +name = "time-macros" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36" +dependencies = [ + "time-core", ] [[package]] @@ -2911,9 +3062,9 @@ dependencies = [ [[package]] name = "tinyvec_macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" @@ -2922,7 +3073,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001" dependencies = [ "autocfg", - "bytes 1.1.0", + "bytes 1.4.0", "libc", "mio", "num_cpus", @@ -2963,16 +3114,16 @@ version = "0.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" dependencies = [ - "rustls 0.20.6", + "rustls 0.20.8", "tokio", "webpki 0.22.0", ] [[package]] name = "tokio-stream" -version = "0.1.9" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df54d54117d6fdc4e4fea40fe1e4e566b3505700e148a6827e59b34b0d2600d9" +checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313" dependencies = [ "futures-core", "pin-project-lite", @@ -2981,9 +3132,9 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.17.2" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f714dd15bead90401d77e04243611caec13726c2408afd5b31901dfcdcb3b181" +checksum = "54319c93411147bced34cb5609a80e0a8e44c5999c93903a81cd866630ec0bfd" dependencies = [ "futures-util", "log", @@ -2993,11 +3144,11 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.3" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45" +checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" dependencies = [ - "bytes 1.1.0", + "bytes 1.4.0", "futures-core", "futures-sink", "pin-project-lite", @@ -3007,9 +3158,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ "serde", ] @@ -3024,6 +3175,47 @@ dependencies = [ "regex", ] +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d1d42a9b3f3ec46ba828e8d376aec14592ea199f70a06a548587ecd1c4ab658" +dependencies = [ + "bitflags", + "bytes 1.4.0", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "pin-project-lite", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + [[package]] name = "tower-service" version = "0.3.2" @@ -3050,7 +3242,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09d48f71a791638519505cefafe162606f706c25592e4bde4d97600c0195312e" dependencies = [ "crossbeam-channel", - "time 0.3.11", + "time 0.3.20", "tracing-subscriber", ] @@ -3062,7 +3254,7 @@ checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ "proc-macro2", "quote", - "syn 1.0.98", + "syn 1.0.109", ] [[package]] @@ -3098,13 +3290,13 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.11" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bc28f93baff38037f64e6f43d34cfa1605f27a49c34e8a04c5e78b0babf2596" +checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" dependencies = [ - "ansi_term", - "lazy_static", "matchers", + "nu-ansi-term", + "once_cell", "regex", "serde", "serde_json", @@ -3119,12 +3311,12 @@ dependencies = [ [[package]] name = "tracing-tree" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07e90b329c621ade432823988574e820212648aa40e7a2497777d58de0fb453" +checksum = "758e983ab7c54fee18403994507e7f212b9005e957ce7984996fac8d11facedb" dependencies = [ - "ansi_term", "atty", + "nu-ansi-term", "tracing-core", "tracing-log", "tracing-subscriber", @@ -3132,43 +3324,34 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "tungstenite" -version = "0.17.3" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e27992fd6a8c29ee7eef28fc78349aa244134e10ad447ce3b9f0ac0ed0fa4ce0" +checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788" dependencies = [ - "base64 0.13.0", + "base64 0.13.1", "byteorder", - "bytes 1.1.0", + "bytes 1.4.0", "http", "httparse", "log", "rand", - "sha-1", + "sha1", "thiserror", "url", "utf-8", ] -[[package]] -name = "twoway" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1" -dependencies = [ - "memchr", -] - [[package]] name = "typenum" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "unicase" @@ -3181,42 +3364,42 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.8" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.1" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" [[package]] name = "unicode-normalization" -version = "0.1.20" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dee68f85cab8cf68dec42158baf3a79a1cdc065a8b103025965d6ccb7f6cbd" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.9.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" [[package]] name = "unicode-width" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" [[package]] name = "unicode-xid" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "unicode_categories" @@ -3242,13 +3425,12 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.2.2" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" dependencies = [ "form_urlencoded", "idna", - "matches", "percent-encoding", ] @@ -3269,9 +3451,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.2.2" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c" +checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79" dependencies = [ "getrandom", ] @@ -3302,12 +3484,11 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "walkdir" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" dependencies = [ "same-file", - "winapi", "winapi-util", ] @@ -3323,11 +3504,11 @@ dependencies = [ [[package]] name = "warp" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed7b8be92646fc3d18b06147664ebc5f48d222686cb11a8755e561a735aacc6d" +checksum = "27e1a710288f0f91a98dd8a74f05b76a10768db245ce183edf64dc1afdc3016c" dependencies = [ - "bytes 1.1.0", + "bytes 1.4.0", "futures-channel", "futures-util", "headers", @@ -3336,10 +3517,10 @@ dependencies = [ "log", "mime", "mime_guess", - "multipart", + "multiparty", "percent-encoding", "pin-project", - "rustls-pemfile 0.2.1", + "rustls-pemfile", "scoped-tls", "serde", "serde_json", @@ -3367,9 +3548,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.81" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -3377,24 +3558,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.81" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" dependencies = [ "bumpalo", - "lazy_static", "log", + "once_cell", "proc-macro2", "quote", - "syn 1.0.98", + "syn 1.0.109", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.31" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de9a9cec1733468a8c657e57fa2413d2ae2c0129b95e87c5b72b8ace4d13f31f" +checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" dependencies = [ "cfg-if", "js-sys", @@ -3404,9 +3585,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.81" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3414,28 +3595,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.81" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", - "syn 1.0.98", + "syn 1.0.109", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.81" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" [[package]] name = "web-sys" -version = "0.3.58" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" dependencies = [ "js-sys", "wasm-bindgen", @@ -3472,9 +3653,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.22.3" +version = "0.22.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d8de8415c823c8abd270ad483c6feeac771fad964890779f9a8cb24fbbc1bf" +checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" dependencies = [ "webpki 0.22.0", ] @@ -3527,15 +3708,17 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.36.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ - "windows_aarch64_msvc 0.36.1", - "windows_i686_gnu 0.36.1", - "windows_i686_msvc 0.36.1", - "windows_x86_64_gnu 0.36.1", - "windows_x86_64_msvc 0.36.1", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] [[package]] @@ -3547,6 +3730,15 @@ dependencies = [ "windows-targets 0.42.2", ] +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -3589,12 +3781,6 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" -[[package]] -name = "windows_aarch64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" - [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -3607,12 +3793,6 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" -[[package]] -name = "windows_i686_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" - [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -3625,12 +3805,6 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" -[[package]] -name = "windows_i686_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" - [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -3643,12 +3817,6 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" -[[package]] -name = "windows_x86_64_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" - [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -3673,12 +3841,6 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" -[[package]] -name = "windows_x86_64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" - [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -3724,24 +3886,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "xtra" -version = "0.6.0" -source = "git+https://github.com/Restioson/xtra#12181eedc4da0fc8afd651b476e87ec9b1dd1fbc" -dependencies = [ - "async-trait", - "catty", - "event-listener", - "futures-core", - "futures-sink", - "futures-timer", - "futures-util", - "pin-project-lite", - "pollster", - "spin 0.9.3", - "tokio", -] - [[package]] name = "xtra_proc" version = "0.1.0" @@ -3750,7 +3894,7 @@ checksum = "0972940e244acf1715d05b50b6e937d2ca97db4247437e9d07c5eaf0d978ebb0" dependencies = [ "proc-macro2", "quote", - "syn 1.0.98", + "syn 1.0.109", ] [[package]] @@ -3764,5 +3908,14 @@ dependencies = [ "crc32fast", "flate2", "thiserror", - "time 0.1.44", + "time 0.1.45", +] + +[[package]] +name = "zune-inflate" +version = "0.2.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "440a08fd59c6442e4b846ea9b10386c38307eae728b216e1ab2c305d1c9daaf8" +dependencies = [ + "simd-adler32", ] diff --git a/Cargo.toml b/Cargo.toml index 2c42b1c1c..960ee03a4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,13 @@ [workspace] -members = ["dim", "dim-auth", "dim-database", "dim-events", "dim-extern-api"] +members = [ + "dim", + "dim-auth", + "dim-database", + "dim-events", + "dim-extern-api", + "dim-web", + "dim-utils" +] [workspace.package] version = "0.4.0-dev" diff --git a/dim-database/Cargo.toml b/dim-database/Cargo.toml index 0d37e97e8..bf4ebb571 100644 --- a/dim-database/Cargo.toml +++ b/dim-database/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dim-database" -build = "src/build.rs" +build = "build.rs" version.workspace = true authors.workspace = true edition.workspace = true @@ -32,4 +32,4 @@ tokio = { version = "1", default-features = false, features = ["rt", "macros"] } [build-dependencies] sqlx = { version = "0.5", features = ["runtime-tokio-rustls"] } tokio = "1.20.4" -dotenv = "0.15.0" +dotenv = "0.15.0" \ No newline at end of file diff --git a/dim-database/src/build.rs b/dim-database/build.rs similarity index 100% rename from dim-database/src/build.rs rename to dim-database/build.rs diff --git a/dim-database/src/lib.rs b/dim-database/src/lib.rs index 6e9cb5f7c..de99a5e49 100644 --- a/dim-database/src/lib.rs +++ b/dim-database/src/lib.rs @@ -1,4 +1,5 @@ // FIXME: We have a shim in dim/utils but we cant depend on dim because itd be a circular dep. +#![deny(warnings)] use crate::utils::ffpath; diff --git a/dim-events/src/lib.rs b/dim-events/src/lib.rs index ee06a4bbd..05a1b3538 100644 --- a/dim-events/src/lib.rs +++ b/dim-events/src/lib.rs @@ -1,3 +1,5 @@ +#![deny(warnings)] + use serde::Serialize; use std::collections::HashMap; diff --git a/dim-utils/Cargo.toml b/dim-utils/Cargo.toml new file mode 100644 index 000000000..a8fac9a14 --- /dev/null +++ b/dim-utils/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "dim-utils" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +dia-i18n = "0.10.0" diff --git a/dim-utils/src/lib.rs b/dim-utils/src/lib.rs new file mode 100644 index 000000000..a899f78b6 --- /dev/null +++ b/dim-utils/src/lib.rs @@ -0,0 +1,519 @@ +/// Source: https://github.com/seanmonstar/warp/issues/619 +/// Takes a list of handler expressions and `or`s them together +/// in a balanced tree. That is, instead of `a.or(b).or(c).or(d)`, +/// it produces `(a.or(b)).or(c.or(d))`, thus nesting the types +/// less deeply, which provides improvements in compile time. +/// +/// It also applies `::warp::Filter::boxed` to each handler expression +/// when in `debug_assertions` mode, improving compile time further. +/// +// +// The basic list splitting algorithm here is based on this gist: +// https://gist.github.com/durka/9fc479de2555225a787f +// It uses a counter from which two items are removed each time, +// stopping when the counter reaches 0. At each step, one item +// is moved from the left to the right, and thus at the end, +// there will be the same number of items in each list. +// +// The flow is as follows: +// - If there is one handler expression, debug_box it and return. +// - If there is more than one handler expression: +// - First, copy the list into two: the one that will go into the +// right side of the `or`, and one that will serve as a counter. +// Recurse with these separated by semicolons, plus an empty `left` +// list before the first semicolon. +// - Then, as long as there are at least two items in the counter +// list, remove them and move the first item on the right side of +// the first semicolon (`head`) to the left side of the first semicolon. +// - Finally, when there are one or zero items left in the counter, +// move one last item to the left, make the call this macro on both the +// left and right sides, and `or` the two sides together. +// +// For example, balanced_or_tree!(a, b, c, d, e) would take the following steps: +// +// - balanced_or_tree!(a, b, c, d, e) +// - balanced_or_tree!(@internal ; a, b, c, d, e ; a, b, c, d, e) // initialise lists +// - balanced_or_tree!(@internal a ; b, c, d, e ; c, d, e) // move one elem; remove two +// - balanced_or_tree!(@internal a, b ; c, d, e ; e) // now only one elem in counter +// - balanced_or_tree!(a, b, c).or(balanced_or_tree(d, e)) // recurse on each sublist +#[macro_export] +macro_rules! balanced_or_tree { + // Base case: just a single expression, return it wrapped in `debug_boxed` + ($x:expr $(,)?) => { $x }; + // Multiple expressions: recurse with three lists: left, right and counter. + ($($x:expr),+ $(,)?) => { + balanced_or_tree!(@internal ; $($x),+; $($x),+) + // ^ left ^ right ^ counter + }; + // Counter 1 or 2; move one more item and recurse on each sublist, and or them together + (@internal $($left:expr),*; $head:expr, $($tail:expr),+; $a:expr $(,$b:expr)?) => { + (balanced_or_tree!($($left,)* $head)).or(balanced_or_tree!($($tail),+)) + }; + // Counter > 2; move one item from the right to the left and subtract two from the counter + (@internal $($left:expr),*; $head:expr, $($tail:expr),+; $a:expr, $b:expr, $($more:expr),+) => { + balanced_or_tree!(@internal $($left,)* $head; $($tail),+; $($more),+) + }; +} + +#[macro_export] +macro_rules! warp_try { + ($x:expr) => { + match $x { + Ok(x) => x, + Err(e) => return Ok(::warp::reply::Reply::into_response(e)), + } + }; +} + +#[macro_export] +macro_rules! warp_unwrap { + ($x:expr) => { + match $x { + Ok(x) => { + Result::<_, ::core::convert::Infallible>::Ok(::warp::reply::Reply::into_response(x)) + } + Err(e) => { + Result::<_, ::core::convert::Infallible>::Ok(::warp::reply::Reply::into_response(e)) + } + } + }; +} + +/// Construct a `serde_json::Value` from a JSON literal. +/// +/// ``` +/// # use serde_json::json; +/// # +/// let value = json!({ +/// "code": 200, +/// "success": true, +/// "payload": { +/// "features": [ +/// "serde", +/// "json" +/// ] +/// } +/// }); +/// ``` +/// +/// Variables or expressions can be interpolated into the JSON literal. Any type +/// interpolated into an array element or object value must implement Serde's +/// `Serialize` trait, while any type interpolated into a object key must +/// implement `Into`. If the `Serialize` implementation of the +/// interpolated type decides to fail, or if the interpolated type contains a +/// map with non-string keys, the `json!` macro will panic. +/// +/// ``` +/// # use serde_json::json; +/// # +/// let code = 200; +/// let features = vec!["serde", "json"]; +/// +/// let value = json!({ +/// "code": code, +/// "success": code == 200, +/// "payload": { +/// features[0]: features[1] +/// } +/// }); +/// ``` +/// +/// Trailing commas are allowed inside both arrays and objects. +/// +/// ``` +/// # use serde_json::json; +/// # +/// let value = json!([ +/// "notice", +/// "the", +/// "trailing", +/// "comma -->", +/// ]); +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! json { + // Hide distracting implementation details from the generated rustdoc. + ($($json:tt)+) => { + json_internal!($($json)+) + }; +} + +// Rocket relies on this because they export their own `json!` with a different +// doc comment than ours, and various Rust bugs prevent them from calling our +// `json!` from their `json!` so they call `json_internal!` directly. Check with +// @SergioBenitez before making breaking changes to this macro. +// +// Changes are fine as long as `json_internal!` does not call any new helper +// macros and can still be invoked as `json_internal!($($json)+)`. +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! json_internal { + ////////////////////////////////////////////////////////////////////////// + // TT muncher for parsing the inside of an array [...]. Produces a vec![...] + // of the elements. + // + // Must be invoked as: json_internal!(@array [] $($tt)*) + ////////////////////////////////////////////////////////////////////////// + + // Done with trailing comma. + (@array [$($elems:expr,)*]) => { + json_internal_vec![$($elems,)*] + }; + + // Done without trailing comma. + (@array [$($elems:expr),*]) => { + json_internal_vec![$($elems),*] + }; + + // Next element is `null`. + (@array [$($elems:expr,)*] null $($rest:tt)*) => { + json_internal!(@array [$($elems,)* json_internal!(null)] $($rest)*) + }; + + // Next element is `true`. + (@array [$($elems:expr,)*] true $($rest:tt)*) => { + json_internal!(@array [$($elems,)* json_internal!(true)] $($rest)*) + }; + + // Next element is `false`. + (@array [$($elems:expr,)*] false $($rest:tt)*) => { + json_internal!(@array [$($elems,)* json_internal!(false)] $($rest)*) + }; + + // Next element is an array. + (@array [$($elems:expr,)*] [$($array:tt)*] $($rest:tt)*) => { + json_internal!(@array [$($elems,)* json_internal!([$($array)*])] $($rest)*) + }; + + // Next element is a map. + (@array [$($elems:expr,)*] {$($map:tt)*} $($rest:tt)*) => { + json_internal!(@array [$($elems,)* json_internal!({$($map)*})] $($rest)*) + }; + + // Next element is an expression followed by comma. + (@array [$($elems:expr,)*] $next:expr, $($rest:tt)*) => { + json_internal!(@array [$($elems,)* json_internal!($next),] $($rest)*) + }; + + // Last element is an expression with no trailing comma. + (@array [$($elems:expr,)*] $last:expr) => { + json_internal!(@array [$($elems,)* json_internal!($last)]) + }; + + // Comma after the most recent element. + (@array [$($elems:expr),*] , $($rest:tt)*) => { + json_internal!(@array [$($elems,)*] $($rest)*) + }; + + // Unexpected token after most recent element. + (@array [$($elems:expr),*] $unexpected:tt $($rest:tt)*) => { + json_unexpected!($unexpected) + }; + + ////////////////////////////////////////////////////////////////////////// + // TT muncher for parsing the inside of an object {...}. Each entry is + // inserted into the given map variable. + // + // Must be invoked as: json_internal!(@object $map () ($($tt)*) ($($tt)*)) + // + // We require two copies of the input tokens so that we can match on one + // copy and trigger errors on the other copy. + ////////////////////////////////////////////////////////////////////////// + + // Done. + (@object $object:ident () () ()) => {}; + + // Insert the current entry followed by trailing comma. + (@object $object:ident [$($key:tt)+] ($value:expr) , $($rest:tt)*) => { + let _ = $object.insert(($($key)+).into(), $value); + json_internal!(@object $object () ($($rest)*) ($($rest)*)); + }; + + // Current entry followed by unexpected token. + (@object $object:ident [$($key:tt)+] ($value:expr) $unexpected:tt $($rest:tt)*) => { + json_unexpected!($unexpected); + }; + + // Insert the last entry without trailing comma. + (@object $object:ident [$($key:tt)+] ($value:expr)) => { + let _ = $object.insert(($($key)+).into(), $value); + }; + + // Next value is `null`. + (@object $object:ident ($($key:tt)+) (: null $($rest:tt)*) $copy:tt) => { + json_internal!(@object $object [$($key)+] (json_internal!(null)) $($rest)*); + }; + + // Next value is `true`. + (@object $object:ident ($($key:tt)+) (: true $($rest:tt)*) $copy:tt) => { + json_internal!(@object $object [$($key)+] (json_internal!(true)) $($rest)*); + }; + + // Next value is `false`. + (@object $object:ident ($($key:tt)+) (: false $($rest:tt)*) $copy:tt) => { + json_internal!(@object $object [$($key)+] (json_internal!(false)) $($rest)*); + }; + + // Next value is an array. + (@object $object:ident ($($key:tt)+) (: [$($array:tt)*] $($rest:tt)*) $copy:tt) => { + json_internal!(@object $object [$($key)+] (json_internal!([$($array)*])) $($rest)*); + }; + + // Next value is a map. + (@object $object:ident ($($key:tt)+) (: {$($map:tt)*} $($rest:tt)*) $copy:tt) => { + json_internal!(@object $object [$($key)+] (json_internal!({$($map)*})) $($rest)*); + }; + + // Next value is an expression followed by comma. + (@object $object:ident ($($key:tt)+) (: $value:expr , $($rest:tt)*) $copy:tt) => { + json_internal!(@object $object [$($key)+] (json_internal!($value)) , $($rest)*); + }; + + // Next value is an optional expression followed by comma. + (@object $object:ident ($($key:tt)+) (:? $value:expr , $($rest:tt)*) $copy:tt) => { + if let Some(x) = $value { + json_internal!(@object $object [$($key)+] (json_internal!($value)) , $($rest)*); + } else { + json_internal!(@object $object () ($($rest)*) ($($rest)*)); + } + }; + + // Next entry is a key with the spread operator and no value + (@object $object:ident ($(...$key:expr)+) (, $($rest:tt)*) $copy:tt) => { + if let Some(map) = ($($key)+).clone().as_object_mut() { + let _ = $object.append(map); + } + + json_internal!(@object $object () ($($rest)*) ($($rest)*)); + }; + + // Last entry is a key with the spread operator and no value. + (@object $object:ident ($(...$key:expr)+) () $copy:tt) => { + if let Some(map) = ($($key)+).clone().as_object_mut() { + let _ = $object.append(map); + } + }; + + // Next entry is a key with the optional spread operator and no value. + // This takes in a `Option` and will merge the value if its `Some`. + (@object $object:ident ($(..?$key:expr)+) (, $($rest:tt)*) $copy:tt) => { + if let Some(map) = ($($key)+).clone().as_mut().and_then(|x| x.as_object_mut()) { + let _ = $object.append(map); + } + + json_internal!(@object $object () ($($rest)*) ($($rest)*)); + }; + + // Last entry is a key with the optional spread operator and no value. + // This takes in a `Option` and will merge the value if its `Some`. + (@object $object:ident ($(..?$key:expr)+) () $copy:tt) => { + if let Some(map) = ($($key)+).clone().as_mut().and_then(|x| x.as_object_mut()) { + let _ = $object.append(map); + } + }; + + // Last value is an expression with no trailing comma. + (@object $object:ident ($($key:tt)+) (: $value:expr) $copy:tt) => { + json_internal!(@object $object [$($key)+] (json_internal!($value))); + }; + + // Missing value for last entry. Trigger a reasonable error message. + (@object $object:ident ($($key:tt)+) (:) $copy:tt) => { + // "unexpected end of macro invocation" + json_internal!(); + }; + + // Missing colon and value for last entry. Trigger a reasonable error + // message. + (@object $object:ident ($($key:tt)+) () $copy:tt) => { + // "unexpected end of macro invocation" + json_internal!(); + }; + + // Misplaced colon. Trigger a reasonable error message. + (@object $object:ident () (: $($rest:tt)*) ($colon:tt $($copy:tt)*)) => { + // Takes no arguments so "no rules expected the token `:`". + json_unexpected!($colon); + }; + + // Found a comma inside a key. Trigger a reasonable error message. + (@object $object:ident ($($key:tt)*) (, $($rest:tt)*) ($comma:tt $($copy:tt)*)) => { + // Takes no arguments so "no rules expected the token `,`". + json_unexpected!($comma); + }; + + // Key is fully parenthesized. This avoids clippy double_parens false + // positives because the parenthesization may be necessary here. + (@object $object:ident () (($key:expr) : $($rest:tt)*) $copy:tt) => { + json_internal!(@object $object ($key) (: $($rest)*) (: $($rest)*)); + }; + + // Refuse to absorb colon token into key expression. + (@object $object:ident ($($key:tt)*) (: $($unexpected:tt)+) $copy:tt) => { + json_expect_expr_comma!($($unexpected)+); + }; + + // Munch a token into the current key. + (@object $object:ident ($($key:tt)*) ($tt:tt $($rest:tt)*) $copy:tt) => { + json_internal!(@object $object ($($key)* $tt) ($($rest)*) ($($rest)*)); + }; + + ////////////////////////////////////////////////////////////////////////// + // The main implementation. + // + // Must be invoked as: json_internal!($($json)+) + ////////////////////////////////////////////////////////////////////////// + + (null) => { + ::serde_json::Value::Null + }; + + (true) => { + ::serde_json::Value::Bool(true) + }; + + (false) => { + ::serde_json::Value::Bool(false) + }; + + ([]) => { + ::serde_json::Value::Array(json_internal_vec![]) + }; + + ([ $($tt:tt)+ ]) => { + ::serde_json::Value::Array(json_internal!(@array [] $($tt)+)) + }; + + ({}) => { + ::serde_json::Value::Object(::serde_json::Map::new()) + }; + + ({ $($tt:tt)+ }) => { + ::serde_json::Value::Object({ + let mut object = ::serde_json::Map::new(); + json_internal!(@object object () ($($tt)+) ($($tt)+)); + object + }) + }; + + // Any Serialize type: numbers, strings, struct literals, variables etc. + // Must be below every other rule. + ($other:expr) => { + ::serde_json::to_value(&$other).unwrap() + }; +} + +// The json_internal macro above cannot invoke vec directly because it uses +// local_inner_macros. A vec invocation there would resolve to $crate::vec. +// Instead invoke vec here outside of local_inner_macros. +#[macro_export] +#[doc(hidden)] +macro_rules! json_internal_vec { + ($($content:tt)*) => { + vec![$($content)*] + }; +} + +#[macro_export] +#[doc(hidden)] +macro_rules! json_unexpected { + () => {}; +} + +#[macro_export] +#[doc(hidden)] +macro_rules! json_expect_expr_comma { + ($e:expr , $($tt:tt)*) => {}; +} + +pub fn quality_to_label(q_bitrate: u64, q_height: u64, brate: Option) -> String { + let bandwidth_ident = if brate.unwrap_or(q_bitrate) > 1_000_000 { + "MB" + } else { + "KB" + }; + + let bandwidth_norm = if brate.unwrap_or(q_bitrate) > 1_000_000 { + q_bitrate / 1_000_000 + } else { + q_bitrate / 1_000 + }; + + format!("{}p@{}{}", q_height, bandwidth_norm, bandwidth_ident) +} + +pub fn ts_to_xml(t: u64) -> String { + let h = t / 3600; + let m = t % 3600 / 60; + let s = t % 3600 % 60; + + let mut tag = "PT".to_string(); + + if h != 0 { + tag = format!("{}{}H", tag, h); + } + + if m != 0 { + tag = format!("{}{}M", tag, m); + } + + if s != 0 { + tag = format!("{}{}S", tag, s); + } + + tag +} + +pub fn secs_to_pretty(t: u64) -> String { + let h = t / 3600; + let m = t % 3600 / 60; + + let mut tag = String::new(); + + if h != 0 { + tag = format!("{h}hr"); + } + + if m != 0 { + tag = format!("{tag} {m}m"); + } + + tag +} + +#[cfg(not(debug_assertions))] +pub fn ffpath(bin: impl AsRef) -> String { + let mut path = std::env::current_exe().expect("Failed to grab path to the `dim` binary."); + path.pop(); // remove the dim bin to get the dir of `dim` + path.push(bin.as_ref()); + + path.to_string_lossy().to_string() +} + +#[cfg(debug_assertions)] +pub fn ffpath(bin: impl AsRef) -> String { + bin.as_ref().to_string() +} + +pub fn codec_pretty(codec: &str) -> String { + match codec { + "h264" => "H.264".into(), + x => x.to_uppercase(), + } +} + +pub fn channels_pretty(ch: i64) -> String { + match ch { + 2 | 3 => "2.1".into(), + 6 => "5.1".into(), + 8 => "7.1".into(), + _ => ch.to_string(), + } +} + +pub fn lang_from_iso639(tag: &str) -> Option<&'static str> { + dia_i18n::iso_639::LANG_CODES + .iter() + .find(|x| x.v2b() == tag) + .map(|x| x.name()) +} diff --git a/dim-web/Cargo.toml b/dim-web/Cargo.toml new file mode 100644 index 000000000..e321142e4 --- /dev/null +++ b/dim-web/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "dim-web" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +dim-database = { path = "../dim-database" } +dim-utils = { path = "../dim-utils" } +dim-events = { path = "../dim-events" } + +nightfall = { git = "https://github.com/Dusk-Labs/nightfall", tag = "0.3.12-rc4", default-features = false, features = ["cuda", "ssa_transmux"] } + +axum = { version = "0.6.12", features = ["ws", "http2"] } +chrono = { version = "0.4.19", features = ["serde"] } +displaydoc = "0.2.3" +futures = "0.3.14" +fuzzy-matcher = "0.3.7" +http = "^0.2.3" +once_cell = "1.8.0" +percent-encoding = "2.1.0" +rust-embed = "^5.9.0" +serde = { version = "^1.0.125", default-features = false, features = ["derive", "std", "rc"] } +serde_derive = "^1.0.125" +serde_json = "^1.0.64" +sqlx = { version = "0.5", features = ["runtime-tokio-rustls"] } +thiserror = "1.0.30" +tokio = { version = "1.27.0", features = ["full"] } +tracing = "0.1.32" +tracing-appender = "0.2.0" +tracing-subscriber = { version = "^0.3.10", features = ["fmt", "env-filter", "json"] } +tracing-tree = "0.2.0" +uuid = { version = "1.2.2", features = ["v4"] } +warp = { version = "0.3.3", features = ["tls", "tokio-rustls"] } +hyper = "0.14.25" +tower = { version = "0.4.13", features = ["tokio", "util"] } diff --git a/dim-web/build.rs b/dim-web/build.rs new file mode 100644 index 000000000..3198dfd2a --- /dev/null +++ b/dim-web/build.rs @@ -0,0 +1,11 @@ +use std::env; +use std::error::Error; + +fn main() -> Result<(), Box> { + let out_dir = env::var("CARGO_TARGET_DIR").unwrap(); + + let db_file = format!("{out_dir}/dim_dev.db"); + println!("cargo:rustc-env=DATABASE_URL=sqlite://{db_file}"); + + Ok(()) +} diff --git a/dim-web/src/lib.rs b/dim-web/src/lib.rs new file mode 100644 index 000000000..68275a6c1 --- /dev/null +++ b/dim-web/src/lib.rs @@ -0,0 +1,15 @@ +#![deny(warnings)] + +use std::net::SocketAddr; + +pub mod routes; +pub mod tree; + +pub use axum; + +#[inline] +pub async fn serve(addr: &SocketAddr, router: axum::Router) -> Result<(), hyper::Error> { + axum::Server::bind(addr) + .serve(router.into_make_service_with_connect_info::()) + .await +} diff --git a/dim-web/src/routes/mod.rs b/dim-web/src/routes/mod.rs new file mode 100644 index 000000000..6eba44d95 --- /dev/null +++ b/dim-web/src/routes/mod.rs @@ -0,0 +1 @@ +pub mod websocket; diff --git a/dim-web/src/routes/websocket.rs b/dim-web/src/routes/websocket.rs new file mode 100644 index 000000000..d97b4781e --- /dev/null +++ b/dim-web/src/routes/websocket.rs @@ -0,0 +1,261 @@ +use std::collections::HashMap; +use std::hash::Hash; +use std::net::SocketAddr; +use std::pin::Pin; + +use tokio::sync::mpsc::unbounded_channel; +use tokio::sync::mpsc::UnboundedReceiver; +use tokio::sync::mpsc::UnboundedSender; + +use futures::prelude::*; + +pub enum CtrlEvent +where + A: Hash + Eq, +{ + Track { + addr: A, + sink: Pin + Send>>, + auth: Box, + }, + + Forget { + addr: A, + }, + + SendTo { + addr: A, + message: M, + }, + + SendAll(M), +} + +pub trait IntoCtrlEvent: Sync + Send + Clone + 'static +where + A: Hash + Eq, +{ + fn into_ctrl_event(self) -> CtrlEvent; +} + +impl IntoCtrlEvent for String +where + A: Hash + Eq, +{ + fn into_ctrl_event(self) -> CtrlEvent { + CtrlEvent::SendAll(self) + } +} + +async fn ctrl_event_processor(mut rx: UnboundedReceiver>) +where + A: Hash + Eq + Clone, + T: ToOwned + Send, +{ + let mut peers = HashMap::new(); + let mut discard = vec![]; + + while let Some(ev) = rx.recv().await { + for addr in &discard { + let _ = peers.remove(addr); + } + + discard.clear(); + + match ev { + CtrlEvent::Track { addr, sink, auth } => { + peers.insert(addr, (sink, auth)); + } + + CtrlEvent::Forget { ref addr } => { + peers.remove(addr); + } + + CtrlEvent::SendAll(body) => { + for (addr, (sink, _)) in peers.iter_mut() { + let result = sink.send(WsMessage::Text(body.to_owned())).await; + + if result.is_err() { + let _ = sink.close().await; + discard.push(addr.clone()); + } + } + } + + CtrlEvent::SendTo { addr, message } => { + if let Some((sink, _)) = peers.get_mut(&addr) { + let result = sink.send(WsMessage::Text(message.to_owned())).await; + + if result.is_err() { + let _ = sink.close().await; + discard.push(addr.clone()); + } + } + } + }; + } +} + +#[derive(serde::Deserialize)] +#[serde(rename_all = "snake_case")] +#[serde(tag = "type")] +pub enum ClientActions { + Authenticate { token: String }, +} + +pub type WsMessage = axum::extract::ws::Message; + +#[derive(Debug)] +pub struct WsMessageError; + +impl From for WsMessageError { + fn from(_: warp::Error) -> Self { + Self + } +} + +impl From for WsMessageError { + fn from(_: axum::Error) -> Self { + Self + } +} + +pub async fn handle_websocket_session( + sink: impl Sink + Send + 'static, + stream: impl Stream, + remote_address: Option, + conn: dim_database::DbConnection, + socket_tx: SocketTx, +) { + let addr = match remote_address { + Some(addr) => addr, + None => return, + }; + + tokio::pin!(stream); + + 'auth_loop: while let Some(message) = stream.next().await { + if let WsMessage::Text(st) = message { + if let Ok(ClientActions::Authenticate { token }) = serde_json::from_str(&st) { + if let Ok(token_data) = dim_database::user::Login::verify_cookie(token) { + if let Ok(mut sql_tx) = conn.read().begin().await { + if let Ok(u) = + dim_database::user::User::get_by_id(&mut sql_tx, token_data).await + { + let _ = socket_tx.send(CtrlEvent::Track { + addr, + sink: Box::pin(sink), + auth: Box::new(u), + }); + + let _ = socket_tx.send(CtrlEvent::SendTo { + addr, + message: dim_events::Message { + id: -1, + event_type: dim_events::PushEventType::EventAuthOk, + } + .to_string(), + }); + + break 'auth_loop; + } + } + } + } + + let _ = socket_tx.send(CtrlEvent::SendTo { + addr, + message: dim_events::Message { + id: -1, + event_type: dim_events::PushEventType::EventAuthErr, + } + .to_string(), + }); + } + } + + loop { + tokio::select! { + biased; + _ = tokio::signal::ctrl_c() => { + break; + } + + None = stream.next() => { + let _ = socket_tx.send(CtrlEvent::Forget { addr }); + break; + } + } + } +} + +pub fn from_warp_message(inner: warp::ws::Message) -> Result { + if inner.is_binary() { + Ok(WsMessage::Binary(inner.as_bytes().into())) + } else if inner.is_text() { + Ok(WsMessage::Text( + String::from_utf8_lossy(inner.as_bytes()).to_string(), + )) + } else if inner.is_ping() { + Ok(WsMessage::Ping(inner.as_bytes().into())) + } else if inner.is_pong() { + Ok(WsMessage::Pong(inner.as_bytes().into())) + } else if inner.is_close() { + let fr = inner + .close_frame() + .map(|(code, reason)| axum::extract::ws::CloseFrame { + code: axum::extract::ws::CloseCode::from(code), + reason: std::borrow::Cow::Owned(reason.to_owned()), + }); + Ok(WsMessage::Close(fr)) + } else { + Err(()) + } +} + +pub fn from_tungstenite_message(inner: WsMessage) -> Result { + use axum::extract::ws::Message; + use warp::ws; + + let m = match inner { + Message::Text(st) => ws::Message::text(st), + Message::Binary(bin) => ws::Message::binary(bin), + Message::Ping(v) => ws::Message::ping(v), + Message::Pong(v) => ws::Message::pong(v), + Message::Close(Some(frame)) => ws::Message::close_with(frame.code, frame.reason), + Message::Close(None) => ws::Message::close(), + }; + + Ok(m) +} + +pub type SocketTx = UnboundedSender>; + +pub fn event_repeater( + source: S, +) -> ( + impl Future + Send + 'static, + impl Future + Send + 'static, + SocketTx, +) +where + S: Stream + Send + 'static, + T: IntoCtrlEvent + Send, + A: Hash + Eq + Clone + Send + Sync + 'static, + M: ToOwned + Send + Sync + 'static, +{ + let (tx, rx) = unbounded_channel::>(); + + let event_prcoessor = ctrl_event_processor::(rx); + let stream_forward_tx = tx.clone(); + let stream_forward = async move { + tokio::pin!(source); + while let Some(t) = source.next().await { + if stream_forward_tx.send(t.into_ctrl_event()).is_err() { + break; + }; + } + }; + + (stream_forward, event_prcoessor, tx) +} diff --git a/dim-web/src/tree.rs b/dim-web/src/tree.rs new file mode 100644 index 000000000..512b0567e --- /dev/null +++ b/dim-web/src/tree.rs @@ -0,0 +1,269 @@ +/// Module contains a data structure that represents a file-tree. +use serde::Serialize; +use std::fmt::Debug; + +#[derive(Debug, PartialEq, Eq, Serialize)] +#[serde(tag = "type")] +#[serde(rename_all = "lowercase")] +/// Represents a entry which can either be a directory with more entries, or a singular file. +pub enum Entry { + Directory { + folder: String, + files: Vec>, + }, + File(T), +} + +impl Entry { + pub fn new() -> Self { + Self::Directory { + folder: "/".into(), + files: vec![], + } + } + + /// Helper which can turn a collection of values into a tree. The caller must supply a closure + /// which extracts a key from a value. + pub fn build_with( + values: impl IntoIterator, + k: impl Fn(&U) -> Vec, + v: impl Fn(&str, U) -> T, + ) -> Self { + let mut entry = Self::new(); + + for value in values.into_iter() { + let mut components = k(&value); + + let filename = match components.pop() { + Some(x) => x, + None => continue, + }; + + entry.insert(components.iter(), v(filename.as_ref(), value)); + } + + // remove root-directories with only one folder inside. + entry.compress(); + + entry + } + + /// Method inserts a value in the current entry by recursively scanning it based on the keys + /// supplied. The supplied value will be associated with the last key in the collection of keys + /// supplied. + pub fn insert<'a>(&mut self, mut keys: impl Iterator>, value: T) { + if self.is_file() { + return; + } + + // NOTE: If the key is None, we've reached the max depth, so we can safely insert the + // record into our current self. + let key = match keys.next() { + Some(x) => x, + None => { + self.insert_inner(Self::File(value)); + return; + } + }; + + if key.as_ref() == "/" { + self.insert(keys, value); + return; + } + + // If we get a key, we want to create a new entry in self for this key, or access it and + // insert `value` recursively. + let files = self.files(); + let folder = if let Some(x) = files.iter_mut().find(|x| x.is_dir(key.as_ref())) { + x + } else { + files.push(Self::Directory { + folder: key.as_ref().to_owned(), + files: vec![], + }); + // SAFETY: Last element will always exist, because we push it above. + match files.last_mut() { + Some(x) => x, + None => unreachable!("Entry::insert: failed to get last file"), + } + }; + + folder.insert(keys, value); + } + + /// Changes the root to the first folder that has children. + pub fn compress(&mut self) { + while let Entry::Directory { files, .. } = self { + if files.len() != 1 { + return; + } + + if let Some(Entry::File(_)) = files.first() { + return; + } + + let mut new_root = files.pop().unwrap(); + + core::mem::swap(self, &mut new_root); + } + } + + /// Insert a new entry into the current entry. + /// + /// # Panics + /// This method will panic if the current entry is not a directory. + fn insert_inner(&mut self, value: Self) { + match self { + Self::Directory { files, .. } => files.push(value), + _ => panic!("Attempted to insert a new entry into a entry that isnt a directory"), + } + } + + /// Will return a mutable reference to a vec of entries. + /// + /// # Panics + /// This method will panic if the current entry is not a directory. + fn files(&mut self) -> &mut Vec { + match self { + Self::Directory { files, .. } => files, + _ => panic!("Attempted to get all files of a entry that isnt a directory"), + } + } + + /// Method indicates whether the current entry is a directory with the name `k`. + fn is_dir(&self, k: &str) -> bool { + match self { + Self::File(_) => false, + Self::Directory { folder, .. } => folder == k, + } + } + + /// Method indicates whether the current entry is a file. + fn is_file(&self) -> bool { + match self { + Self::File(_) => true, + _ => false, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[derive(Debug, PartialEq, Eq)] + struct Record(String); + + #[test] + fn insert_some() { + let mut entry = Entry::new(); + + // file located at /a/b/c + let keys = ["a", "b", "c"]; + + entry.insert(IntoIterator::into_iter(keys), Record("d.txt".to_string())); + entry.insert(IntoIterator::into_iter(keys), Record("d.txt".to_string())); + + assert_eq!( + entry, + Entry::Directory { + folder: "/".into(), + files: vec![Entry::Directory { + folder: "a".into(), + files: vec![Entry::Directory { + folder: "b".into(), + files: vec![Entry::Directory { + folder: "c".into(), + files: vec![ + Entry::File(Record("d.txt".to_string())), + Entry::File(Record("d.txt".to_string())) + ] + }] + }] + }] + } + ); + } + + #[test] + fn insert_different_folders() { + let mut entry = Entry::new(); + + entry.insert( + IntoIterator::into_iter(["a", "b", "c"]), + Record("d.txt".to_string()), + ); + entry.insert( + IntoIterator::into_iter(["a", "b", "d"]), + Record("d.txt".to_string()), + ); + entry.insert( + IntoIterator::into_iter(["z", "b", "d"]), + Record("d.txt".to_string()), + ); + entry.insert( + IntoIterator::into_iter(["a", "z"]), + Record("d.txt".to_string()), + ); + + assert_eq!( + entry, + Entry::Directory { + folder: "/".into(), + files: vec![ + Entry::Directory { + folder: "a".into(), + files: vec![ + Entry::Directory { + folder: "b".into(), + files: vec![ + Entry::Directory { + folder: "c".into(), + files: vec![Entry::File(Record("d.txt".to_string())),] + }, + Entry::Directory { + folder: "d".into(), + files: vec![Entry::File(Record("d.txt".to_string())),] + } + ] + }, + Entry::Directory { + folder: "z".into(), + files: vec![Entry::File(Record("d.txt".to_string())),] + } + ] + }, + Entry::Directory { + folder: "z".into(), + files: vec![Entry::Directory { + folder: "b".into(), + files: vec![Entry::Directory { + folder: "d".into(), + files: vec![Entry::File(Record("d.txt".to_string())),] + }] + }] + }, + ] + } + ); + } + + #[test] + fn test_compression() { + let mut entry = Entry::new(); + + entry.insert( + IntoIterator::into_iter(["a", "b", "c"]), + Record("d.txt".into()), + ); + entry.compress(); + + assert_eq!( + entry, + Entry::Directory { + folder: "c".into(), + files: vec![Entry::File(Record("d.txt".into()))] + } + ); + } +} diff --git a/dim/Cargo.toml b/dim/Cargo.toml index ba0a4ab46..9001d57cd 100644 --- a/dim/Cargo.toml +++ b/dim/Cargo.toml @@ -22,6 +22,9 @@ dim-auth = { path = "../dim-auth" } dim-database = { path = "../dim-database" } dim-events = { path = "../dim-events" } dim-extern-api = { path = "../dim-extern-api" } +dim-web = { path = "../dim-web" } +dim-utils = { path = "../dim-utils" } + serde = { version = "^1.0.125", default-features = false, features = ["derive", "std", "rc"] } serde_derive = "^1.0.125" @@ -34,41 +37,41 @@ chrono = { version = "0.4.19", features = ["serde"] } dia-i18n = "0.10.0" displaydoc = "0.2.3" dominant_color = "0.3.0" +fdlimit = "0.2.1" futures = "0.3.14" fuzzy-matcher = "0.3.7" http = "^0.2.3" +hyper = "0.14.20" image = "0.24.3" itertools = "0.10.3" lazy_static = "1.4.0" +libsqlite3-sys = { version = "^0.24.0" } notify = "5.0.0" once_cell = "1.8.0" parking_lot = "0.12.0" percent-encoding = "2.1.0" rand = { version = "0.8.5", features = ["small_rng"] } reqwest = { version = "0.11.0", features = ["json", "rustls-tls", "brotli"], default-features = false } +rusqlite = { version = "0.27.0", features = ["hooks"] } rust-embed = "^5.9.0" sqlx = { version = "0.5", features = ["runtime-tokio-rustls"] } structopt = "0.3.21" thiserror = "1.0.30" tokio = { version = "1", features = ["rt", "signal", "full", "tracing"] } +tokio-stream = "0.1.12" +tokio-tungstenite = "0.18.0" toml = "0.5.8" +tower-http = { version = "0.4.0", features = ["trace", "cors"] } tracing = "0.1.32" tracing-appender = "0.2.0" tracing-subscriber = { version = "^0.3.10", features = ["fmt", "env-filter", "json"] } tracing-tree = "0.2.0" +url = "2.2.2" uuid = { version = "1.2.2", features = ["v4"] } walkdir = "2.3.1" warp = { version = "0.3.3", features = ["tls", "tokio-rustls"] } xmlwriter = "0.1.0" -xtra = { version = "0.5.1", features = ["with-tokio-1"] } - -# FIXME: Remove when we get rid of xtra_proc -new_xtra = { package = "xtra", git = "https://github.com/Restioson/xtra", features = ["with-tokio-1"] } -url = "2.2.2" -hyper = "0.14.20" -rusqlite = { version = "0.27.0", features = ["hooks"] } -libsqlite3-sys = { version = "^0.24.0" } -fdlimit = "0.2.1" +xtra = { version = "0.5.1", features = ["tokio", "with-tokio-1"] } [build-dependencies] fs_extra = "1.1.0" diff --git a/dim/src/core.rs b/dim/src/core.rs index c09b61153..713bf505d 100644 --- a/dim/src/core.rs +++ b/dim/src/core.rs @@ -1,23 +1,28 @@ -use crate::balanced_or_tree; -use crate::logger::RequestLogger; use crate::routes; use crate::routes::*; use crate::scanner; use crate::stream_tracking::StreamTracking; -use crate::websocket; use dim_database::library::MediaType; use dim_extern_api::tmdb::TMDBMetadataProvider; +use dim_web::axum::extract::ConnectInfo; +use dim_web::axum::extract::State; +use futures::SinkExt; +use futures::StreamExt; use once_cell::sync::OnceCell; use tokio::sync::mpsc::UnboundedReceiver; use tokio::sync::mpsc::UnboundedSender; use tracing::{info, instrument}; -use warp::http::status::StatusCode; +use dim_web::routes::websocket; + use warp::Filter; +use std::net::IpAddr; +use std::net::Ipv4Addr; +use std::net::SocketAddr; use std::sync::Arc; pub type StateManager = nightfall::StateManager; @@ -81,11 +86,10 @@ pub async fn run_scanners(tx: EventTx) { } } -#[instrument(skip(stream_manager, event_tx, rt, event_rx))] +// #[instrument(skip(stream_manager, event_tx, rt, event_rx))] pub async fn warp_core( event_tx: EventTx, stream_manager: StateManager, - rt: tokio::runtime::Handle, port: u16, event_rx: UnboundedReceiver, ) { @@ -95,115 +99,224 @@ pub async fn warp_core( .await .expect("Failed to grab a handle to the connection pool."); - let request_logger = RequestLogger::new(); - - let api_routes = balanced_or_tree![ - /* NOTE: v1 REST API routes start HERE */ - /* /api/v1/auth routes*/ - auth::filters::login(conn.clone()), - user::filters::whoami(conn.clone()), - host::filters::admin_exists(conn.clone()), - auth::filters::register(conn.clone()), - invites::filters::get_all_invites(conn.clone()), - invites::filters::generate_invite(conn.clone()), - invites::filters::delete_token(conn.clone()), - /* /api/v1/user routes */ - user::filters::change_password(conn.clone()), - user::filters::delete(conn.clone()), - user::filters::change_username(conn.clone()), - user::filters::upload_avatar(conn.clone()), - /* general routes */ - routes::general::filters::search(conn.clone()), - routes::general::filters::get_directory_structure(conn.clone()), - /* library routes */ - routes::library::filters::library_get(conn.clone()), - routes::library::filters::library_post(conn.clone(), event_tx.clone()), - routes::library::filters::library_delete(conn.clone()), - routes::library::filters::library_get_self(conn.clone()), - routes::library::filters::get_all_of_library(conn.clone()), - routes::library::filters::get_all_unmatched_media(conn.clone()), - /* dashboard routes */ - routes::dashboard::filters::dashboard(conn.clone(), rt.clone()), - routes::dashboard::filters::banners(conn.clone()), - /* media routes */ - routes::media::filters::get_media_by_id(conn.clone()), - routes::media::filters::get_media_files(conn.clone()), - routes::media::filters::update_media_by_id(conn.clone()), - routes::media::filters::delete_media_by_id(conn.clone()), - routes::media::filters::tmdb_search(conn.clone()), - routes::media::filters::map_progress(conn.clone()), - routes::media::filters::get_mediafile_tree(conn.clone()), - routes::rematch_media::filters::rematch_media_by_id(conn.clone(), event_tx.clone()), - /* tv routes */ - routes::tv::filters::get_tv_seasons(conn.clone()), - routes::tv::filters::patch_episode_by_id(conn.clone()), - routes::tv::filters::delete_season_by_id(conn.clone()), - routes::tv::filters::get_season_episodes(conn.clone()), - routes::tv::filters::patch_episode_by_id(conn.clone()), - routes::tv::filters::delete_episode_by_id(conn.clone()), - /* mediafile routes */ - routes::mediafile::filters::get_mediafile_info(conn.clone()), - routes::mediafile::filters::rematch_mediafile(conn.clone()), - /* settings routes */ - routes::settings::filters::get_user_settings(conn.clone()), - routes::settings::filters::post_user_settings(conn.clone()), - routes::settings::filters::get_global_settings(conn.clone()), - routes::settings::filters::set_global_settings(conn.clone()), - /* stream routes */ - routes::stream::filters::return_virtual_manifest( - conn.clone(), - state.clone(), - stream_tracking.clone() - ), - routes::stream::filters::return_manifest( - conn.clone(), - state.clone(), - stream_tracking.clone() - ), - routes::stream::filters::get_init(state.clone()) - .recover(routes::global_filters::handle_rejection), - routes::stream::filters::should_client_hard_seek(state.clone(), stream_tracking.clone()), - routes::stream::filters::session_get_stderr(state.clone(), stream_tracking.clone()), - routes::stream::filters::kill_session(state.clone(), stream_tracking.clone()), - routes::stream::filters::get_subtitle(state.clone()), - routes::stream::filters::get_subtitle_ass(state.clone()), - routes::stream::filters::get_chunk(state.clone()) - .recover(routes::global_filters::handle_rejection), - warp::path!("api" / "stream" / ..) - .and(warp::any()) - .map(|| StatusCode::NOT_FOUND), - routes::statik::filters::get_image(conn.clone()), - ] - .recover(routes::global_filters::handle_rejection); - - cfg_if::cfg_if! { - if #[cfg(debug_assertions)] { - let api_routes = api_routes.boxed(); - } + macro_rules! warp { + ($p:path) => { + ::warp::service($p(conn.clone())) + }; } - let routes = balanced_or_tree![ - api_routes, - /* NOTE: This is a barrier to 404 any rest api calls that dont match till here */ - routes::global_filters::api_not_found(), - /* websocket route */ - websocket::event_socket(tokio::runtime::Handle::current(), event_rx, conn.clone()) - .recover(routes::global_filters::handle_rejection), - /* static routes */ - routes::statik::filters::dist_static(), - routes::statik::filters::react_routes(), - ] - .recover(routes::global_filters::handle_rejection) - .with(warp::filters::log::custom(move |x| { - request_logger.on_response(x); - })) - .with(warp::cors().allow_any_origin()) - .boxed(); + let (a, b, socket_tx) = websocket::event_repeater( + tokio_stream::wrappers::UnboundedReceiverStream::new(event_rx), + ); + + tokio::spawn(async move { + tokio::join!(a, b); + }); + + #[derive(Debug, Clone)] + struct AppState { + conn: DbConnection, + socket_tx: websocket::SocketTx, + } + + async fn ws_handler( + ws: dim_web::axum::extract::WebSocketUpgrade, + ConnectInfo(remote_address): ConnectInfo, + State(AppState { conn, socket_tx }): State, + ) -> dim_web::axum::response::Response { + ws.on_upgrade(move |websocket| async move { + let (ws_tx, ws_rx) = websocket.split(); + + websocket::handle_websocket_session( + ws_tx.sink_err_into::(), + ws_rx.filter_map(|m| async move { m.ok() }), + Some(remote_address), + conn, + socket_tx, + ) + .await; + }) + } + + let router = dim_web::axum::Router::new() + .route_service("/api/v1/auth/login", warp!(auth::filters::login)) + .route_service("/api/v1/auth/register", warp!(auth::filters::register)) + .route_service("/api/v1/auth/whoami", warp!(user::filters::whoami)) + .route_service( + "/api/v1/host/admin_exists", + warp!(host::filters::admin_exists), + ) + .route_service( + "/api/v1/library/*path", + warp::service({ + routes::library::filters::library_get_self(conn.clone()) + .or(routes::library::filters::get_all_unmatched_media( + conn.clone(), + )) + .or(routes::library::filters::library_delete(conn.clone())) + .or(routes::library::filters::library_get_self(conn.clone())) + .or(routes::library::filters::get_all_of_library(conn.clone())) + }), + ) + .route_service( + "/api/v1/library", + warp::service(library::filters::library_get(conn.clone()).or( + routes::library::filters::library_post(conn.clone(), event_tx.clone()), + )), + ) + .route_service("/api/v1/dashboard", warp!(dashboard::filters::dashboard)) + .route_service( + "/api/v1/dashboard/banner", + warp!(dashboard::filters::banners), + ) + .route_service("/api/v1/search", warp!(routes::general::filters::search)) + .route_service( + "/api/v1/filebrowser/", + warp!(routes::general::filters::get_directory_structure), + ) + .route_service( + "/api/v1/filebrowser/*path", + warp!(routes::general::filters::get_directory_structure), + ) + .route_service("/images/*path", warp!(statik::filters::get_image)) + .route_service( + "/api/v1/media/*path", + warp::service({ + routes::media::filters::get_media_by_id(conn.clone()) + .or(routes::media::filters::get_media_files(conn.clone())) + .or(routes::media::filters::update_media_by_id(conn.clone())) + .or(routes::media::filters::delete_media_by_id(conn.clone())) + .or(routes::media::filters::tmdb_search(conn.clone())) + .or(routes::media::filters::map_progress(conn.clone())) + .or(routes::media::filters::get_mediafile_tree(conn.clone())) + .or(routes::rematch_media::filters::rematch_media_by_id( + conn.clone(), + event_tx.clone(), + )) + }), + ) + .route_service( + "/api/v1/stream/*path", + warp::service({ + routes::stream::filters::return_virtual_manifest( + conn.clone(), + state.clone(), + stream_tracking.clone(), + ) + .or(routes::stream::filters::return_manifest( + conn.clone(), + state.clone(), + stream_tracking.clone(), + )) + .or(routes::stream::filters::get_init(state.clone()) + .recover(routes::global_filters::handle_rejection)) + .or(routes::stream::filters::should_client_hard_seek( + state.clone(), + stream_tracking.clone(), + )) + .or(routes::stream::filters::session_get_stderr( + state.clone(), + stream_tracking.clone(), + )) + .or(routes::stream::filters::kill_session( + state.clone(), + stream_tracking.clone(), + )) + .or(routes::stream::filters::get_subtitle(state.clone())) + .or(routes::stream::filters::get_subtitle_ass(state.clone())) + .or(routes::stream::filters::get_chunk(state.clone()) + .recover(routes::global_filters::handle_rejection)) + }), + ) + .route_service( + "/api/v1/mediafile/*path", + warp::service({ + routes::mediafile::filters::get_mediafile_info(conn.clone()) + .or(routes::mediafile::filters::rematch_mediafile(conn.clone())) + }), + ) + .route_service( + "/api/v1/tv/*path", + warp!(routes::tv::filters::get_tv_seasons), + ) + .route_service( + "/api/v1/season/*path", + warp::service({ + routes::tv::filters::patch_episode_by_id(conn.clone()) + .or(routes::tv::filters::delete_season_by_id(conn.clone())) + .or(routes::tv::filters::get_season_episodes(conn.clone())) + .or(routes::tv::filters::patch_episode_by_id(conn.clone())) + .or(routes::tv::filters::delete_episode_by_id(conn.clone())) + }), + ) + .route_service( + "/api/v1/episode/*path", + warp::service({ + routes::tv::filters::patch_episode_by_id(conn.clone()) + .or(routes::tv::filters::delete_episode_by_id(conn.clone())) + }), + ) + .route_service( + "/api/v1/user/settings", + warp::service({ + settings::filters::get_user_settings(conn.clone()) + .or(routes::settings::filters::get_user_settings(conn.clone())) + .or(routes::settings::filters::post_user_settings(conn.clone())) + .or(routes::settings::filters::get_global_settings(conn.clone())) + .or(routes::settings::filters::set_global_settings(conn.clone())) + }), + ) + .route_service( + "/api/v1/host/settings", + warp::service({ + routes::settings::filters::get_global_settings(conn.clone()) + .or(routes::settings::filters::set_global_settings(conn.clone())) + }), + ) + .route_service( + "/api/v1/user/*path", + warp::service({ + user::filters::change_password(conn.clone()) + .or(user::filters::delete(conn.clone())) + .or(user::filters::change_username(conn.clone())) + .or(user::filters::upload_avatar(conn.clone())) + }), + ) + .route_service( + "/api/v1/auth/*path", + warp::service({ + invites::filters::get_all_invites(conn.clone()) + .or(invites::filters::generate_invite(conn.clone())) + .or(invites::filters::delete_token(conn.clone())) + }), + ) + .route_service( + "/static/*path", + warp::service( + routes::statik::filters::dist_static().or(routes::statik::filters::react_routes()), + ), + ) + .route("/ws", dim_web::axum::routing::get(ws_handler)) + .with_state(AppState { + conn: conn.clone(), + socket_tx, + }) + .layer(tower_http::trace::TraceLayer::new_for_http()) + .layer({ + let cors = tower_http::cors::CorsLayer::new() + // allow requests from any origin + .allow_origin(tower_http::cors::Any); + + cors + }); info!("Webserver is listening on 0.0.0.0:{}", port); + let socket_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), port); + let web_fut = dim_web::serve(&socket_addr, router); + tokio::select! { - _ = warp::serve(routes).run(([0, 0, 0, 0], port)) => {}, + _ = web_fut => {}, _ = tokio::signal::ctrl_c() => { std::process::exit(0); } diff --git a/dim/src/lib.rs b/dim/src/lib.rs index dc463250f..2190d072d 100644 --- a/dim/src/lib.rs +++ b/dim/src/lib.rs @@ -19,12 +19,17 @@ //! To test run `make test` in the root, or `cargo test` in the root of each module including the //! root dir. #![allow(opaque_hidden_inferred_bound)] +#![deny(warnings)] use std::fs::create_dir_all; use tracing_subscriber::fmt; use tracing_subscriber::layer::SubscriberExt; use tracing_subscriber::EnvFilter; +/// Various utilities +pub mod utils; +pub(crate) use utils::json; + /// Module contains our core initialization logic. pub mod core; /// Module contains all the error definitions used in dim, and returned by the web-service. @@ -49,10 +54,6 @@ pub mod streaming; mod tests; /// Tree-like structure for representing directories of files. pub mod tree; -/// Various utilities -pub mod utils; -/// Websocket related logic. -pub mod websocket; pub use routes::settings::get_global_settings; pub use routes::settings::init_global_settings; @@ -64,7 +65,7 @@ pub fn setup_logging(_debug: bool) { let _ = create_dir_all("logs"); if std::env::var("RUST_LOG").is_err() { - std::env::set_var("RUST_LOG", "info"); + std::env::set_var("RUST_LOG", "info,tower_http=trace"); } let log_appender = tracing_appender::rolling::daily("./logs", "dim-log.log"); diff --git a/dim/src/main.rs b/dim/src/main.rs index 11b457b08..102ed443d 100644 --- a/dim/src/main.rs +++ b/dim/src/main.rs @@ -130,9 +130,7 @@ fn main() { info!("Summoning Dim v{}...", structopt::clap::crate_version!()); - let rt = tokio::runtime::Handle::current(); - - core::warp_core(event_tx, stream_manager, rt, global_settings.port, event_rx).await; + core::warp_core(event_tx, stream_manager, global_settings.port, event_rx).await; }; tokio::runtime::Runtime::new() diff --git a/dim/src/routes/dashboard.rs b/dim/src/routes/dashboard.rs index 98150ef44..7e6dac22f 100644 --- a/dim/src/routes/dashboard.rs +++ b/dim/src/routes/dashboard.rs @@ -25,24 +25,18 @@ pub mod filters { use super::super::global_filters::with_state; - use tokio::runtime::Handle as TokioHandle; - pub fn dashboard( conn: DbConnection, - rt: tokio::runtime::Handle, ) -> impl Filter + Clone { warp::path!("api" / "v1" / "dashboard") .and(warp::get()) .and(with_auth(conn.clone())) .and(with_state::(conn)) - .and(with_state::(rt)) - .and_then( - |user: User, conn: DbConnection, rt: TokioHandle| async move { - super::dashboard(conn, user, rt) - .await - .map_err(|e| reject::custom(e)) - }, - ) + .and_then(|user: User, conn: DbConnection| async move { + super::dashboard(conn, user, tokio::runtime::Handle::current()) + .await + .map_err(|e| reject::custom(e)) + }) } pub fn banners( diff --git a/dim/src/routes/mod.rs b/dim/src/routes/mod.rs index f6ae1f53a..d740d3bba 100644 --- a/dim/src/routes/mod.rs +++ b/dim/src/routes/mod.rs @@ -30,6 +30,7 @@ pub mod statik; pub mod stream; pub mod tv; pub mod user; +pub mod websocket; #[doc(hidden)] pub mod global_filters { @@ -48,7 +49,7 @@ pub mod global_filters { pub fn with_db( conn: DbConnection, - ) -> impl Filter + Clone { + ) -> impl Filter + Clone + 'static { warp::any().map(move || conn.clone()) } diff --git a/dim/src/routes/stream.rs b/dim/src/routes/stream.rs index 667e232b3..040e03b92 100644 --- a/dim/src/routes/stream.rs +++ b/dim/src/routes/stream.rs @@ -44,7 +44,6 @@ pub mod filters { use crate::core::StateManager; use crate::errors::StreamingErrors; use crate::stream_tracking::StreamTracking; - use crate::warp_unwrap; use dim_database::user::User; use uuid::Uuid; @@ -81,7 +80,7 @@ pub mod filters { stream_tracking: StreamTracking| async move { let gid = gid.and_then(|x| Uuid::parse_str(x.as_str()).ok()); - warp_unwrap!( + dim_utils::warp_unwrap!( super::return_virtual_manifest( state, stream_tracking, @@ -512,7 +511,7 @@ pub async fn create_video( 24, )); - let label = quality_to_label(quality, Some(bitrate)); + let label = quality_to_label(quality.bitrate, quality.height, Some(bitrate)); // TODO: This code will not work correctly if there are similar resolutions with different // brates. diff --git a/dim/src/routes/websocket.rs b/dim/src/routes/websocket.rs new file mode 100644 index 000000000..531e88828 --- /dev/null +++ b/dim/src/routes/websocket.rs @@ -0,0 +1,44 @@ +use std::net::SocketAddr; + +use dim_web::routes::websocket::{handle_websocket_session, SocketTx, WsMessageError}; + +use warp::Filter; + +use futures::prelude::*; + +use crate::routes; + +pub fn ws( + socket_tx: SocketTx, + conn: dim_database::DbConnection, +) -> impl warp::Filter + Clone { + warp::path("ws") + .and(warp::filters::addr::remote()) + .and(routes::global_filters::with_state(socket_tx)) + .and(warp::ws()) + .and(warp::any().map(move || conn.clone())) + .map( + |remote_address: Option, + socket_tx: SocketTx, + ws: warp::ws::Ws, + conn: dim_database::DbConnection| { + ws.on_upgrade(move |websocket| async move { + let (ws_tx, ws_rx) = websocket.split(); + let ws_tx = ws_tx + .sink_err_into::() + .with(|m| async move { + dim_web::routes::websocket::from_tungstenite_message(m) + }); + + let ws_rx = ws_rx + .map_err(|_| ()) + .and_then( + |m| async move { dim_web::routes::websocket::from_warp_message(m) }, + ) + .filter_map(|res| async move { res.ok() }); + + handle_websocket_session(ws_tx, ws_rx, remote_address, conn, socket_tx).await; + }) + }, + ) +} diff --git a/dim/src/scanner/mediafile.rs b/dim/src/scanner/mediafile.rs index 2a40206ab..c889ec573 100644 --- a/dim/src/scanner/mediafile.rs +++ b/dim/src/scanner/mediafile.rs @@ -26,7 +26,7 @@ use tracing::Instrument; use thiserror::Error; -use new_xtra::prelude::*; +use xtra::prelude::*; /// This semaphore is necessary so that we dont create too many instances of `MediafileCreator`. /// Having too many instances would not make sense as we can support only so many instances without @@ -239,19 +239,21 @@ impl MediafileCreator { } #[async_trait] -impl Actor for MediafileCreator { - type Stop = (); - - async fn stopped(self) {} -} +impl Actor for MediafileCreator {} pub struct InsertBatch(pub Vec); +impl Message for InsertBatch { + type Result = Result>; +} + #[async_trait] impl Handler for MediafileCreator { - type Return = Result>; - - async fn handle(&mut self, batch: InsertBatch, _: &mut Context) -> Self::Return { + async fn handle( + &mut self, + batch: InsertBatch, + _: &mut Context, + ) -> ::Result { self.insert_batch(batch.0.iter()).await } } diff --git a/dim/src/scanner/movie.rs b/dim/src/scanner/movie.rs index 0fba55a4f..42a672e39 100644 --- a/dim/src/scanner/movie.rs +++ b/dim/src/scanner/movie.rs @@ -324,7 +324,7 @@ mod tests { external_id: "123".into(), title: "Test Title".into(), description: Some("test description".into()), - release_date: Some(chrono::Utc.ymd(1983, 1, 10).and_hms(0, 0, 0)), + release_date: chrono::Utc.with_ymd_and_hms(1983, 1, 10, 0, 0, 0).single(), posters: vec![], backdrops: vec![], genres: vec!["Comedy".into()], @@ -529,7 +529,7 @@ mod tests { external_id: "123".into(), title: "Test Title".into(), description: Some("test description".into()), - release_date: Some(chrono::Utc.ymd(1983, 1, 10).and_hms(0, 0, 0)), + release_date: chrono::Utc.with_ymd_and_hms(1983, 1, 10, 0, 0, 0).single(), posters: vec![], backdrops: vec![], genres: vec!["Comedy".into()], @@ -616,7 +616,7 @@ mod tests { external_id: "123".into(), title: "Test Title".into(), description: Some("test description".into()), - release_date: Some(chrono::Utc.ymd(1983, 1, 10).and_hms(0, 0, 0)), + release_date: chrono::Utc.with_ymd_and_hms(1983, 1, 10, 0, 0, 0).single(), posters: vec![], backdrops: vec![], genres: vec!["Comedy".into()], diff --git a/dim/src/scanner/tests/mediafile.rs b/dim/src/scanner/tests/mediafile.rs index d4d263aef..3512c37ab 100644 --- a/dim/src/scanner/tests/mediafile.rs +++ b/dim/src/scanner/tests/mediafile.rs @@ -18,8 +18,8 @@ use core::pin::Pin; use futures::FutureExt; -use new_xtra::spawn::Tokio; -use new_xtra::Actor; +use xtra::spawn::Tokio; +use xtra::Actor; pub(crate) async fn create_library(conn: &mut dim_database::DbConnection) -> i64 { let mut lock = conn.writer().lock_owned().await; diff --git a/dim/src/utils.rs b/dim/src/utils.rs index da5f96721..74aa49fcd 100644 --- a/dim/src/utils.rs +++ b/dim/src/utils.rs @@ -1,521 +1,2 @@ -/// Source: https://github.com/seanmonstar/warp/issues/619 -/// Takes a list of handler expressions and `or`s them together -/// in a balanced tree. That is, instead of `a.or(b).or(c).or(d)`, -/// it produces `(a.or(b)).or(c.or(d))`, thus nesting the types -/// less deeply, which provides improvements in compile time. -/// -/// It also applies `::warp::Filter::boxed` to each handler expression -/// when in `debug_assertions` mode, improving compile time further. -/// -// -// The basic list splitting algorithm here is based on this gist: -// https://gist.github.com/durka/9fc479de2555225a787f -// It uses a counter from which two items are removed each time, -// stopping when the counter reaches 0. At each step, one item -// is moved from the left to the right, and thus at the end, -// there will be the same number of items in each list. -// -// The flow is as follows: -// - If there is one handler expression, debug_box it and return. -// - If there is more than one handler expression: -// - First, copy the list into two: the one that will go into the -// right side of the `or`, and one that will serve as a counter. -// Recurse with these separated by semicolons, plus an empty `left` -// list before the first semicolon. -// - Then, as long as there are at least two items in the counter -// list, remove them and move the first item on the right side of -// the first semicolon (`head`) to the left side of the first semicolon. -// - Finally, when there are one or zero items left in the counter, -// move one last item to the left, make the call this macro on both the -// left and right sides, and `or` the two sides together. -// -// For example, balanced_or_tree!(a, b, c, d, e) would take the following steps: -// -// - balanced_or_tree!(a, b, c, d, e) -// - balanced_or_tree!(@internal ; a, b, c, d, e ; a, b, c, d, e) // initialise lists -// - balanced_or_tree!(@internal a ; b, c, d, e ; c, d, e) // move one elem; remove two -// - balanced_or_tree!(@internal a, b ; c, d, e ; e) // now only one elem in counter -// - balanced_or_tree!(a, b, c).or(balanced_or_tree(d, e)) // recurse on each sublist -#[macro_export] -macro_rules! balanced_or_tree { - // Base case: just a single expression, return it wrapped in `debug_boxed` - ($x:expr $(,)?) => { $x }; - // Multiple expressions: recurse with three lists: left, right and counter. - ($($x:expr),+ $(,)?) => { - balanced_or_tree!(@internal ; $($x),+; $($x),+) - // ^ left ^ right ^ counter - }; - // Counter 1 or 2; move one more item and recurse on each sublist, and or them together - (@internal $($left:expr),*; $head:expr, $($tail:expr),+; $a:expr $(,$b:expr)?) => { - (balanced_or_tree!($($left,)* $head)).or(balanced_or_tree!($($tail),+)) - }; - // Counter > 2; move one item from the right to the left and subtract two from the counter - (@internal $($left:expr),*; $head:expr, $($tail:expr),+; $a:expr, $b:expr, $($more:expr),+) => { - balanced_or_tree!(@internal $($left,)* $head; $($tail),+; $($more),+) - }; -} - -#[macro_export] -macro_rules! warp_try { - ($x:expr) => { - match $x { - Ok(x) => x, - Err(e) => return Ok(::warp::reply::Reply::into_response(e)), - } - }; -} - -#[macro_export] -macro_rules! warp_unwrap { - ($x:expr) => { - match $x { - Ok(x) => { - Result::<_, ::core::convert::Infallible>::Ok(::warp::reply::Reply::into_response(x)) - } - Err(e) => { - Result::<_, ::core::convert::Infallible>::Ok(::warp::reply::Reply::into_response(e)) - } - } - }; -} - -/// Construct a `serde_json::Value` from a JSON literal. -/// -/// ``` -/// # use serde_json::json; -/// # -/// let value = json!({ -/// "code": 200, -/// "success": true, -/// "payload": { -/// "features": [ -/// "serde", -/// "json" -/// ] -/// } -/// }); -/// ``` -/// -/// Variables or expressions can be interpolated into the JSON literal. Any type -/// interpolated into an array element or object value must implement Serde's -/// `Serialize` trait, while any type interpolated into a object key must -/// implement `Into`. If the `Serialize` implementation of the -/// interpolated type decides to fail, or if the interpolated type contains a -/// map with non-string keys, the `json!` macro will panic. -/// -/// ``` -/// # use serde_json::json; -/// # -/// let code = 200; -/// let features = vec!["serde", "json"]; -/// -/// let value = json!({ -/// "code": code, -/// "success": code == 200, -/// "payload": { -/// features[0]: features[1] -/// } -/// }); -/// ``` -/// -/// Trailing commas are allowed inside both arrays and objects. -/// -/// ``` -/// # use serde_json::json; -/// # -/// let value = json!([ -/// "notice", -/// "the", -/// "trailing", -/// "comma -->", -/// ]); -/// ``` -#[macro_export(local_inner_macros)] -macro_rules! json { - // Hide distracting implementation details from the generated rustdoc. - ($($json:tt)+) => { - json_internal!($($json)+) - }; -} - -// Rocket relies on this because they export their own `json!` with a different -// doc comment than ours, and various Rust bugs prevent them from calling our -// `json!` from their `json!` so they call `json_internal!` directly. Check with -// @SergioBenitez before making breaking changes to this macro. -// -// Changes are fine as long as `json_internal!` does not call any new helper -// macros and can still be invoked as `json_internal!($($json)+)`. -#[macro_export(local_inner_macros)] -#[doc(hidden)] -macro_rules! json_internal { - ////////////////////////////////////////////////////////////////////////// - // TT muncher for parsing the inside of an array [...]. Produces a vec![...] - // of the elements. - // - // Must be invoked as: json_internal!(@array [] $($tt)*) - ////////////////////////////////////////////////////////////////////////// - - // Done with trailing comma. - (@array [$($elems:expr,)*]) => { - json_internal_vec![$($elems,)*] - }; - - // Done without trailing comma. - (@array [$($elems:expr),*]) => { - json_internal_vec![$($elems),*] - }; - - // Next element is `null`. - (@array [$($elems:expr,)*] null $($rest:tt)*) => { - json_internal!(@array [$($elems,)* json_internal!(null)] $($rest)*) - }; - - // Next element is `true`. - (@array [$($elems:expr,)*] true $($rest:tt)*) => { - json_internal!(@array [$($elems,)* json_internal!(true)] $($rest)*) - }; - - // Next element is `false`. - (@array [$($elems:expr,)*] false $($rest:tt)*) => { - json_internal!(@array [$($elems,)* json_internal!(false)] $($rest)*) - }; - - // Next element is an array. - (@array [$($elems:expr,)*] [$($array:tt)*] $($rest:tt)*) => { - json_internal!(@array [$($elems,)* json_internal!([$($array)*])] $($rest)*) - }; - - // Next element is a map. - (@array [$($elems:expr,)*] {$($map:tt)*} $($rest:tt)*) => { - json_internal!(@array [$($elems,)* json_internal!({$($map)*})] $($rest)*) - }; - - // Next element is an expression followed by comma. - (@array [$($elems:expr,)*] $next:expr, $($rest:tt)*) => { - json_internal!(@array [$($elems,)* json_internal!($next),] $($rest)*) - }; - - // Last element is an expression with no trailing comma. - (@array [$($elems:expr,)*] $last:expr) => { - json_internal!(@array [$($elems,)* json_internal!($last)]) - }; - - // Comma after the most recent element. - (@array [$($elems:expr),*] , $($rest:tt)*) => { - json_internal!(@array [$($elems,)*] $($rest)*) - }; - - // Unexpected token after most recent element. - (@array [$($elems:expr),*] $unexpected:tt $($rest:tt)*) => { - json_unexpected!($unexpected) - }; - - ////////////////////////////////////////////////////////////////////////// - // TT muncher for parsing the inside of an object {...}. Each entry is - // inserted into the given map variable. - // - // Must be invoked as: json_internal!(@object $map () ($($tt)*) ($($tt)*)) - // - // We require two copies of the input tokens so that we can match on one - // copy and trigger errors on the other copy. - ////////////////////////////////////////////////////////////////////////// - - // Done. - (@object $object:ident () () ()) => {}; - - // Insert the current entry followed by trailing comma. - (@object $object:ident [$($key:tt)+] ($value:expr) , $($rest:tt)*) => { - let _ = $object.insert(($($key)+).into(), $value); - json_internal!(@object $object () ($($rest)*) ($($rest)*)); - }; - - // Current entry followed by unexpected token. - (@object $object:ident [$($key:tt)+] ($value:expr) $unexpected:tt $($rest:tt)*) => { - json_unexpected!($unexpected); - }; - - // Insert the last entry without trailing comma. - (@object $object:ident [$($key:tt)+] ($value:expr)) => { - let _ = $object.insert(($($key)+).into(), $value); - }; - - // Next value is `null`. - (@object $object:ident ($($key:tt)+) (: null $($rest:tt)*) $copy:tt) => { - json_internal!(@object $object [$($key)+] (json_internal!(null)) $($rest)*); - }; - - // Next value is `true`. - (@object $object:ident ($($key:tt)+) (: true $($rest:tt)*) $copy:tt) => { - json_internal!(@object $object [$($key)+] (json_internal!(true)) $($rest)*); - }; - - // Next value is `false`. - (@object $object:ident ($($key:tt)+) (: false $($rest:tt)*) $copy:tt) => { - json_internal!(@object $object [$($key)+] (json_internal!(false)) $($rest)*); - }; - - // Next value is an array. - (@object $object:ident ($($key:tt)+) (: [$($array:tt)*] $($rest:tt)*) $copy:tt) => { - json_internal!(@object $object [$($key)+] (json_internal!([$($array)*])) $($rest)*); - }; - - // Next value is a map. - (@object $object:ident ($($key:tt)+) (: {$($map:tt)*} $($rest:tt)*) $copy:tt) => { - json_internal!(@object $object [$($key)+] (json_internal!({$($map)*})) $($rest)*); - }; - - // Next value is an expression followed by comma. - (@object $object:ident ($($key:tt)+) (: $value:expr , $($rest:tt)*) $copy:tt) => { - json_internal!(@object $object [$($key)+] (json_internal!($value)) , $($rest)*); - }; - - // Next value is an optional expression followed by comma. - (@object $object:ident ($($key:tt)+) (:? $value:expr , $($rest:tt)*) $copy:tt) => { - if let Some(x) = $value { - json_internal!(@object $object [$($key)+] (json_internal!($value)) , $($rest)*); - } else { - json_internal!(@object $object () ($($rest)*) ($($rest)*)); - } - }; - - // Next entry is a key with the spread operator and no value - (@object $object:ident ($(...$key:expr)+) (, $($rest:tt)*) $copy:tt) => { - if let Some(map) = ($($key)+).clone().as_object_mut() { - let _ = $object.append(map); - } - - json_internal!(@object $object () ($($rest)*) ($($rest)*)); - }; - - // Last entry is a key with the spread operator and no value. - (@object $object:ident ($(...$key:expr)+) () $copy:tt) => { - if let Some(map) = ($($key)+).clone().as_object_mut() { - let _ = $object.append(map); - } - }; - - // Next entry is a key with the optional spread operator and no value. - // This takes in a `Option` and will merge the value if its `Some`. - (@object $object:ident ($(..?$key:expr)+) (, $($rest:tt)*) $copy:tt) => { - if let Some(map) = ($($key)+).clone().as_mut().and_then(|x| x.as_object_mut()) { - let _ = $object.append(map); - } - - json_internal!(@object $object () ($($rest)*) ($($rest)*)); - }; - - // Last entry is a key with the optional spread operator and no value. - // This takes in a `Option` and will merge the value if its `Some`. - (@object $object:ident ($(..?$key:expr)+) () $copy:tt) => { - if let Some(map) = ($($key)+).clone().as_mut().and_then(|x| x.as_object_mut()) { - let _ = $object.append(map); - } - }; - - // Last value is an expression with no trailing comma. - (@object $object:ident ($($key:tt)+) (: $value:expr) $copy:tt) => { - json_internal!(@object $object [$($key)+] (json_internal!($value))); - }; - - // Missing value for last entry. Trigger a reasonable error message. - (@object $object:ident ($($key:tt)+) (:) $copy:tt) => { - // "unexpected end of macro invocation" - json_internal!(); - }; - - // Missing colon and value for last entry. Trigger a reasonable error - // message. - (@object $object:ident ($($key:tt)+) () $copy:tt) => { - // "unexpected end of macro invocation" - json_internal!(); - }; - - // Misplaced colon. Trigger a reasonable error message. - (@object $object:ident () (: $($rest:tt)*) ($colon:tt $($copy:tt)*)) => { - // Takes no arguments so "no rules expected the token `:`". - json_unexpected!($colon); - }; - - // Found a comma inside a key. Trigger a reasonable error message. - (@object $object:ident ($($key:tt)*) (, $($rest:tt)*) ($comma:tt $($copy:tt)*)) => { - // Takes no arguments so "no rules expected the token `,`". - json_unexpected!($comma); - }; - - // Key is fully parenthesized. This avoids clippy double_parens false - // positives because the parenthesization may be necessary here. - (@object $object:ident () (($key:expr) : $($rest:tt)*) $copy:tt) => { - json_internal!(@object $object ($key) (: $($rest)*) (: $($rest)*)); - }; - - // Refuse to absorb colon token into key expression. - (@object $object:ident ($($key:tt)*) (: $($unexpected:tt)+) $copy:tt) => { - json_expect_expr_comma!($($unexpected)+); - }; - - // Munch a token into the current key. - (@object $object:ident ($($key:tt)*) ($tt:tt $($rest:tt)*) $copy:tt) => { - json_internal!(@object $object ($($key)* $tt) ($($rest)*) ($($rest)*)); - }; - - ////////////////////////////////////////////////////////////////////////// - // The main implementation. - // - // Must be invoked as: json_internal!($($json)+) - ////////////////////////////////////////////////////////////////////////// - - (null) => { - ::serde_json::Value::Null - }; - - (true) => { - ::serde_json::Value::Bool(true) - }; - - (false) => { - ::serde_json::Value::Bool(false) - }; - - ([]) => { - ::serde_json::Value::Array(json_internal_vec![]) - }; - - ([ $($tt:tt)+ ]) => { - ::serde_json::Value::Array(json_internal!(@array [] $($tt)+)) - }; - - ({}) => { - ::serde_json::Value::Object(::serde_json::Map::new()) - }; - - ({ $($tt:tt)+ }) => { - ::serde_json::Value::Object({ - let mut object = ::serde_json::Map::new(); - json_internal!(@object object () ($($tt)+) ($($tt)+)); - object - }) - }; - - // Any Serialize type: numbers, strings, struct literals, variables etc. - // Must be below every other rule. - ($other:expr) => { - ::serde_json::to_value(&$other).unwrap() - }; -} - -// The json_internal macro above cannot invoke vec directly because it uses -// local_inner_macros. A vec invocation there would resolve to $crate::vec. -// Instead invoke vec here outside of local_inner_macros. -#[macro_export] -#[doc(hidden)] -macro_rules! json_internal_vec { - ($($content:tt)*) => { - vec![$($content)*] - }; -} - -#[macro_export] -#[doc(hidden)] -macro_rules! json_unexpected { - () => {}; -} - -#[macro_export] -#[doc(hidden)] -macro_rules! json_expect_expr_comma { - ($e:expr , $($tt:tt)*) => {}; -} - -use crate::streaming::Quality; - -pub fn quality_to_label(quality: &'static Quality, brate: Option) -> String { - let bandwidth_ident = if brate.unwrap_or(quality.bitrate) > 1_000_000 { - "MB" - } else { - "KB" - }; - - let bandwidth_norm = if brate.unwrap_or(quality.bitrate) > 1_000_000 { - quality.bitrate / 1_000_000 - } else { - quality.bitrate / 1_000 - }; - - format!("{}p@{}{}", quality.height, bandwidth_norm, bandwidth_ident) -} - -pub fn ts_to_xml(t: u64) -> String { - let h = t / 3600; - let m = t % 3600 / 60; - let s = t % 3600 % 60; - - let mut tag = "PT".to_string(); - - if h != 0 { - tag = format!("{}{}H", tag, h); - } - - if m != 0 { - tag = format!("{}{}M", tag, m); - } - - if s != 0 { - tag = format!("{}{}S", tag, s); - } - - tag -} - -pub fn secs_to_pretty(t: u64) -> String { - let h = t / 3600; - let m = t % 3600 / 60; - - let mut tag = String::new(); - - if h != 0 { - tag = format!("{h}hr"); - } - - if m != 0 { - tag = format!("{tag} {m}m"); - } - - tag -} - -#[cfg(not(debug_assertions))] -pub fn ffpath(bin: impl AsRef) -> String { - let mut path = std::env::current_exe().expect("Failed to grab path to the `dim` binary."); - path.pop(); // remove the dim bin to get the dir of `dim` - path.push(bin.as_ref()); - - path.to_string_lossy().to_string() -} - -#[cfg(debug_assertions)] -pub fn ffpath(bin: impl AsRef) -> String { - bin.as_ref().to_string() -} - -pub fn codec_pretty(codec: &str) -> String { - match codec { - "h264" => "H.264".into(), - x => x.to_uppercase(), - } -} - -pub fn channels_pretty(ch: i64) -> String { - match ch { - 2 | 3 => "2.1".into(), - 6 => "5.1".into(), - 8 => "7.1".into(), - _ => ch.to_string(), - } -} - -pub fn lang_from_iso639(tag: &str) -> Option<&'static str> { - dia_i18n::iso_639::LANG_CODES - .iter() - .find(|x| x.v2b() == tag) - .map(|x| x.name()) -} +pub use dim_utils::*; +pub use dim_utils::{balanced_or_tree, json, warp_try, warp_unwrap}; diff --git a/dim/src/websocket.rs b/dim/src/websocket.rs deleted file mode 100644 index b131e5524..000000000 --- a/dim/src/websocket.rs +++ /dev/null @@ -1,234 +0,0 @@ -use std::collections::HashMap; -use std::hash::Hash; -use std::net::SocketAddr; - -use tokio::runtime::Handle; -use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}; - -use warp::filters::ws::Message; -use warp::filters::ws::WebSocket; -use warp::Filter; - -use futures::prelude::*; -use futures::stream::SplitSink; - -use crate::routes; - -pub enum CtrlEvent -where - A: Hash + Eq, -{ - Track { - addr: A, - sink: SplitSink, - auth: Box, - }, - - Forget { - addr: A, - }, - - SendTo { - addr: A, - message: M, - }, - - SendAll(M), -} - -pub trait IntoCtrlEvent: Sync + Send + Clone + 'static -where - A: Hash + Eq, -{ - fn into_ctrl_event(self) -> CtrlEvent; -} - -impl IntoCtrlEvent for String -where - A: Hash + Eq, -{ - fn into_ctrl_event(self) -> CtrlEvent { - CtrlEvent::SendAll(self) - } -} - -impl CtrlEvent -where - A: Hash + Eq + Clone, -{ - async fn recv_from_rx(mut rx: UnboundedReceiver) { - let mut peers = HashMap::new(); - let mut discard = vec![]; - - while let Some(ev) = rx.recv().await { - for addr in &discard { - let _ = peers.remove(addr); - } - - discard.clear(); - - match ev { - CtrlEvent::Track { addr, sink, auth } => { - peers.insert(addr, (sink, auth)); - } - - CtrlEvent::Forget { ref addr } => { - peers.remove(addr); - } - - CtrlEvent::SendAll(body) => { - for (addr, (sink, _)) in peers.iter_mut() { - let result = sink.send(Message::text(body.clone())).await; - - if result.is_err() { - let _ = sink.close().await; - discard.push(addr.clone()); - } - } - } - - CtrlEvent::SendTo { addr, message } => { - if let Some((sink, _)) = peers.get_mut(&addr) { - let result = sink.send(Message::text(message.clone())).await; - - if result.is_err() { - let _ = sink.close().await; - discard.push(addr.clone()); - } - } - } - }; - } - } -} - -#[derive(serde::Deserialize)] -#[serde(rename_all = "snake_case")] -#[serde(tag = "type")] -pub enum ClientActions { - Authenticate { token: String }, -} - -pub fn event_socket( - rt_handle: Handle, - mut event_rx: UnboundedReceiver, - conn: dim_database::DbConnection, -) -> impl warp::Filter + Clone { - let (i_tx, i_rx) = unbounded_channel::>(); - - let _ev = rt_handle.spawn(CtrlEvent::recv_from_rx(i_rx)); - - let forwarder_fut = { - let i_tx = i_tx.clone(); - - async move { - while let Some(st) = event_rx.recv().await { - let _ = i_tx.send(st.into_ctrl_event()); - } - } - }; - - let _forwarder = rt_handle.spawn(forwarder_fut); - - warp::path("ws") - .and(warp::filters::addr::remote()) - .and(routes::global_filters::with_state(i_tx)) - .and(routes::global_filters::with_state(rt_handle)) - .and(warp::ws()) - .and(warp::any().map(move || conn.clone())) - .map( - |addr: Option, - i_tx: UnboundedSender>, - rt_handle: Handle, - ws: warp::ws::Ws, - conn: dim_database::DbConnection| { - ws.on_upgrade(move |websocket| async move { - let addr = match addr { - Some(addr) => addr, - None => return, - }; - - let (m_tx, mut m_rx) = unbounded_channel::<(SocketAddr, Message)>(); - let (ws_tx, mut ws_rx) = websocket.split(); - - 'auth_loop: while let Some(Ok(x)) = ws_rx.next().await { - if x.is_text() { - if let Ok(ClientActions::Authenticate { token }) = - serde_json::from_slice(x.as_bytes()) - { - if let Ok(token_data) = - dim_database::user::Login::verify_cookie(token) - { - if let Ok(mut tx) = conn.read().begin().await { - if let Ok(u) = - dim_database::user::User::get_by_id(&mut tx, token_data) - .await - { - let _ = i_tx.send(CtrlEvent::Track { - addr, - sink: ws_tx, - auth: Box::new(u), - }); - - let _ = i_tx.send(CtrlEvent::SendTo { - addr, - message: dim_events::Message { - id: -1, - event_type: - dim_events::PushEventType::EventAuthOk, - } - .to_string(), - }); - - break 'auth_loop; - } - } - } - } - - let _ = i_tx.send(CtrlEvent::SendTo { - addr, - message: dim_events::Message { - id: -1, - event_type: dim_events::PushEventType::EventAuthErr, - } - .to_string(), - }); - } - } - - let m_tx = m_tx.clone(); - - rt_handle.spawn(async move { - while let Some(Ok(message)) = ws_rx.next().await { - if m_tx.send((addr, message)).is_err() { - break; - } - } - - i_tx.send(CtrlEvent::Forget { addr }) - }); - - 'outer: loop { - tokio::select! { - biased; - _ = tokio::signal::ctrl_c() => { - break 'outer; - } - - message = m_rx.recv() => { - let (_addr, _message) = match message { - Some(p) => p, - None => break 'outer, - }; - } - - else => break 'outer, - } - } - - tokio::task::yield_now().await; - }) - }, - ) -}