From 7ea0633e527d47ff5327f4faaf40a8cda1d50364 Mon Sep 17 00:00:00 2001 From: Pavel Kirilin Date: Mon, 20 Nov 2023 10:28:43 +0100 Subject: [PATCH 1/9] Rustus has been rewritten from scratch (#145) --- .github/workflows/release.yml | 2 +- .github/workflows/test.yml | 38 +- .gitignore | 2 + .pre-commit-config.yaml | 14 +- .rustfmt.toml | 2 + Cargo.lock | 3577 +++++------------ Cargo.toml | 181 +- README.md | 43 +- deploy/Dockerfile | 4 +- docker-compose.yml | 27 + docs/configuration.md | 51 +- rust-toolchain.toml | 1 + src/config.rs | 334 +- .../storage.rs => data_storage/base.rs} | 27 +- src/data_storage/impls/file_storage.rs | 182 + src/data_storage/impls/mod.rs | 2 + .../impls/s3_hybrid.rs} | 69 +- src/data_storage/mod.rs | 159 + src/errors.rs | 72 +- src/extensions.rs | 19 + .../{models/info_store.rs => base.rs} | 12 +- src/info_storages/db_info_storage.rs | 144 - src/info_storages/file_info_storage.rs | 175 - src/info_storages/impls/file_info_storage.rs | 74 + src/info_storages/impls/mod.rs | 2 + src/info_storages/impls/redis_info_storage.rs | 101 + src/info_storages/mod.rs | 96 +- .../models/available_info_storages.rs | 70 - src/info_storages/models/mod.rs | 3 - src/info_storages/redis_info_storage.rs | 151 - src/main.rs | 334 +- src/metrics.rs | 61 - src/{info_storages => }/models/file_info.rs | 42 +- src/models/mod.rs | 1 + src/notifiers/amqp_notifier.rs | 314 -- src/notifiers/{models/notifier.rs => base.rs} | 12 +- src/notifiers/dir_notifier.rs | 105 - src/notifiers/file_notifier.rs | 123 - src/notifiers/hooks.rs | 20 + src/notifiers/http_notifier.rs | 171 - src/notifiers/impls/amqp_notifier.rs | 191 + src/notifiers/impls/dir_notifier.rs | 50 + src/notifiers/impls/file_notifier.rs | 45 + src/notifiers/impls/http_notifier.rs | 81 + src/notifiers/impls/mod.rs | 4 + src/notifiers/manager.rs | 99 + src/notifiers/mod.rs | 46 +- src/notifiers/models/hooks.rs | 22 - src/notifiers/models/message_format.rs | 167 - src/notifiers/models/mod.rs | 4 - src/notifiers/models/notification_manager.rs | 85 - src/notifiers/serializer.rs | 174 + src/protocol/core/get_info.rs | 240 -- src/protocol/core/mod.rs | 44 - src/protocol/core/server_info.rs | 55 - src/protocol/core/write_bytes.rs | 432 -- src/protocol/creation/mod.rs | 18 - src/protocol/creation/routes.rs | 584 --- src/protocol/extensions.rs | 25 - src/protocol/getting/mod.rs | 20 - src/protocol/getting/routes.rs | 75 - src/protocol/mod.rs | 32 - src/protocol/termination/mod.rs | 18 - src/protocol/termination/routes.rs | 113 - src/routes.rs | 17 - src/server.rs | 45 - src/server/cors.rs | 72 + src/server/mod.rs | 160 + src/server/routes/create.rs | 224 ++ src/server/routes/delete.rs | 90 + src/server/routes/file_info.rs | 54 + src/server/routes/get_file.rs | 34 + src/server/routes/info.rs | 34 + src/server/routes/mod.rs | 6 + src/server/routes/upload.rs | 158 + src/state.rs | 103 +- src/storages/file_storage.rs | 355 -- src/storages/mod.rs | 5 - src/storages/models/available_stores.rs | 86 - src/storages/models/mod.rs | 2 - src/utils/dir_struct.rs | 2 + src/utils/enums.rs | 34 +- src/utils/hashes.rs | 6 +- src/utils/headers.rs | 190 +- src/utils/lapin_pool.rs | 63 + src/utils/mod.rs | 2 + src/utils/result.rs | 53 + 87 files changed, 3887 insertions(+), 7349 deletions(-) create mode 100644 .rustfmt.toml create mode 100644 docker-compose.yml create mode 100644 rust-toolchain.toml rename src/{storages/models/storage.rs => data_storage/base.rs} (79%) create mode 100644 src/data_storage/impls/file_storage.rs create mode 100644 src/data_storage/impls/mod.rs rename src/{storages/s3_hybrid_storage.rs => data_storage/impls/s3_hybrid.rs} (77%) create mode 100644 src/data_storage/mod.rs create mode 100644 src/extensions.rs rename src/info_storages/{models/info_store.rs => base.rs} (82%) delete mode 100644 src/info_storages/db_info_storage.rs delete mode 100644 src/info_storages/file_info_storage.rs create mode 100644 src/info_storages/impls/file_info_storage.rs create mode 100644 src/info_storages/impls/mod.rs create mode 100644 src/info_storages/impls/redis_info_storage.rs delete mode 100644 src/info_storages/models/available_info_storages.rs delete mode 100644 src/info_storages/models/mod.rs delete mode 100644 src/info_storages/redis_info_storage.rs delete mode 100644 src/metrics.rs rename src/{info_storages => }/models/file_info.rs (71%) create mode 100644 src/models/mod.rs delete mode 100644 src/notifiers/amqp_notifier.rs rename src/notifiers/{models/notifier.rs => base.rs} (52%) delete mode 100644 src/notifiers/dir_notifier.rs delete mode 100644 src/notifiers/file_notifier.rs create mode 100644 src/notifiers/hooks.rs delete mode 100644 src/notifiers/http_notifier.rs create mode 100644 src/notifiers/impls/amqp_notifier.rs create mode 100644 src/notifiers/impls/dir_notifier.rs create mode 100644 src/notifiers/impls/file_notifier.rs create mode 100644 src/notifiers/impls/http_notifier.rs create mode 100644 src/notifiers/impls/mod.rs create mode 100644 src/notifiers/manager.rs delete mode 100644 src/notifiers/models/hooks.rs delete mode 100644 src/notifiers/models/message_format.rs delete mode 100644 src/notifiers/models/mod.rs delete mode 100644 src/notifiers/models/notification_manager.rs create mode 100644 src/notifiers/serializer.rs delete mode 100644 src/protocol/core/get_info.rs delete mode 100644 src/protocol/core/mod.rs delete mode 100644 src/protocol/core/server_info.rs delete mode 100644 src/protocol/core/write_bytes.rs delete mode 100644 src/protocol/creation/mod.rs delete mode 100644 src/protocol/creation/routes.rs delete mode 100644 src/protocol/extensions.rs delete mode 100644 src/protocol/getting/mod.rs delete mode 100644 src/protocol/getting/routes.rs delete mode 100644 src/protocol/mod.rs delete mode 100644 src/protocol/termination/mod.rs delete mode 100644 src/protocol/termination/routes.rs delete mode 100644 src/routes.rs delete mode 100644 src/server.rs create mode 100644 src/server/cors.rs create mode 100644 src/server/mod.rs create mode 100644 src/server/routes/create.rs create mode 100644 src/server/routes/delete.rs create mode 100644 src/server/routes/file_info.rs create mode 100644 src/server/routes/get_file.rs create mode 100644 src/server/routes/info.rs create mode 100644 src/server/routes/mod.rs create mode 100644 src/server/routes/upload.rs delete mode 100644 src/storages/file_storage.rs delete mode 100644 src/storages/mod.rs delete mode 100644 src/storages/models/available_stores.rs delete mode 100644 src/storages/models/mod.rs create mode 100644 src/utils/lapin_pool.rs create mode 100644 src/utils/result.rs diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 90d28ca..31aec4e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,7 +11,7 @@ jobs: runs-on: ${{ matrix.job.os }} strategy: matrix: - rust: [stable] + rust: [nightly] job: - os: macos-latest os-name: macos diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d839a69..818a98e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,12 +27,12 @@ jobs: - name: Install stable toolchain uses: actions-rs/toolchain@v1 with: - toolchain: stable + toolchain: nightly override: true - name: Adding component run: rustup component add rustfmt - name: Checking code format - run: cargo fmt -- --check --config use_try_shorthand=true,imports_granularity=Crate + run: cargo fmt -- --check code_check: needs: pre_job @@ -43,39 +43,18 @@ jobs: - name: Install stable toolchain uses: actions-rs/toolchain@v1 with: - toolchain: stable + toolchain: nightly override: true - run: rustup component add clippy - uses: actions-rs/clippy-check@v1 with: token: ${{ secrets.GITHUB_TOKEN }} - args: --all-features -p rustus -- -W clippy::all -W clippy::pedantic -D warnings + args: --all-features -p rustus -- -W clippy::all -W clippy::pedantic -D warnings -A clippy::module_name_repetitions tests: needs: pre_job if: ${{ needs.pre_job.outputs.should_skip != 'true' }} runs-on: ubuntu-latest - services: - redis: - image: redis:6.2-alpine3.15 - ports: - - 6379/tcp - pg: - image: postgres:13.1 - ports: - - 5432/tcp - env: - POSTGRES_PASSWORD: "rustus" - POSTGRES_USER: "rustus" - POSTGRES_DB: "rustus" - rabbit: - image: rabbitmq:3.8.27-alpine - ports: - - 5672/tcp - env: - RABBITMQ_DEFAULT_USER: "guest" - RABBITMQ_DEFAULT_PASS: "guest" - RABBITMQ_DEFAULT_VHOST: "/" steps: - uses: actions/checkout@v2 with: @@ -83,11 +62,10 @@ jobs: - name: Install stable toolchain uses: actions-rs/toolchain@v1 with: - toolchain: stable + toolchain: nightly override: true - name: Run tests - run: cargo test --features=all,integration_tests -- --test-threads 1 + run: cargo test -- --test-threads 1 env: - TEST_REDIS_URL: redis://localhost:${{ job.services.redis.ports['6379'] }}/0 - TEST_DB_URL: postgresql://rustus:rustus@localhost:${{ job.services.pg.ports['5432'] }}/rustus - TEST_AMQP_URL: amqp://guest:guest@localhost:${{ job.services.rabbit.ports['5672'] }} + TEST_REDIS_URL: redis://localhost:6479/0 + TEST_AMQP_URL: amqp://guest:guest@localhost:5672/ diff --git a/.gitignore b/.gitignore index cb95e64..852bc78 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ data/ tarpaulin-report.html lcov.info site +.venv/ +.virtualenv/ \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1c35608..5f94262 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -27,7 +27,6 @@ repos: entry: cargo args: - clippy - - --features=all - --all - -p - rustus @@ -38,6 +37,8 @@ repos: - clippy::pedantic - -D - warnings + - -A + - clippy::module_name_repetitions - id: check types: @@ -48,14 +49,3 @@ repos: pass_filenames: false args: - check - - - id: check-all - types: - - rust - name: cargo check all - language: system - entry: cargo - pass_filenames: false - args: - - check - - --features=all diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 0000000..f5e4b58 --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1,2 @@ +use_try_shorthand=true +imports_granularity="Crate" \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index ad03003..443b531 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,243 +2,11 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "actix-codec" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a7559404a7f3573127aab53c08ce37a6c6a315c374a31070f3c91cd1b4a7fe" -dependencies = [ - "bitflags", - "bytes", - "futures-core", - "futures-sink", - "log", - "memchr", - "pin-project-lite", - "tokio", - "tokio-util", -] - -[[package]] -name = "actix-cors" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b340e9cfa5b08690aae90fb61beb44e9b06f44fe3d0f93781aaa58cfba86245e" -dependencies = [ - "actix-utils", - "actix-web", - "derive_more", - "futures-util", - "log", - "once_cell", - "smallvec", -] - -[[package]] -name = "actix-files" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d832782fac6ca7369a70c9ee9a20554623c5e51c76e190ad151780ebea1cf689" -dependencies = [ - "actix-http", - "actix-service", - "actix-utils", - "actix-web", - "askama_escape", - "bitflags", - "bytes", - "derive_more", - "futures-core", - "http-range", - "log", - "mime", - "mime_guess", - "percent-encoding", - "pin-project-lite", -] - -[[package]] -name = "actix-http" -version = "3.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2079246596c18b4a33e274ae10c0e50613f4d32a4198e09c7b93771013fed74" -dependencies = [ - "actix-codec", - "actix-rt", - "actix-service", - "actix-utils", - "ahash 0.8.3", - "base64 0.21.0", - "bitflags", - "brotli", - "bytes", - "bytestring", - "derive_more", - "encoding_rs", - "flate2", - "futures-core", - "h2", - "http", - "httparse", - "httpdate", - "itoa", - "language-tags", - "local-channel", - "mime", - "percent-encoding", - "pin-project-lite", - "rand 0.8.5", - "sha1 0.10.5", - "smallvec", - "tokio", - "tokio-util", - "tracing", - "zstd", -] - -[[package]] -name = "actix-macros" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "465a6172cf69b960917811022d8f29bc0b7fa1398bc4f78b3c466673db1213b6" -dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "actix-router" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66ff4d247d2b160861fa2866457e85706833527840e4133f8f49aa423a38799" -dependencies = [ - "bytestring", - "http", - "regex", - "serde", - "tracing", -] - -[[package]] -name = "actix-rt" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15265b6b8e2347670eb363c47fc8c75208b4a4994b27192f345fcbe707804f3e" -dependencies = [ - "actix-macros", - "futures-core", - "tokio", -] - -[[package]] -name = "actix-server" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e8613a75dd50cc45f473cee3c34d59ed677c0f7b44480ce3b8247d7dc519327" -dependencies = [ - "actix-rt", - "actix-service", - "actix-utils", - "futures-core", - "futures-util", - "mio", - "num_cpus", - "socket2", - "tokio", - "tracing", -] - -[[package]] -name = "actix-service" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a" -dependencies = [ - "futures-core", - "paste", - "pin-project-lite", -] - -[[package]] -name = "actix-utils" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8" -dependencies = [ - "local-waker", - "pin-project-lite", -] - -[[package]] -name = "actix-web" -version = "4.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd3cb42f9566ab176e1ef0b8b3a896529062b4efc6be0123046095914c4c1c96" -dependencies = [ - "actix-codec", - "actix-http", - "actix-macros", - "actix-router", - "actix-rt", - "actix-server", - "actix-service", - "actix-utils", - "actix-web-codegen", - "ahash 0.7.6", - "bytes", - "bytestring", - "cfg-if", - "cookie", - "derive_more", - "encoding_rs", - "futures-core", - "futures-util", - "http", - "itoa", - "language-tags", - "log", - "mime", - "once_cell", - "pin-project-lite", - "regex", - "serde", - "serde_json", - "serde_urlencoded", - "smallvec", - "socket2", - "time 0.3.20", - "url", -] - -[[package]] -name = "actix-web-codegen" -version = "4.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2262160a7ae29e3415554a3f1fc04c764b1540c116aa524683208078b7a75bc9" -dependencies = [ - "actix-router", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "actix-web-prom" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9df3127d20a5d01c9fc9aceb969a38d31a6767e1b48a54d55a8f56c769a84923" -dependencies = [ - "actix-web", - "futures-core", - "pin-project-lite", - "prometheus", -] - [[package]] name = "addr2line" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" dependencies = [ "gimli", ] @@ -251,56 +19,20 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] - -[[package]] -name = "ahash" -version = "0.8.3" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" dependencies = [ - "cfg-if", "getrandom", "once_cell", "version_check", ] -[[package]] -name = "aho-corasick" -version = "0.7.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" -dependencies = [ - "memchr", -] - -[[package]] -name = "alloc-no-stdlib" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" - -[[package]] -name = "alloc-stdlib" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" -dependencies = [ - "alloc-no-stdlib", -] - [[package]] name = "amq-protocol" -version = "7.0.1" +version = "7.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acc7cad07d1b4533fcb46f0819a6126fa201fd0385469aba75e405424f3fe009" +checksum = "1d40d8b2465c7959dd40cee32ba6ac334b5de57e9fca0cc756759894a4152a5d" dependencies = [ "amq-protocol-tcp", "amq-protocol-types", @@ -312,9 +44,9 @@ dependencies = [ [[package]] name = "amq-protocol-tcp" -version = "7.0.1" +version = "7.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d8b20aba8c35a0b885e1e978eff456ced925730a4e012e63e4ff89a1deb602b" +checksum = "9cb2100adae7da61953a2c3a01935d86caae13329fadce3333f524d6d6ce12e2" dependencies = [ "amq-protocol-uri", "tcp-stream", @@ -323,9 +55,9 @@ dependencies = [ [[package]] name = "amq-protocol-types" -version = "7.0.1" +version = "7.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e245e0e9083b6a6db5f8c10013074cb382266eb9e2a37204d19c651b8d3b8114" +checksum = "156ff13c8a3ced600b4e54ed826a2ae6242b6069d00dd98466827cef07d3daff" dependencies = [ "cookie-factory", "nom", @@ -335,15 +67,21 @@ dependencies = [ [[package]] name = "amq-protocol-uri" -version = "7.0.1" +version = "7.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56987108bf48d2eb500cae8896cd9291564eedd8744776ecc5c3338a8b2ca5f8" +checksum = "751bbd7d440576066233e740576f1b31fdc6ab86cfabfbd48c548de77eca73e4" dependencies = [ "amq-protocol-types", "percent-encoding", "url", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -354,39 +92,95 @@ dependencies = [ ] [[package]] -name = "arrayvec" -version = "0.7.2" +name = "anstream" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is-terminal", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" + +[[package]] +name = "anstyle-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +checksum = "c677ab05e09154296dd37acecd46420c17b9713e8366facafa8fc0885167cf4c" +dependencies = [ + "anstyle", + "windows-sys", +] [[package]] -name = "askama_escape" -version = "0.10.3" +name = "arc-swap" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" +checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" [[package]] name = "async-channel" -version = "1.8.0" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", +] + +[[package]] +name = "async-channel" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833" +checksum = "d37875bd9915b7d67c2f117ea2c30a0989874d0b2cb694fe25403c85763c0c9e" dependencies = [ "concurrent-queue", - "event-listener", + "event-listener 3.1.0", + "event-listener-strategy", "futures-core", + "pin-project-lite", ] [[package]] name = "async-executor" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17adb73da160dfb475c183343c8cccd80721ea5a605d3eb57125f0a7b7a92d0b" +checksum = "4b0c4a4f319e45986f347ee47fef8bf5e81c9abc3f6f58dc2391439f30df65f0" dependencies = [ - "async-lock", + "async-lock 2.8.0", "async-task", "concurrent-queue", - "fastrand", - "futures-lite", + "fastrand 2.0.1", + "futures-lite 1.13.0", "slab", ] @@ -396,12 +190,12 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776" dependencies = [ - "async-channel", + "async-channel 1.9.0", "async-executor", "async-io", - "async-lock", + "async-lock 2.8.0", "blocking", - "futures-lite", + "futures-lite 1.13.0", "once_cell", ] @@ -418,31 +212,42 @@ dependencies = [ [[package]] name = "async-io" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c374dda1ed3e7d8f0d9ba58715f924862c63eae6849c92d3a18e7fbde9e2794" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" dependencies = [ - "async-lock", + "async-lock 2.8.0", "autocfg", + "cfg-if", "concurrent-queue", - "futures-lite", - "libc", + "futures-lite 1.13.0", "log", "parking", "polling", + "rustix 0.37.27", "slab", - "socket2", + "socket2 0.4.9", "waker-fn", - "windows-sys 0.42.0", ] [[package]] name = "async-lock" -version = "2.7.0" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +dependencies = [ + "event-listener 2.5.3", +] + +[[package]] +name = "async-lock" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa24f727524730b077666307f2734b4a1a1c57acb79193127dcc8914d5242dd7" +checksum = "deb2ab2aa8a746e221ab826c73f48bc6ba41be6763f0855cb249eb6d154cf1d7" dependencies = [ - "event-listener", + "event-listener 3.1.0", + "event-listener-strategy", + "pin-project-lite", ] [[package]] @@ -459,61 +264,39 @@ dependencies = [ [[package]] name = "async-task" -version = "4.3.0" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524" +checksum = "b4eb2cdb97421e01129ccb49169d8279ed21e829929144f4a22a6e54ac549ca1" [[package]] name = "async-trait" -version = "0.1.66" +version = "0.1.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b84f9ebcc6c1f5b8cb160f6990096a5c127f423fcb6e1ccc46c370cbdfb75dfc" +checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn", -] - -[[package]] -name = "atoi" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616896e05fc0e2649463a93a15183c6a16bf03413a7af88ef1285ddedfa9cda5" -dependencies = [ - "num-traits", + "syn 2.0.28", ] [[package]] name = "atomic-waker" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "debc29dde2e69f9e47506b525f639ed42300fc014a3e007832592448fa8e4599" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "attohttpc" -version = "0.19.1" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "262c3f7f5d61249d8c00e5546e2685cd15ebeeb1bc0f3cc5449350a1cb07319e" +checksum = "1fcf00bc6d5abb29b5f97e3c61a90b6d3caa12f3faf897d4a3e3607c050a35a7" dependencies = [ "http", "log", "native-tls", - "openssl", "serde", "serde_json", "url", - "wildmatch", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", ] [[package]] @@ -524,123 +307,107 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "aws-creds" -version = "0.30.0" +version = "0.34.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aeeee1a5defa63cba39097a510dfe63ef53658fc8995202a610f6a8a4d03639" +checksum = "3776743bb68d4ad02ba30ba8f64373f1be4e082fe47651767171ce75bb2f6cf5" dependencies = [ "attohttpc", "dirs", + "log", + "quick-xml", "rust-ini", "serde", - "serde-xml-rs", "thiserror", - "time 0.3.20", + "time 0.3.30", "url", ] [[package]] name = "aws-region" -version = "0.25.1" +version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92a8af5850d0ea0916ca3e015ab86951ded0bf4b70fd27896e81ae1dfb0af37" +checksum = "42fed2b9fca70f2908268d057a607f2a906f47edbf856ea8587de9038d264e22" dependencies = [ "thiserror", ] [[package]] -name = "backtrace" -version = "0.3.67" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "base-x" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" - -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "base64" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" - -[[package]] -name = "base64ct" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" - -[[package]] -name = "bb8" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1627eccf3aa91405435ba240be23513eeca466b5dc33866422672264de061582" +name = "axum" +version = "0.6.16" +source = "git+https://github.com/tokio-rs/axum.git?rev=3ff45d9#3ff45d9c96b5192af6b6ec26eb2a2bfcddd00d7d" dependencies = [ "async-trait", - "futures-channel", + "axum-core", + "bytes", "futures-util", - "parking_lot 0.12.1", + "http", + "http-body 0.4.5", + "hyper 0.14.27", + "hyper 1.0.0-rc.4", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper", "tokio", + "tower", + "tower-hyper-http-body-compat", + "tower-layer", + "tower-service", ] [[package]] -name = "bb8-lapin" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5441692a6e0820dd92853f61ab61dd3a44681d3606a4fbefe67cfdad7093a0c9" +name = "axum-core" +version = "0.3.4" +source = "git+https://github.com/tokio-rs/axum.git?rev=3ff45d9#3ff45d9c96b5192af6b6ec26eb2a2bfcddd00d7d" dependencies = [ "async-trait", - "bb8", - "lapin", + "bytes", + "futures-util", + "http", + "http-body 0.4.5", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper", + "tower-layer", + "tower-service", ] [[package]] -name = "bb8-redis" -version = "0.12.0" +name = "backtrace" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8310da711a26fa0326202261abd73a414340f3ec957f63927a055511a01d7fb2" +checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" dependencies = [ - "async-trait", - "bb8", - "redis", + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", ] [[package]] -name = "bigdecimal" -version = "0.2.2" +name = "base64" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1e50562e37200edf7c6c43e54a08e64a5553bfb59d9c297d5572512aa517256" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", - "serde", -] +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] -name = "bit-vec" -version = "0.6.3" +name = "base64" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" -dependencies = [ - "serde", -] +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] name = "bitflags" @@ -648,6 +415,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + [[package]] name = "block-buffer" version = "0.10.4" @@ -659,152 +432,40 @@ dependencies = [ [[package]] name = "block-padding" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a90ec2df9600c28a01c56c4784c9207a96d2451833aeceb8cc97e4c9548bb78" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" dependencies = [ "generic-array", ] [[package]] name = "blocking" -version = "1.3.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c67b173a56acffd6d2326fb7ab938ba0b00a71480e14902b2591c87bc5741e8" +checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118" dependencies = [ - "async-channel", - "async-lock", + "async-channel 2.1.0", + "async-lock 3.1.0", "async-task", - "atomic-waker", - "fastrand", - "futures-lite", -] - -[[package]] -name = "borsh" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40f9ca3698b2e4cb7c15571db0abc5551dca417a21ae8140460b50309bb2cc62" -dependencies = [ - "borsh-derive", - "hashbrown 0.13.2", -] - -[[package]] -name = "borsh-derive" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "598b3eacc6db9c3ee57b22707ad8f6a8d2f6d442bfe24ffeb8cbb70ca59e6a35" -dependencies = [ - "borsh-derive-internal", - "borsh-schema-derive-internal", - "proc-macro-crate", - "proc-macro2", - "syn", -] - -[[package]] -name = "borsh-derive-internal" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186b734fa1c9f6743e90c95d7233c9faab6360d1a96d4ffa19d9cfd1e9350f8a" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "borsh-schema-derive-internal" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99b7ff1008316626f485991b960ade129253d4034014616b94f309a15366cc49" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "brotli" -version = "3.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor", -] - -[[package]] -name = "brotli-decompressor" -version = "2.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -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", + "fastrand 2.0.1", + "futures-io", + "futures-lite 2.0.1", + "piper", + "tracing", ] [[package]] name = "bumpalo" -version = "3.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" - -[[package]] -name = "bytecheck" -version = "0.6.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13fe11640a23eb24562225322cd3e452b93a3d4091d62fab69c70542fcd17d1f" -dependencies = [ - "bytecheck_derive", - "ptr_meta", - "simdutf8", -] - -[[package]] -name = "bytecheck_derive" -version = "0.6.10" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e31225543cb46f81a7e224762764f4a6a0f097b1db0b175f69e8065efaa42de5" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" [[package]] name = "bytes" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" - -[[package]] -name = "bytestring" -version = "1.3.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "238e4886760d98c4f899360c834fa93e62cf7f721ac3c2da375cbdf4b8679aae" -dependencies = [ - "bytes", -] +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cbc" @@ -817,11 +478,11 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.79" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01" dependencies = [ - "jobserver", + "libc", ] [[package]] @@ -832,13 +493,13 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.24" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" +checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" dependencies = [ + "android-tzdata", "iana-time-zone", "js-sys", - "num-integer", "num-traits", "serde", "time 0.1.45", @@ -847,329 +508,154 @@ dependencies = [ ] [[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", -] - -[[package]] -name = "clap" -version = "3.2.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" -dependencies = [ - "atty", - "bitflags", - "clap_lex 0.2.4", - "indexmap", - "strsim", - "termcolor", - "textwrap", -] - -[[package]] -name = "clap" -version = "4.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d7ae14b20b94cb02149ed21a86c423859cbe18dc7ed69845cace50e52b40a5" -dependencies = [ - "bitflags", - "clap_derive", - "clap_lex 0.3.2", - "is-terminal", - "once_cell", - "strsim", - "termcolor", -] - -[[package]] -name = "clap_derive" -version = "4.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44bec8e5c9d09e439c4335b1af0abaab56dcf3b94999a936e1bb47b9134288f0" -dependencies = [ - "heck", - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "clap_lex" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" -dependencies = [ - "os_str_bytes", -] - -[[package]] -name = "clap_lex" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "350b9cf31731f9957399229e9b2adc51eeabdfbe9d71d9a0552275fd12710d09" -dependencies = [ - "os_str_bytes", -] - -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] - -[[package]] -name = "colored" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" -dependencies = [ - "atty", - "lazy_static", - "winapi", -] - -[[package]] -name = "combine" -version = "4.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" -dependencies = [ - "bytes", - "futures-core", - "memchr", - "pin-project-lite", - "tokio", - "tokio-util", -] - -[[package]] -name = "concurrent-queue" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c278839b831783b70278b14df4d45e1beb1aad306c07bb796637de9a0e323e8e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "const-oid" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" - -[[package]] -name = "const_fn" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbdcdcb6d86f71c5e97409ad45898af11cbc995b4ee8112d59095a28d376c935" - -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - -[[package]] -name = "cookie" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" -dependencies = [ - "percent-encoding", - "time 0.3.20", - "version_check", -] - -[[package]] -name = "cookie-factory" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396de984970346b0d9e93d1415082923c679e5ae5c3ee3dcbd104f5610af126b" - -[[package]] -name = "core-foundation" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" - -[[package]] -name = "cpufeatures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" -dependencies = [ - "libc", -] - -[[package]] -name = "crc" -version = "2.1.0" +name = "cipher" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49fc9a695bca7f35f5f4c15cddc84415f66a74ea78eef08e90c5024f2b540e23" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "crc-catalog", + "crypto-common", + "inout", ] [[package]] -name = "crc-catalog" -version = "1.1.1" +name = "clap" +version = "4.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccaeedb56da03b09f598226e25e80088cb4cd25f316e6e4df7d695f0feeb1403" +checksum = "c27cdf28c0f604ba3f512b0c9a409f8de8513e4816705deb0498b627e7c3a3fd" +dependencies = [ + "clap_builder", + "clap_derive", + "once_cell", +] [[package]] -name = "crc32fast" -version = "1.3.2" +name = "clap_builder" +version = "4.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "08a9f1ab5e9f01a9b81f202e8562eb9a10de70abf9eaeac1be465c28b75aa4aa" dependencies = [ - "cfg-if", + "anstream", + "anstyle", + "clap_lex", + "strsim", ] [[package]] -name = "crossbeam-channel" -version = "0.5.7" +name = "clap_derive" +version = "4.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c" +checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050" dependencies = [ - "cfg-if", - "crossbeam-utils", + "heck", + "proc-macro2", + "quote", + "syn 2.0.28", ] [[package]] -name = "crossbeam-queue" -version = "0.3.8" +name = "clap_lex" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] +checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" [[package]] -name = "crossbeam-utils" -version = "0.8.15" +name = "colorchoice" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" -dependencies = [ - "cfg-if", -] +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] -name = "crypto-bigint" -version = "0.3.2" +name = "colored" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" +checksum = "5a5f741c91823341bebf717d4c71bda820630ce065443b58bd1b7451af008355" dependencies = [ - "generic-array", - "subtle", + "is-terminal", + "lazy_static", + "winapi", ] [[package]] -name = "crypto-common" -version = "0.1.6" +name = "combine" +version = "4.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" dependencies = [ - "generic-array", - "typenum", + "bytes", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", + "tokio-util", ] [[package]] -name = "cxx" -version = "1.0.92" +name = "concurrent-queue" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a140f260e6f3f79013b8bfc65e7ce630c9ab4388c6a89c71e07226f49487b72" +checksum = "f057a694a54f12365049b0958a1685bb52d567f5593b355fbf685838e873d400" dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", + "crossbeam-utils", ] [[package]] -name = "cxx-build" -version = "1.0.92" +name = "cookie-factory" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396de984970346b0d9e93d1415082923c679e5ae5c3ee3dcbd104f5610af126b" + +[[package]] +name = "core-foundation" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da6383f459341ea689374bf0a42979739dc421874f112ff26f829b8040b8e613" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn", + "core-foundation-sys", + "libc", ] [[package]] -name = "cxxbridge-flags" -version = "1.0.92" +name = "core-foundation-sys" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90201c1a650e95ccff1c8c0bb5a343213bdd317c6e600a93075bca2eff54ec97" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] -name = "cxxbridge-macro" -version = "1.0.92" +name = "cpufeatures" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b75aed41bb2e6367cae39e6326ef817a851db13c13e4f3263714ca3cfb8de56" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" dependencies = [ - "proc-macro2", - "quote", - "syn", + "libc", ] [[package]] -name = "debugid" -version = "0.8.0" +name = "crossbeam-utils" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ - "serde", - "uuid 1.3.0", + "cfg-if", ] [[package]] -name = "der" -version = "0.5.1" +name = "crypto-common" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "const-oid", - "crypto-bigint", - "pem-rfc7468", + "generic-array", + "typenum", ] [[package]] -name = "derive_more" -version = "0.99.17" +name = "deranged" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version 0.4.0", - "syn", + "powerfmt", + "serde", ] [[package]] @@ -1183,9 +669,9 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", @@ -1212,12 +698,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "discard" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" - [[package]] name = "dlv-list" version = "0.3.0" @@ -1231,47 +711,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" [[package]] -name = "dotenvy" -version = "0.15.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d8c417d7a8cb362e0c37e5d815f5eb7c37f79ff93707329d5a194e42e54ca0" -dependencies = [ - "clap 3.2.23", -] - -[[package]] -name = "dyn-clone" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30" - -[[package]] -name = "either" -version = "1.8.1" +name = "encoding_rs" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ - "serde", + "cfg-if", ] [[package]] -name = "encoding_rs" -version = "0.8.32" +name = "enum_dispatch" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +checksum = "8f33313078bb8d4d05a2733a94ac4c2d8a0df9a2b84424ebf4f33bfc224a890e" dependencies = [ - "cfg-if", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.28", ] [[package]] name = "errno" -version = "0.2.8" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" dependencies = [ "errno-dragonfly", "libc", - "winapi", + "windows-sys", ] [[package]] @@ -1290,6 +758,27 @@ version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +[[package]] +name = "event-listener" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96b852f1345da36d551b9473fa1e2b1eb5c5195585c6c018118bc92a8d91160" +dependencies = [ + "event-listener 3.1.0", + "pin-project-lite", +] + [[package]] name = "executor-trait" version = "2.1.0" @@ -1309,35 +798,20 @@ dependencies = [ ] [[package]] -name = "fern" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bdd7b0849075e79ee9a1836df22c717d1eba30451796fdc631b04565dd11e2a" -dependencies = [ - "colored", - "log", -] - -[[package]] -name = "findshlibs" -version = "0.10.2" +name = "fastrand" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40b9e59cd0f7e0806cca4be089683ecb6434e602038df21fe6bf6711b2f07f64" -dependencies = [ - "cc", - "lazy_static", - "libc", - "winapi", -] +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] -name = "flate2" -version = "1.0.25" +name = "fern" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" +checksum = "d9f0c14694cbd524c8720dd69b0e3179344f04ebb5f90f2e4a440c6ea3b2f1ee" dependencies = [ - "crc32fast", - "miniz_oxide", + "chrono", + "colored", + "log", ] [[package]] @@ -1349,7 +823,16 @@ dependencies = [ "futures-core", "futures-sink", "pin-project", - "spin 0.9.5", + "spin", +] + +[[package]] +name = "flume" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +dependencies = [ + "spin", ] [[package]] @@ -1375,24 +858,18 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" dependencies = [ "percent-encoding", ] -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" - [[package]] name = "futures" -version = "0.3.27" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "531ac96c6ff5fd7c62263c5e3c67a603af4fcaee2e1a0ae5565ba3a11e69e549" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" dependencies = [ "futures-channel", "futures-core", @@ -1405,9 +882,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.27" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "164713a5a0dcc3e7b4b1ed7d3b433cabc18025386f9339346e8daf15963cf7ac" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" dependencies = [ "futures-core", "futures-sink", @@ -1415,45 +892,34 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.27" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86d7a0c1aa76363dac491de0ee99faf6941128376f1cf96f07db7603b7de69dd" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" [[package]] name = "futures-executor" -version = "0.3.27" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1997dd9df74cdac935c76252744c1ed5794fac083242ea4fe77ef3ed60ba0f83" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" dependencies = [ "futures-core", "futures-task", "futures-util", ] -[[package]] -name = "futures-intrusive" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a604f7a68fbf8103337523b1fadc8ade7361ee3f112f7c680ad179651616aed5" -dependencies = [ - "futures-core", - "lock_api", - "parking_lot 0.11.2", -] - [[package]] name = "futures-io" -version = "0.3.27" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d422fa3cbe3b40dca574ab087abb5bc98258ea57eea3fd6f1fa7162c778b91" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" [[package]] name = "futures-lite" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" dependencies = [ - "fastrand", + "fastrand 1.9.0", "futures-core", "futures-io", "memchr", @@ -1462,34 +928,50 @@ dependencies = [ "waker-fn", ] +[[package]] +name = "futures-lite" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3831c2651acb5177cbd83943f3d9c8912c5ad03c76afcc0e9511ba568ec5ebb" +dependencies = [ + "futures-core", + "pin-project-lite", +] + [[package]] name = "futures-macro" -version = "0.3.27" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eb14ed937631bd8b8b8977f2c198443447a8355b6e3ca599f38c975e5a963b6" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.28", ] [[package]] name = "futures-sink" -version = "0.3.27" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec93083a4aecafb2a80a885c9de1f0ccae9dbd32c2bb54b0c3a65690e0b8d2f2" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" [[package]] name = "futures-task" -version = "0.3.27" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd65540d33b37b16542a0438c12e6aeead10d4ac5d05bd3f805b8f35ab592879" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" + +[[package]] +name = "futures-timer" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.27" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ef6b17e481503ec85211fed8f39d1970f128935ca1f814cd32ac4a6842e84ab" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ "futures-channel", "futures-core", @@ -1505,9 +987,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.6" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -1515,9 +997,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", @@ -1526,15 +1008,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.2" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" [[package]] name = "h2" -version = "0.3.16" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be7b54589b581f624f566bf5d8eb2bab1db736c51528720b6bd36b96b55924d" +checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" dependencies = [ "bytes", "fnv", @@ -1549,40 +1031,13 @@ dependencies = [ "tracing", ] -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" -dependencies = [ - "ahash 0.7.6", -] - [[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash 0.7.6", -] - -[[package]] -name = "hashbrown" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" -dependencies = [ - "ahash 0.8.3", -] - -[[package]] -name = "hashlink" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf" -dependencies = [ - "hashbrown 0.11.2", + "ahash", ] [[package]] @@ -1593,27 +1048,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -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" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" [[package]] name = "hex" @@ -1621,54 +1058,20 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hkdf" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" -dependencies = [ - "hmac", -] - [[package]] name = "hmac" version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "hostname" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" -dependencies = [ - "libc", - "match_cfg", - "winapi", -] - -[[package]] -name = "html_parser" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec016cabcf7c9c48f9d5fdc6b03f273585bfce640a0f47a69552039e92b1959a" -dependencies = [ - "pest", - "pest_derive", - "serde", - "serde_derive", - "serde_json", - "thiserror", +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", ] [[package]] name = "http" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ "bytes", "fnv", @@ -1687,10 +1090,20 @@ dependencies = [ ] [[package]] -name = "http-range" -version = "0.1.5" +name = "http-body" +version = "1.0.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "951dfc2e32ac02d67c90c0d65bd27009a635dc9b381a2cc7d284ab01e3a0150d" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-range-header" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573" +checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" [[package]] name = "httparse" @@ -1700,52 +1113,51 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] -name = "httptest" -version = "0.15.4" +name = "hyper" +version = "0.14.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f25cfb6def593d43fae1ead24861f217e93bc70768a45cc149a69b5f049df4" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" dependencies = [ - "bstr", "bytes", - "crossbeam-channel", - "form_urlencoded", - "futures", + "futures-channel", + "futures-core", + "futures-util", + "h2", "http", - "hyper", - "log", - "once_cell", - "regex", - "serde", - "serde_json", - "serde_urlencoded", + "http-body 0.4.5", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.4.9", "tokio", + "tower-service", + "tracing", + "want", ] [[package]] name = "hyper" -version = "0.14.25" +version = "1.0.0-rc.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc5e554ff619822309ffd57d8734d77cd5ce6238bc956f037ea06c58238c9899" +checksum = "d280a71f348bcc670fc55b02b63c53a04ac0bf2daff2980795aeaf53edae10e6" dependencies = [ "bytes", "futures-channel", - "futures-core", "futures-util", "h2", "http", - "http-body", + "http-body 1.0.0-rc.2", "httparse", "httpdate", "itoa", "pin-project-lite", - "socket2", "tokio", - "tower-service", "tracing", "want", ] @@ -1757,41 +1169,60 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper", + "hyper 0.14.27", "native-tls", "tokio", "tokio-native-tls", ] +[[package]] +name = "hyper-util" +version = "0.0.0" +source = "git+https://github.com/hyperium/hyper-util?rev=d97181a#d97181a278d9c59f1d7f2713732e400440861216" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body 1.0.0-rc.2", + "hyper 1.0.0-rc.4", + "once_cell", + "pin-project-lite", + "socket2 0.5.3", + "tokio", + "tower", + "tower-service", + "tracing", +] + [[package]] name = "iana-time-zone" -version = "0.1.53" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" +checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "winapi", + "windows", ] [[package]] name = "iana-time-zone-haiku" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ - "cxx", - "cxx-build", + "cc", ] [[package]] name = "idna" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -1799,12 +1230,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown 0.12.3", + "hashbrown", ] [[package]] @@ -1828,95 +1259,62 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.6" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfa919a82ea574332e2de6e74b4c36e74d41982b335080fa59d4ef31be20fdf3" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ + "hermit-abi", "libc", - "windows-sys 0.45.0", + "windows-sys", ] [[package]] name = "ipnet" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" - -[[package]] -name = "ipnetwork" -version = "0.17.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02c3eaab3ac0ede60ffa41add21970a7df7d91772c03383aac6c2c3d53cc716b" -dependencies = [ - "serde", -] +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "is-terminal" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857" -dependencies = [ - "hermit-abi 0.3.1", - "io-lifetimes", - "rustix", - "windows-sys 0.45.0", -] - -[[package]] -name = "itertools" -version = "0.10.5" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ - "either", + "hermit-abi", + "rustix 0.38.8", + "windows-sys", ] [[package]] name = "itoa" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" - -[[package]] -name = "jobserver" -version = "0.1.26" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" -dependencies = [ - "libc", -] +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "js-sys" -version = "0.3.61" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" dependencies = [ "wasm-bindgen", ] -[[package]] -name = "language-tags" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" - [[package]] name = "lapin" -version = "2.1.1" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd03ea5831b44775e296239a64851e2fd14a80a363d202ba147009ffc994ff0f" +checksum = "5f3067a1fcfbc3fc46455809c023e69b8f6602463201010f4ae5a3b572adb9dc" dependencies = [ "amq-protocol", "async-global-executor-trait", "async-reactor-trait", "async-trait", "executor-trait", - "flume", + "flume 0.10.14", "futures-core", "futures-io", - "parking_lot 0.12.1", + "parking_lot", "pinky-swear", "reactor-trait", "serde", @@ -1929,81 +1327,51 @@ name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -dependencies = [ - "spin 0.5.2", -] [[package]] name = "libc" -version = "0.2.140" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" - -[[package]] -name = "libm" -version = "0.2.6" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libmimalloc-sys" -version = "0.1.30" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8c7cbf8b89019683667e347572e6d55a7df7ea36b0c4ce69961b0cde67b174" +checksum = "3979b5c37ece694f1f5e51e7ecc871fdb0f517ed04ee45f88d15d6d553cb9664" dependencies = [ "cc", "libc", ] [[package]] -name = "libsqlite3-sys" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "898745e570c7d0453cc1fbc4a701eb6c662ed54e8fec8b7d14be137ebeeb9d14" -dependencies = [ - "cc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "link-cplusplus" -version = "1.0.8" +name = "libredox" +version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" dependencies = [ - "cc", + "bitflags 2.4.0", + "libc", + "redox_syscall 0.4.1", ] [[package]] name = "linux-raw-sys" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" - -[[package]] -name = "local-channel" -version = "0.1.3" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f303ec0e94c6c54447f84f3b0ef7af769858a9c4ef56ef2a986d3dcd4c3fc9c" -dependencies = [ - "futures-core", - "futures-sink", - "futures-util", - "local-waker", -] +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] -name = "local-waker" -version = "0.1.3" +name = "linux-raw-sys" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e34f76eb3611940e0e7d53a9aaa4e6a3151f69541a282fd0dad5571420c53ff1" +checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", @@ -2011,18 +1379,15 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] -name = "match_cfg" -version = "0.1.0" +name = "matchit" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" +checksum = "ed1202b2a6f884ae56f04cff409ab315c5ce26b5e58d7412e484f01fd52f52ef" [[package]] name = "maybe-async" @@ -2032,15 +1397,16 @@ checksum = "0f1b8c13cb1f814b634a96b2c725449fe7ed464a7b8781de8688be5ffbd3f305" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "md-5" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ + "cfg-if", "digest", ] @@ -2056,11 +1422,32 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "metrics" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e52eb6380b6d2a10eb3434aec0885374490f5b82c8aaf5cd487a183c98be834" +dependencies = [ + "ahash", + "metrics-macros", +] + +[[package]] +name = "metrics-macros" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49e30813093f757be5cf21e50389a24dc7dbb22c49f23b7e8f51d69b508a5ffa" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "mimalloc" -version = "0.1.34" +version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dcb174b18635f7561a0c6c9fc2ce57218ac7523cf72c50af80e2d79ab8f3ba1" +checksum = "fa01922b5ea280a911e323e4d2fd24b7fe5cc4042e0d2cda3c40775cdc4bdc9c" dependencies = [ "libmimalloc-sys", ] @@ -2083,9 +1470,9 @@ dependencies = [ [[package]] name = "minidom" -version = "0.15.1" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e9ce45d459e358790a285e7609ff5ae4cfab88b75f237e8838e62029dda397b" +checksum = "f45614075738ce1b77a1768912a60c0227525971b03e09122a05b8a34a2a6278" dependencies = [ "rxml", ] @@ -2098,23 +1485,41 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.6.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", - "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.45.0", + "windows-sys", +] + +[[package]] +name = "mobc" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90eb49dc5d193287ff80e72a86f34cfb27aae562299d22fea215e06ea1059dd3" +dependencies = [ + "async-trait", + "futures-channel", + "futures-core", + "futures-timer", + "futures-util", + "log", + "metrics", + "thiserror", + "tokio", + "tracing", + "tracing-subscriber", ] [[package]] @@ -2146,96 +1551,56 @@ dependencies = [ ] [[package]] -name = "num-bigint" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-bigint-dig" -version = "0.8.2" +name = "nu-ansi-term" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2399c9463abc5f909349d8aa9ba080e0b88b3ce2885389b60b993f39b1a56905" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" dependencies = [ - "byteorder", - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits", - "rand 0.8.5", - "smallvec", - "zeroize", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", + "overload", + "winapi", ] [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", - "libm", ] [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi", "libc", ] [[package]] name = "object" -version = "0.30.3" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "openssl" -version = "0.10.45" +version = "0.10.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b102428fd03bc5edf97f62620f7298614c45cedf287c271e7ed450bbaf83f2e1" +checksum = "7a257ad03cd8fb16ad4172fedf8094451e1af1c4b70097636ef2eac9a5f0cc33" dependencies = [ - "bitflags", + "bitflags 2.4.0", "cfg-if", "foreign-types", "libc", @@ -2246,13 +1611,13 @@ dependencies = [ [[package]] name = "openssl-macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.28", ] [[package]] @@ -2261,25 +1626,14 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" -[[package]] -name = "openssl-src" -version = "111.25.1+1.1.1t" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ef9a9cc6ea7d9d5e7c4a913dc4b48d0e359eddf01af1dfec96ba7064b4aba10" -dependencies = [ - "cc", -] - [[package]] name = "openssl-sys" -version = "0.9.80" +version = "0.9.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23bbbf7854cd45b83958ebe919f0e8e516793727652e27fda10a8384cfc790b7" +checksum = "40a4130519a360279579c2053038317e40eff64d13fd3f004f9e1b72b8a6aaf9" dependencies = [ - "autocfg", "cc", "libc", - "openssl-src", "pkg-config", "vcpkg", ] @@ -2291,25 +1645,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a" dependencies = [ "dlv-list", - "hashbrown 0.12.3", -] - -[[package]] -name = "os_info" -version = "3.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c424bc68d15e0778838ac013b5b3449544d8133633d8016319e7e05a820b8c0" -dependencies = [ - "log", - "serde", - "winapi", + "hashbrown", ] [[package]] -name = "os_str_bytes" -version = "6.4.1" +name = "overload" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "p12" @@ -2324,154 +1667,70 @@ dependencies = [ "hmac", "lazy_static", "rc2", - "sha1 0.10.5", + "sha1", "yasna", ] [[package]] name = "parking" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" - -[[package]] -name = "parking_lot" -version = "0.11.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" [[package]] name = "parking_lot" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core 0.9.7", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall", - "smallvec", - "winapi", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-sys 0.45.0", -] - -[[package]] -name = "paste" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" - -[[package]] -name = "pem-rfc7468" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01de5d978f34aa4b2296576379fcc416034702fd94117c56ffd8a1a767cefb30" -dependencies = [ - "base64ct", -] - -[[package]] -name = "percent-encoding" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" - -[[package]] -name = "pest" -version = "2.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cbd939b234e95d72bc393d51788aec68aeeb5d51e748ca08ff3aad58cb722f7" -dependencies = [ - "thiserror", - "ucd-trie", -] - -[[package]] -name = "pest_derive" -version = "2.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a81186863f3d0a27340815be8f2078dd8050b14cd71913db9fbda795e5f707d7" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ - "pest", - "pest_generator", + "lock_api", + "parking_lot_core", ] [[package]] -name = "pest_generator" -version = "2.5.6" +name = "parking_lot_core" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75a1ef20bf3193c15ac345acb32e26b3dc3223aff4d77ae4fc5359567683796b" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ - "pest", - "pest_meta", - "proc-macro2", - "quote", - "syn", + "cfg-if", + "libc", + "redox_syscall 0.4.1", + "smallvec", + "windows-targets", ] [[package]] -name = "pest_meta" -version = "2.5.6" +name = "percent-encoding" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e3b284b1f13a20dc5ebc90aff59a51b8d7137c221131b52a7260c08cbc1cc80" -dependencies = [ - "once_cell", - "pest", - "sha2", -] +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pin-project" -version = "1.0.12" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.12" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.28", ] [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" [[package]] name = "pin-utils" @@ -2481,177 +1740,89 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pinky-swear" -version = "6.1.0" +version = "6.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d894b67aa7a4bf295db5e85349078c604edaa6fa5c8721e8eca3c7729a27f2ac" +checksum = "6cfae3ead413ca051a681152bd266438d3bfa301c9bdf836939a14c721bb2a21" dependencies = [ "doc-comment", - "flume", - "parking_lot 0.12.1", + "flume 0.11.0", + "parking_lot", "tracing", ] [[package]] -name = "pkcs1" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a78f66c04ccc83dd4486fd46c33896f4e17b24a7a3a6400dedc48ed0ddd72320" -dependencies = [ - "der", - "pkcs8", - "zeroize", -] - -[[package]] -name = "pkcs8" -version = "0.8.0" +name = "piper" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cabda3fb821068a9a4fab19a683eac3af12edf0f34b94a8be53c4972b8149d0" +checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" dependencies = [ - "der", - "spki", - "zeroize", + "atomic-waker", + "fastrand 2.0.1", + "futures-io", ] [[package]] name = "pkg-config" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "polling" -version = "2.6.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e1f879b2998099c2d69ab9605d145d5b661195627eccc680002c4918a7fb6fa" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" dependencies = [ "autocfg", - "bitflags", + "bitflags 1.3.2", "cfg-if", "concurrent-queue", "libc", "log", "pin-project-lite", - "windows-sys 0.45.0", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "proc-macro-crate" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" -dependencies = [ - "toml", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn", - "version_check", + "windows-sys", ] [[package]] -name = "proc-macro-error-attr" -version = "1.0.4" +name = "powerfmt" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" +name = "ppv-lite86" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.52" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] [[package]] -name = "prometheus" -version = "0.13.3" +name = "quick-xml" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "449811d15fbdf5ceb5c1144416066429cf82316e2ec8ce0c1f6f8a02e7bbcf8c" +checksum = "7f50b1c63b38611e7d4d7f68b82d3ad0cc71a2ad2e7f61fc10f1328d917c93cd" dependencies = [ - "cfg-if", - "fnv", - "lazy_static", "memchr", - "parking_lot 0.12.1", - "protobuf", - "thiserror", -] - -[[package]] -name = "protobuf" -version = "2.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" - -[[package]] -name = "ptr_meta" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" -dependencies = [ - "ptr_meta_derive", -] - -[[package]] -name = "ptr_meta_derive" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" -dependencies = [ - "proc-macro2", - "quote", - "syn", + "serde", ] [[package]] name = "quote" -version = "1.0.25" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5308e8208729c3e1504a6cfad0d5daacc4614c9a2e65d1ea312a34b5cb00fe84" +checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" dependencies = [ "proc-macro2", ] -[[package]] -name = "rand" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" -dependencies = [ - "fuchsia-cprng", - "libc", - "rand_core 0.3.1", - "rdrand", - "winapi", -] - [[package]] name = "rand" version = "0.8.5" @@ -2660,7 +1831,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -2670,24 +1841,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -dependencies = [ - "rand_core 0.4.2", + "rand_core", ] -[[package]] -name = "rand_core" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" - [[package]] name = "rand_core" version = "0.6.4" @@ -2697,107 +1853,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "rbatis" -version = "3.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "457fd9d51f0c9fa7445171c580532c9d5e62a76ed1488e8203fe91c818f89068" -dependencies = [ - "async-trait", - "chrono", - "futures", - "futures-core", - "hex", - "log", - "once_cell", - "rand 0.8.5", - "rbatis-core", - "rbatis-macro-driver", - "rbatis_sql", - "rbson", - "serde", - "uuid 0.8.2", -] - -[[package]] -name = "rbatis-core" -version = "3.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6324adca27a8b4f1fb5e98b8cfd08d91cf3c5007d1c1c24651234004e585123" -dependencies = [ - "base64 0.13.1", - "bigdecimal", - "bit-vec", - "chrono", - "hex", - "ipnetwork", - "lazy_static", - "log", - "rbson", - "serde", - "serde_json", - "sqlx-core", - "time 0.2.27", - "uuid 0.8.2", -] - -[[package]] -name = "rbatis-macro-driver" -version = "3.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c6c87b61272806fbb246e9089c3088e50b7f95126bcab47dc1b053cea6ed2b4" -dependencies = [ - "html_parser", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "rbatis_sql" -version = "3.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db741534547f71bc59590b69c51bf20daa1d4431326bb8377766dc5a32a14ad8" -dependencies = [ - "rbatis_sql_macro", - "rbson", - "serde", -] - -[[package]] -name = "rbatis_sql_macro" -version = "3.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "187141a7d66aea864ac042af881cd0618e4ae11fe86232600c0b172e35741b59" -dependencies = [ - "async-trait", - "base64 0.13.1", - "html_parser", - "proc-macro2", - "quote", - "syn", - "url", -] - -[[package]] -name = "rbson" -version = "2.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bf0ecc799682a85ab76226c1b63fd2ef9dd0a0f5cd21d877b0af44dc8cc2bf" -dependencies = [ - "ahash 0.7.6", - "base64 0.13.1", - "chrono", - "hex", - "indexmap", - "lazy_static", - "rand 0.8.5", - "serde", - "serde_bytes", - "serde_json", - "uuid 0.8.2", -] - [[package]] name = "rc2" version = "0.8.1" @@ -2807,15 +1862,6 @@ dependencies = [ "cipher", ] -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -dependencies = [ - "rand_core 0.3.1", -] - [[package]] name = "reactor-trait" version = "1.1.0" @@ -2829,100 +1875,72 @@ dependencies = [ [[package]] name = "redis" -version = "0.22.3" +version = "0.23.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa8455fa3621f6b41c514946de66ea0531f57ca017b2e6c7cc368035ea5b46df" +checksum = "4f49cdc0bb3f412bf8e7d1bd90fe1d9eb10bc5c399ba90973c14662a27b3f8ba" dependencies = [ + "arc-swap", "async-trait", "bytes", "combine", + "futures", "futures-util", "itoa", "percent-encoding", "pin-project-lite", "ryu", "sha1_smol", + "socket2 0.4.9", "tokio", + "tokio-retry", "tokio-util", "url", ] [[package]] name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_users" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" -dependencies = [ - "getrandom", - "redox_syscall", - "thiserror", -] - -[[package]] -name = "regex" -version = "1.7.1" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", + "bitflags 1.3.2", ] [[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" - -[[package]] -name = "regex-syntax" -version = "0.6.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" - -[[package]] -name = "remove_dir_all" -version = "0.5.3" +name = "redox_syscall" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ - "winapi", + "bitflags 1.3.2", ] [[package]] -name = "rend" -version = "0.4.0" +name = "redox_users" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581008d2099240d37fb08d77ad713bcaec2c4d89d50b5b21a8bb1996bbab68ab" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" dependencies = [ - "bytecheck", + "getrandom", + "libredox", + "thiserror", ] [[package]] name = "reqwest" -version = "0.11.14" +version = "0.11.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21eed90ec8570952d53b772ecf8f206aa1ec9a3d76b2521c56c42973f2d91ee9" +checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" dependencies = [ - "base64 0.21.0", + "base64 0.21.5", "bytes", "encoding_rs", "futures-core", "futures-util", "h2", "http", - "http-body", - "hyper", + "http-body 0.4.5", + "hyper 0.14.27", "hyper-tls", "ipnet", "js-sys", @@ -2935,6 +1953,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", + "system-configuration", "tokio", "tokio-native-tls", "tokio-util", @@ -2949,62 +1968,16 @@ dependencies = [ [[package]] name = "ring" -version = "0.16.20" +version = "0.17.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +checksum = "9babe80d5c16becf6594aa32ad2be8fe08498e7ae60b77de8df700e67f191d7e" dependencies = [ "cc", + "getrandom", "libc", - "once_cell", - "spin 0.5.2", + "spin", "untrusted", - "web-sys", - "winapi", -] - -[[package]] -name = "rkyv" -version = "0.7.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c30f1d45d9aa61cbc8cd1eb87705470892289bb2d01943e7803b873a57404dc3" -dependencies = [ - "bytecheck", - "hashbrown 0.12.3", - "ptr_meta", - "rend", - "rkyv_derive", - "seahash", -] - -[[package]] -name = "rkyv_derive" -version = "0.7.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff26ed6c7c4dfc2aa9480b86a60e3c7233543a270a680e10758a507c5a4ce476" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "rsa" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cf22754c49613d2b3b119f0e5d46e34a2c628a937e3024b8762de4e7d8c710b" -dependencies = [ - "byteorder", - "digest", - "num-bigint-dig", - "num-integer", - "num-iter", - "num-traits", - "pkcs1", - "pkcs8", - "rand_core 0.6.4", - "smallvec", - "subtle", - "zeroize", + "windows-sys", ] [[package]] @@ -3019,15 +1992,17 @@ dependencies = [ [[package]] name = "rust-s3" -version = "0.32.3" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6009d9d4cf910505534d62d380a0aa305805a2af0b5c3ad59a3024a0715b847" +checksum = "1b2ac5ff6acfbe74226fa701b5ef793aaa054055c13ebb7060ad36942956e027" dependencies = [ "async-trait", "aws-creds", "aws-region", "base64 0.13.1", + "bytes", "cfg-if", + "futures", "hex", "hmac", "http", @@ -3036,270 +2011,213 @@ dependencies = [ "md5", "minidom", "percent-encoding", + "quick-xml", "reqwest", "serde", - "serde-xml-rs", "serde_derive", "sha2", "thiserror", - "time 0.3.20", + "time 0.3.30", "tokio", "tokio-stream", "url", ] -[[package]] -name = "rust_decimal" -version = "1.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b1b21b8760b0ef8ae5b43d40913ff711a2053cb7ff892a34facff7a6365375a" -dependencies = [ - "arrayvec", - "borsh", - "bytecheck", - "byteorder", - "bytes", - "num-traits", - "rand 0.8.5", - "rkyv", - "serde", - "serde_json", -] - [[package]] name = "rustc-demangle" -version = "0.1.21" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] -name = "rustc_version" -version = "0.2.3" +name = "rustc-hash" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver 0.9.0", -] +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] -name = "rustc_version" -version = "0.4.0" +name = "rustix" +version = "0.37.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" dependencies = [ - "semver 1.0.17", + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys", ] [[package]] name = "rustix" -version = "0.36.9" +version = "0.38.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd5c6ff11fecd55b40746d1995a02f2eb375bf8c00d192d521ee09f42bef37bc" +checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f" dependencies = [ - "bitflags", + "bitflags 2.4.0", "errno", - "io-lifetimes", "libc", - "linux-raw-sys", - "windows-sys 0.45.0", + "linux-raw-sys 0.4.5", + "windows-sys", ] [[package]] name = "rustls" -version = "0.19.1" +version = "0.21.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" +checksum = "629648aced5775d558af50b2b4c7b02983a04b312126d45eeead26e7caa498b9" dependencies = [ - "base64 0.13.1", "log", "ring", - "sct 0.6.1", - "webpki 0.21.4", + "rustls-webpki", + "sct", ] [[package]] -name = "rustls" -version = "0.20.8" +name = "rustls-connector" +version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" +checksum = "25da151615461c7347114b1ad1a7458b4cdebc69cb220cd140cd5cb324b1dd37" dependencies = [ "log", - "ring", - "sct 0.7.0", - "webpki 0.22.0", + "rustls", + "rustls-native-certs", + "rustls-webpki", ] [[package]] -name = "rustls-connector" -version = "0.16.1" +name = "rustls-native-certs" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c6a18f8d10f71bce9bca6eaeb80429460e652f3bcf0381f0c5f8954abf7b3b8" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" dependencies = [ - "log", - "rustls 0.20.8", - "rustls-native-certs", - "webpki 0.22.0", + "openssl-probe", + "rustls-pemfile", + "schannel", + "security-framework", ] [[package]] -name = "rustls-native-certs" -version = "0.6.2" +name = "rustls-pemfile" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "openssl-probe", - "rustls-pemfile", - "schannel", - "security-framework", + "base64 0.21.5", ] [[package]] -name = "rustls-pemfile" -version = "1.0.2" +name = "rustls-webpki" +version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "base64 0.21.0", + "ring", + "untrusted", ] [[package]] name = "rustus" version = "0.7.6" dependencies = [ - "actix-cors", - "actix-files", - "actix-http", - "actix-rt", - "actix-web", - "actix-web-prom", "async-trait", - "base64 0.21.0", - "bb8", - "bb8-lapin", - "bb8-redis", + "axum", + "base64 0.21.5", "bytes", "chrono", - "clap 4.1.8", - "derive_more", + "clap", "digest", - "dotenvy", - "dyn-clone", + "enum_dispatch", "fern", "futures", - "httptest", + "http", "lapin", "log", "md-5", "mimalloc", "mime", "mime_guess", - "openssl", - "prometheus", - "rbatis", - "rbson", + "mobc", "redis", "reqwest", "rust-s3", - "sentry", - "sentry-actix", + "rustc-hash", "serde", "serde_json", - "sha1 0.10.5", + "sha1", "sha2", "strum", - "tempdir", "thiserror", "tokio", - "url", - "uuid 1.3.0", + "tokio-util", + "tower", + "tower-http", + "uuid", "wildmatch", ] [[package]] name = "rustversion" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "rxml" -version = "0.8.2" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a071866b8c681dc2cfffa77184adc32b57b0caad4e620b6292609703bceb804" +checksum = "a98f186c7a2f3abbffb802984b7f1dfd65dac8be1aafdaabbca4137f53f0dff7" dependencies = [ "bytes", - "pin-project-lite", "rxml_validation", "smartstring", - "tokio", ] [[package]] name = "rxml_validation" -version = "0.8.2" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53bc79743f9a66c2fb1f951cd83735f275d46bfe466259fbc5897bb60a0d00ee" +checksum = "22a197350ece202f19a166d1ad6d9d6de145e1d2a8ef47db299abe164dbd7530" [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "schannel" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" dependencies = [ - "windows-sys 0.42.0", + "windows-sys", ] [[package]] name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "scratch" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" - -[[package]] -name = "sct" -version = "0.6.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" -dependencies = [ - "ring", - "untrusted", -] +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sct" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ "ring", "untrusted", ] -[[package]] -name = "seahash" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" - [[package]] name = "security-framework" -version = "2.8.2" +version = "2.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "core-foundation-sys", "libc", @@ -3308,191 +2226,52 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.8.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" dependencies = [ "core-foundation-sys", "libc", ] -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - -[[package]] -name = "sentry" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5ce6d3512e2617c209ec1e86b0ca2fea06454cd34653c91092bf0f3ec41f8e3" -dependencies = [ - "httpdate", - "native-tls", - "reqwest", - "sentry-backtrace", - "sentry-contexts", - "sentry-core", - "sentry-debug-images", - "sentry-panic", - "tokio", - "ureq", -] - -[[package]] -name = "sentry-actix" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c210068218470670c03fbe59f53944061f9b1fcdb7748f9326248ab1ddf56238" -dependencies = [ - "actix-web", - "futures-util", - "sentry-core", -] - -[[package]] -name = "sentry-backtrace" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7fe408d4d1f8de188a9309916e02e129cbe51ca19e55badea5a64899399b1a" -dependencies = [ - "backtrace", - "once_cell", - "regex", - "sentry-core", -] - -[[package]] -name = "sentry-contexts" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5695096a059a89973ec541062d331ff4c9aeef9c2951416c894f0fff76340e7d" -dependencies = [ - "hostname", - "libc", - "os_info", - "rustc_version 0.4.0", - "sentry-core", - "uname", -] - -[[package]] -name = "sentry-core" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b22828bfd118a7b660cf7a155002a494755c0424cebb7061e4743ecde9c7dbc" -dependencies = [ - "once_cell", - "rand 0.8.5", - "sentry-types", - "serde", - "serde_json", -] - -[[package]] -name = "sentry-debug-images" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a9164d44a2929b1b7670afd7e87552514b70d3ae672ca52884639373d912a3d" -dependencies = [ - "findshlibs", - "once_cell", - "sentry-core", -] - -[[package]] -name = "sentry-panic" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4ced2a7a8c14899d58eec402d946f69d5ed26a3fc363a7e8b1e5cb88473a01" -dependencies = [ - "sentry-backtrace", - "sentry-core", -] - -[[package]] -name = "sentry-types" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "360ee3270f7a4a1eee6c667f7d38360b995431598a73b740dfe420da548d9cc9" -dependencies = [ - "debugid", - "getrandom", - "hex", - "serde", - "serde_json", - "thiserror", - "time 0.3.20", - "url", - "uuid 1.3.0", -] - [[package]] name = "serde" -version = "1.0.155" +version = "1.0.192" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71f2b4817415c6d4210bfe1c7bfcf4801b2d904cb4d0e1a8fdb651013c9e86b8" +checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" dependencies = [ "serde_derive", ] [[package]] -name = "serde-xml-rs" -version = "0.5.1" +name = "serde_derive" +version = "1.0.192" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65162e9059be2f6a3421ebbb4fef3e74b7d9e7c60c50a0e292c6239f19f1edfa" +checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" dependencies = [ - "log", - "serde", - "thiserror", - "xml-rs", + "proc-macro2", + "quote", + "syn 2.0.28", ] [[package]] -name = "serde_bytes" -version = "0.11.9" +name = "serde_json" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416bda436f9aab92e02c8e10d49a15ddd339cea90b6e340fe51ed97abb548294" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ + "itoa", + "ryu", "serde", ] [[package]] -name = "serde_derive" -version = "1.0.155" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d071a94a3fac4aff69d023a7f411e33f40f3483f8c5190b1953822b6b76d7630" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.94" +name = "serde_path_to_error" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea" +checksum = "4beec8bce849d58d06238cb50db2e1c417cfeafa4c63f692b15c82b7c80f8335" dependencies = [ - "indexmap", "itoa", - "ryu", "serde", ] @@ -3508,31 +2287,11 @@ dependencies = [ "serde", ] -[[package]] -name = "sha-1" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha1" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" -dependencies = [ - "sha1_smol", -] - [[package]] name = "sha1" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", @@ -3547,15 +2306,24 @@ checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", "digest", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -3565,34 +2333,30 @@ dependencies = [ "libc", ] -[[package]] -name = "simdutf8" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" - [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "smallvec" -version = "1.10.0" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] name = "smartstring" -version = "0.2.10" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e714dff2b33f2321fdcd475b71cec79781a692d846f37f415fb395a1d2bcd48e" +checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" dependencies = [ + "autocfg", "static_assertions", + "version_check", ] [[package]] @@ -3606,191 +2370,29 @@ dependencies = [ ] [[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - -[[package]] -name = "spin" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dccf47db1b41fa1573ed27ccf5e08e3ca771cb994f776668c5ebda893b248fc" -dependencies = [ - "lock_api", -] - -[[package]] -name = "spki" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d01ac02a6ccf3e07db148d2be087da624fea0221a16152ed01f0496a6b0a27" -dependencies = [ - "base64ct", - "der", -] - -[[package]] -name = "sqlformat" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4b7922be017ee70900be125523f38bdd644f4f06a1b16e8fa5a8ee8c34bffd4" -dependencies = [ - "itertools", - "nom", - "unicode_categories", -] - -[[package]] -name = "sqlx-core" -version = "0.5.13" +name = "socket2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48c61941ccf5ddcada342cd59e3e5173b007c509e1e8e990dafc830294d9dc5" +checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" dependencies = [ - "ahash 0.7.6", - "atoi", - "base64 0.13.1", - "bigdecimal", - "bit-vec", - "bitflags", - "byteorder", - "bytes", - "chrono", - "crc", - "crossbeam-queue", - "digest", - "dirs", - "either", - "encoding_rs", - "event-listener", - "flume", - "futures-channel", - "futures-core", - "futures-executor", - "futures-intrusive", - "futures-util", - "generic-array", - "hashlink", - "hex", - "hkdf", - "hmac", - "indexmap", - "itoa", "libc", - "libsqlite3-sys", - "log", - "md-5", - "memchr", - "num-bigint", - "once_cell", - "paste", - "percent-encoding", - "rand 0.8.5", - "regex", - "rsa", - "rust_decimal", - "rustls 0.19.1", - "serde", - "serde_json", - "sha-1", - "sha2", - "smallvec", - "sqlformat", - "sqlx-rt", - "stringprep", - "thiserror", - "tokio-stream", - "url", - "uuid 0.8.2", - "webpki 0.21.4", - "webpki-roots", - "whoami", + "windows-sys", ] [[package]] -name = "sqlx-rt" -version = "0.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4db708cd3e459078f85f39f96a00960bd841f66ee2a669e90bf36907f5a79aae" -dependencies = [ - "once_cell", - "tokio", - "tokio-rustls", -] - -[[package]] -name = "standback" -version = "0.2.17" +name = "spin" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" dependencies = [ - "version_check", + "lock_api", ] [[package]] name = "static_assertions" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "stdweb" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" -dependencies = [ - "discard", - "rustc_version 0.2.3", - "stdweb-derive", - "stdweb-internal-macros", - "stdweb-internal-runtime", - "wasm-bindgen", -] - -[[package]] -name = "stdweb-derive" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "serde_derive", - "syn", -] - -[[package]] -name = "stdweb-internal-macros" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" -dependencies = [ - "base-x", - "proc-macro2", - "quote", - "serde", - "serde_derive", - "serde_json", - "sha1 0.6.1", - "syn", -] - -[[package]] -name = "stdweb-internal-runtime" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" - -[[package]] -name = "stringprep" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "strsim" @@ -3800,31 +2402,31 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "strum" -version = "0.24.1" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" -version = "0.24.3" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" dependencies = [ "heck", "proc-macro2", "quote", "rustversion", - "syn", + "syn 2.0.28", ] [[package]] name = "subtle" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" @@ -3838,152 +2440,138 @@ dependencies = [ ] [[package]] -name = "tcp-stream" -version = "0.24.4" +name = "syn" +version = "2.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a4b0a70bac0a58ca6a7659d1328e34ee462339c70b0fa49f72bad1f278910a" +checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" dependencies = [ - "cfg-if", - "p12", - "rustls-connector", - "rustls-pemfile", + "proc-macro2", + "quote", + "unicode-ident", ] [[package]] -name = "tempdir" -version = "0.3.7" +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "system-configuration" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ - "rand 0.4.6", - "remove_dir_all", + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", ] [[package]] -name = "tempfile" -version = "3.4.0" +name = "system-configuration-sys" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" dependencies = [ - "cfg-if", - "fastrand", - "redox_syscall", - "rustix", - "windows-sys 0.42.0", + "core-foundation-sys", + "libc", ] [[package]] -name = "termcolor" -version = "1.2.0" +name = "tcp-stream" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "4da30af7998f51ee1aa48ab24276fe303a697b004e31ff542b192c088d5630a5" dependencies = [ - "winapi-util", + "cfg-if", + "p12", + "rustls-connector", + "rustls-pemfile", ] [[package]] -name = "textwrap" -version = "0.16.0" +name = "tempfile" +version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" +checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +dependencies = [ + "cfg-if", + "fastrand 2.0.1", + "redox_syscall 0.3.5", + "rustix 0.38.8", + "windows-sys", +] [[package]] name = "thiserror" -version = "1.0.39" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5ab016db510546d856297882807df8da66a16fb8c4101cb8b30054b0d5b2d9c" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.39" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5420d42e90af0c38c3290abcca25b9b3bdf379fc9f55c528f53a269d9c9a267e" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.28", ] [[package]] -name = "time" -version = "0.1.45" +name = "thread_local" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", + "cfg-if", + "once_cell", ] [[package]] name = "time" -version = "0.2.27" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" dependencies = [ - "const_fn", "libc", - "serde", - "standback", - "stdweb", - "time-macros 0.1.1", - "version_check", + "wasi 0.10.0+wasi-snapshot-preview1", "winapi", ] [[package]] name = "time" -version = "0.3.20" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" +checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" dependencies = [ + "deranged", "itoa", + "powerfmt", "serde", "time-core", - "time-macros 0.2.8", + "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.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" -dependencies = [ - "proc-macro-hack", - "time-macros-impl", -] +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.8" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36" +checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" dependencies = [ "time-core", ] -[[package]] -name = "time-macros-impl" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" -dependencies = [ - "proc-macro-hack", - "proc-macro2", - "quote", - "standback", - "syn", -] - [[package]] name = "tinyvec" version = "1.6.0" @@ -4001,33 +2589,32 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.26.0" +version = "1.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03201d01c3c27a29c8a5cee5b55a93ddae1ccf6f08f65365c2c918f8c1b76f64" +checksum = "40de3a2ba249dcb097e01be5e67a5ff53cf250397715a071a81543e8a832a920" dependencies = [ - "autocfg", + "backtrace", "bytes", "libc", - "memchr", "mio", "num_cpus", - "parking_lot 0.12.1", + "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.5.3", "tokio-macros", - "windows-sys 0.45.0", + "windows-sys", ] [[package]] name = "tokio-macros" -version = "1.8.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.28", ] [[package]] @@ -4041,21 +2628,21 @@ dependencies = [ ] [[package]] -name = "tokio-rustls" -version = "0.22.0" +name = "tokio-retry" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" +checksum = "7f57eb36ecbe0fc510036adff84824dd3c24bb781e21bfa67b69d556aa85214f" dependencies = [ - "rustls 0.19.1", + "pin-project", + "rand", "tokio", - "webpki 0.21.4", ] [[package]] name = "tokio-stream" -version = "0.1.12" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" dependencies = [ "futures-core", "pin-project-lite", @@ -4064,9 +2651,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.7" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", @@ -4077,14 +2664,60 @@ dependencies = [ ] [[package]] -name = "toml" -version = "0.5.11" +name = "tower" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" dependencies = [ - "serde", + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" +dependencies = [ + "bitflags 2.4.0", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body 0.4.5", + "http-range-header", + "pin-project-lite", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-hyper-http-body-compat" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7ea3e622710ee44a8255baa6fcb2a34d67450e2ffb48e5e58d5a7bd6ff55a21" +dependencies = [ + "http", + "http-body 0.4.5", + "http-body 1.0.0-rc.2", + "hyper 1.0.0-rc.4", + "pin-project-lite", + "tower", + "tower-service", ] +[[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" @@ -4100,65 +2733,88 @@ dependencies = [ "cfg-if", "log", "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ "once_cell", + "valuable", ] [[package]] -name = "try-lock" -version = "0.2.4" +name = "tracing-log" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] [[package]] -name = "typenum" -version = "1.16.0" +name = "tracing-subscriber" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", +] [[package]] -name = "ucd-trie" -version = "0.1.5" +name = "try-lock" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] -name = "uname" -version = "0.1.1" +name = "typenum" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b72f89f0ca32e4db1c04e2a72f5345d59796d4866a1ee0609084569f73683dc8" -dependencies = [ - "libc", -] +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicase" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" dependencies = [ "version_check", ] [[package]] name = "unicode-bidi" -version = "0.3.11" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524b68aca1d05e03fdf03fcdce2c6c94b6daf6d16861ddaa7e4f2b6638a9052c" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" [[package]] name = "unicode-normalization" @@ -4169,69 +2825,44 @@ dependencies = [ "tinyvec", ] -[[package]] -name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - -[[package]] -name = "unicode_categories" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" - [[package]] name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - -[[package]] -name = "ureq" -version = "2.6.2" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "338b31dd1314f68f3aabf3ed57ab922df95ffcd902476ca7ba3c4ce7b908c46d" -dependencies = [ - "base64 0.13.1", - "log", - "native-tls", - "once_cell", - "url", -] +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.3.1" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" dependencies = [ "form_urlencoded", "idna", "percent-encoding", - "serde", ] [[package]] -name = "uuid" -version = "0.8.2" +name = "utf8parse" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" -dependencies = [ - "getrandom", - "serde", -] +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.3.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79" +checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc" dependencies = [ "getrandom", - "serde", ] +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "vcpkg" version = "0.2.15" @@ -4246,17 +2877,16 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "waker-fn" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" +checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690" [[package]] name = "want" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "log", "try-lock", ] @@ -4274,9 +2904,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -4284,24 +2914,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.28", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.34" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" dependencies = [ "cfg-if", "js-sys", @@ -4311,9 +2941,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4321,28 +2951,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.28", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "wasm-streams" -version = "0.2.3" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bbae3363c08332cadccd13b67db371814cd214c2524020932f0804b8cf7c078" +checksum = "b4609d447824375f43e1ffbc051b50ad8f4b3ae8219680c94452ea05eb240ac7" dependencies = [ "futures-util", "js-sys", @@ -4353,53 +2983,14 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.61" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" dependencies = [ "js-sys", "wasm-bindgen", ] -[[package]] -name = "webpki" -version = "0.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "webpki" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "webpki-roots" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" -dependencies = [ - "webpki 0.21.4", -] - -[[package]] -name = "whoami" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c70234412ca409cc04e864e89523cb0fc37f5e1344ebed5a3ebf4192b6b9f68" -dependencies = [ - "wasm-bindgen", - "web-sys", -] - [[package]] name = "wildmatch" version = "2.1.1" @@ -4422,15 +3013,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -4438,34 +3020,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows-sys" -version = "0.42.0" +name = "windows" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows-targets", ] [[package]] name = "windows-sys" -version = "0.45.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" -version = "0.42.1" +version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -4478,99 +3054,58 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.1" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" [[package]] name = "windows_aarch64_msvc" -version = "0.42.1" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" [[package]] name = "windows_i686_gnu" -version = "0.42.1" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" [[package]] name = "windows_i686_msvc" -version = "0.42.1" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" [[package]] name = "windows_x86_64_gnu" -version = "0.42.1" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.1" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" [[package]] name = "windows_x86_64_msvc" -version = "0.42.1" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winreg" -version = "0.10.1" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "winapi", + "cfg-if", + "windows-sys", ] -[[package]] -name = "xml-rs" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" - [[package]] name = "yasna" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aed2e7a52e3744ab4d0c05c20aa065258e84c49fd4226f5191b2ed29712710b4" - -[[package]] -name = "zeroize" -version = "1.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" - -[[package]] -name = "zstd" -version = "0.12.3+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76eea132fb024e0e13fd9c2f5d5d595d8a967aa72382ac2f9d39fcc95afd0806" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "6.0.4+zstd.1.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7afb4b54b8910cf5447638cb54bf4e8a65cbedd783af98b98c62ffe91f185543" -dependencies = [ - "libc", - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.7+zstd.1.5.4" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94509c3ba2fe55294d752b79842c530ccfab760192521df74a081a78d2b3c7f5" -dependencies = [ - "cc", - "libc", - "pkg-config", -] +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" diff --git a/Cargo.toml b/Cargo.toml index 82d27f0..534287e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,159 +3,58 @@ name = "rustus" version = "0.7.6" edition = "2021" description = "TUS protocol implementation written in Rust." -keywords = ["tus", "server", "actix-web"] license-file = "LICENSE" -authors = [ - "Pavel Kirilin ", - "Maxim Naumov ", -] +authors = ["Pavel Kirilin "] homepage = "https://github.com/s3rius/rustus" readme = "README.md" - [[bin]] name = "rustus" +path = "src/main.rs" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -bytes = "^1.3.0" -bb8 = "^0.8.0" -async-trait = "^0.1.52" -base64 = "^0.21.0" -log = "^0.4.14" -serde_json = "^1" -thiserror = "^1.0" -url = "^2.2.2" -prometheus = "^0.13.0" -actix-web-prom = "^0.6.0" -dyn-clone = "^1.0.5" -actix-cors = "0.6.1" -wildmatch = "2.1.0" -md-5 = "^0.10.1" -digest = "0.10.3" -mimalloc = { version = "~0.1.30", default-features = false } -clap = { version = "4.1.8", features = ["derive", "env"] } -dotenvy = { version = "0.15.6", features = ["clap"] } -sentry = "0.30.0" -sentry-actix = "0.30.0" +async-trait = "0.1.74" +axum = { git = "https://github.com/tokio-rs/axum.git", rev = "3ff45d9" } +base64 = "0.21.5" +bytes = "1.5.0" +chrono = { version = "0.4.26", features = ["serde"] } +clap = { version = "4.3.21", features = ["env", "derive"] } +enum_dispatch = "0.3.12" +fern = { version = "0.6.2", features = ["colored", "chrono"] } +futures = "0.3.29" +log = "0.4.20" +mimalloc = "0.1.39" mime = "0.3.17" mime_guess = "2.0.4" +mobc = "0.8.3" +redis = { version = "0.23.3", features = ["tokio-comp", "connection-manager"] } +rustc-hash = "1.1.0" +serde = { version = "1.0.192", features = ["derive"] } +serde_json = "1.0.108" +strum = { version = "0.25.0", features = ["derive"] } +thiserror = "1.0.50" +tokio = { version = "1.31.0", features = ["full"] } +tokio-util = { version = "0.7.10", features = ["io"] } +uuid = { version = "1.5.0", features = ["v4"] } +rust-s3 = "^0.33" +tower = "0.4.13" +# Hashsums +sha1 = { version = "^0.10.1", features = ["compress"] } +sha2 = { version = "^0.10.1", features = ["compress"] } +md-5 = "^0.10.1" +digest = "^0.10.1" +reqwest = "0.11.22" +lapin = "2.3.1" +tower-http = { version = "0.4.4", features = ["cors"] } +http = "^0.2" +wildmatch = "2.1.1" -[dependencies.sha1] -version = "^0.10.1" -features = ["compress"] - -[dependencies.sha2] -version = "^0.10.1" -features = ["compress"] - -[dependencies.futures] -version = "^0.3.21" - -[dependencies.serde] -version = "^1" -features = ["derive"] - -[dependencies.openssl] -version = "^0.10.38" -features = ["vendored"] - -[dependencies.actix-files] -version = "^0.6.0-beta.13" - -[dependencies.actix-web] -version = "^4.0.1" - -[dependencies.chrono] -features = ["serde"] -version = "^0.4.19" - -[dependencies.derive_more] -default-features = false -features = ["display", "from", "from_str"] -version = "^0.99.9" - -[dependencies.fern] -features = ["colored"] -version = "^0.6.0" - -[dependencies.lapin] -optional = true -version = "^2.0.0" - -[dependencies.bb8-lapin] -version = "^0.4.0" -optional = true - -[dependencies.bb8-redis] -optional = true -version = "^0.12.0" - -[dependencies.redis] -optional = true -version = "^0.22.3" - -[dependencies.rbatis] -default-features = false -features = ["runtime-tokio-rustls", "all-database"] -optional = true -version = "^3.0" - -[dependencies.rbson] -optional = true -version = "^2.0" - -[dependencies.reqwest] -features = ["json"] -version = "^0.11.8" - -[dependencies.strum] -features = ["derive"] -version = "0.24.0" - -[dependencies.tokio] -features = [ - "time", - "process", - "fs", - "io-std", - "io-util", - "rt-multi-thread", - "bytes", - "rt", - "macros", -] -version = "^1.4.0" - -[dependencies.uuid] -features = ["v4"] -version = "^1.0.0-alpha.1" - -[dependencies.rust-s3] -version = "~0.32.3" - -[features] -all = ["redis_info_storage", "db_info_storage", "amqp_notifier"] -amqp_notifier = ["lapin", "bb8-lapin"] -db_info_storage = ["rbatis", "rbson"] -default = [] -redis_info_storage = ["bb8-redis", "redis"] - -### For testing -test_redis = [] -test_db = [] -test_rmq = [] -integration_tests = ["test_redis", "test_db", "test_rmq"] - -[dev-dependencies] -tempdir = "0.3.7" -actix-rt = "2.6.0" -httptest = "0.15.4" -actix-http = "3.2.2" -[profile] [profile.release] -debug = false -lto = "fat" -panic = "abort" opt-level = 3 +debug = false codegen-units = 1 +lto = true +panic = "abort" diff --git a/README.md b/README.md index cef8216..ad03d65 100644 --- a/README.md +++ b/README.md @@ -14,47 +14,28 @@ This implementation has several features to make usage as simple as possible. * Rustus is robust, since it uses asynchronous Rust; -* It can store information about uploads in databases; -* You can specify directory structure to organize your uploads; -* It has a lot of hooks options, and hooks can be combined. -* Highly configurable; +* It can store information about uploads not only in files; +* You can define your own directory structure to organize your uploads; +* It has a lot of hooks options, and hooks can be combined; +* Highly configurable. Please check out [Documentation](https://s3rius.github.io/rustus/) for more information about configuration and deploy. ## Installation -You can install rustus by 4 different ways. +You can install rustus by 3 different ways. ### From source -To build it from source rust must be installed. We don't rely on nightly features, -you can use last stable release. +To build it from source rust must be installed. We rely on nightly features, +so please switch to nightly channel before building. ```bash +rustup update nightly git clone https://github.com/s3rius/rustus.git cd rustus -cargo install --path . --features=all +cargo install --path . ``` -Also you can speedup build by disabling some features. - -Available features: - -* `amqp_notifier` - adds amqp protocol support for notifying about upload status; -* `db_info_storage` - adds support for storing information about upload in different databases (Postgres, MySQL, SQLite); -* `redis_info_storage` - adds support for storing information about upload in redis database; -* `all` - enables all rustus features. - -All precompiled binaries have all features enabled. - -### With cargo - -If you have cargo installed maybe it would be easier to -install it directly from crates.io. - -```bash -cargo install rustus --features=all -``` - ### Binaries All precompiled binaries available on github releases page. @@ -78,6 +59,12 @@ Alpine based images are more lightweight than debian To run rustus you just need to run this command +```bash +docker run --rm -p "1081:1081" -d s3rius/rustus --log-level "DEBUG" +``` + +To persist data you can mount volume to `/data` directory + ```bash docker run --rm -p "1081:1081" -d s3rius/rustus --log-level "DEBUG" ``` \ No newline at end of file diff --git a/deploy/Dockerfile b/deploy/Dockerfile index 545994f..ceaf08b 100644 --- a/deploy/Dockerfile +++ b/deploy/Dockerfile @@ -1,10 +1,10 @@ -FROM rust:1.66.0-bullseye AS builder +FROM rustlang/rust:nightly-buster AS builder WORKDIR /app COPY Cargo.toml Cargo.lock ./ COPY src ./src COPY imgs ./imgs -RUN cargo build --release --bin rustus --features=all +RUN cargo build --release --bin rustus FROM debian:bullseye-20211201-slim AS base diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..a8bc7d5 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,27 @@ +version: '3.9' + +services: + redis: + image: redis:7.2 + ports: + - 6379:6379 + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 1s + timeout: 3s + retries: 50 + + rabbitmq: + image: rabbitmq:3.10.23-management + ports: + - 5672:5672 + - 15672:15672 + environment: + RABBITMQ_DEFAULT_USER: "guest" + RABBITMQ_DEFAULT_PASS: "guest" + RABBITMQ_DEFAULT_VHOST: "/" + healthcheck: + test: ["CMD", "rabbitmq-diagnostics", "check_running", "-q"] + interval: 3s + timeout: 3s + retries: 50 \ No newline at end of file diff --git a/docs/configuration.md b/docs/configuration.md index aac9573..7254b3c 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -6,7 +6,7 @@ description: "How to configure Rusts" Rustus is highly configurable. You can adjust it with CLI or you can use environment variables. !!! info - Information about hooks you can find on [Hooks page](../hooks). + Information about hooks you can find on [Hooks page](hooks.md). ## Configuring server @@ -19,17 +19,17 @@ Also you can configure number of actix `workers` that handle connections. `--url` is a base URL for all tus requests. -`--workers` by default is equal to number of physical CPU cores. Edit it carefully. +`--workers` number of threads used by async runtime. By default equals to number of CPU cores. `--cors` is a list of allowed hosts with wildcards separated by commas. By default all hosts are allowed. You can define which hosts are allowed for your particular application. -`--allow-empty` is a parameter that allows users to upload empty files. Empty -file means that while creation 0 bytes was passed as an `Upload-Length`. - For example if you add `--cors "*.staging.domain,*.prod.domain"`, it allows all origins like `my.staging.domain` or `my.prod.domain`, but it will refuse to serve other origins. +`--allow-empty` is a parameter that allows users to upload empty files. Empty +file means that while creation 0 bytes was passed as an `Upload-Length`. + Also you can disable access log for `/health` endpoint, by using `--disable-health-access-log`. === "CLI" @@ -133,7 +133,7 @@ data ``` bash rustus --force-fsync \ - --storage "file-storage" \ + --data-storage "file-storage" \ --data-dir "./data/" \ --dir-structure "{year}/{month}/{day}" ``` @@ -141,7 +141,7 @@ data === "ENV" ``` bash - export RUSTUS_STORAGE="file-storage" + export RUSTUS_STORAGE="file" export RUSTUS_DATA_DIR="./data/" export RUSTUS_DIR_STRUCTURE="{year}/{month}/{day}" export RUSTUS_FORCE_FSYNC="true" @@ -187,7 +187,7 @@ Required parameter are only `--s3-url` and `--s3-bucket`. === "CLI" ``` bash - rustus --storage "hybrid-s3" \ + rustus --data-storage "hybrid-s3" \ --s3-url "https://localhost:9000" \ --s3-bucket "bucket" \ --s3-region "eu-central1" \ @@ -254,14 +254,14 @@ storing information about uploads. But if you don't plan to have many uploads, i === "CLI" ``` bash - rustus --info-storage "file-info-storage" \ + rustus --info-storage "file" \ --info-dir "./data" ``` === "ENV" ``` bash - export RUSTUS_INFO_STORAGE="file-info-storage" + export RUSTUS_INFO_STORAGE="file" export RUSTUS_INFO_DIR="./data" rustus @@ -279,7 +279,7 @@ Redis db is a good way to store information. Configuration parameters: * `--info-db-dsn` - connection string for your Redis database. - It's required if `redis-info-storage` is chosen. + It's required if `redis` is chosen. * `--redis-info-expiration` - number of seconds when key will expire. === "CLI" @@ -301,35 +301,6 @@ Configuration parameters: ``` -### DB info storage - -Rustus can store information about upload in a database. - -It's a good and reliable option. But Rustus can't work -with replicas, since it requires the most recent information -about uploads. - -You can use `postgresql`, `mysql` or even `sqlite` schemas to -connect to database. - -`--info-db-dsn` - connection string for your database. - -=== "CLI" - - ``` bash - rustus --info-storage "db-info-storage" \ - --info-db-dsn "postgresql://user:password@localhost/db" - ``` - -=== "ENV" - - ``` bash - export RUSTUS_INFO_STORAGE="redis-info-storage" - export RUSTUS_INFO_DB_DSN="postgresql://user:password@localhost/db" - - rustus - ``` - ## Configuring TUS Since TUS protocol offers extensibility you can turn off some protocol extensions. diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..a0e2ab6 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1 @@ +toolchain.channel = "nightly" diff --git a/src/config.rs b/src/config.rs index 599e2d8..0c1d79d 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,23 +1,57 @@ -use std::{ffi::OsString, path::PathBuf}; +use std::path::PathBuf; use clap::Parser; use crate::{ - info_storages::AvailableInfoStores, - notifiers::{Format, Hook}, - protocol::extensions::Extensions, + data_storage::AvailableStorages, + extensions::TusExtensions, + info_storages::AvailableInfoStorages, + notifiers::{self, hooks::Hook}, }; -use crate::storages::AvailableStores; +#[derive(Parser, Clone, Debug)] +pub struct InfoStorageConfig { + /// Rustus info storage type. + /// + /// Info storages are used to store + /// information about uploads. + #[arg(long, default_value = "file-info-storage", env = "RUSTUS_INFO_STORAGE")] + pub info_storage: AvailableInfoStorages, -#[derive(Parser, Debug, Clone)] -pub struct StorageOptions { + /// Rustus info directory + /// + /// This directory is used to store .info files + /// for `file_info_storage`. + #[arg(long, default_value = "./data", env = "RUSTUS_INFO_DIR")] + pub info_dir: PathBuf, + + /// Connection string for remote info storages. + /// + /// This connection string is used for storages + /// which require connection. Examples of such storages + /// are `Postgres`, `MySQL` or `Redis`. + /// + /// Value must include all connection details. + #[arg( + long, + required_if_eq_any([("info_storage", "redis-info-storage")]), + env = "RUSTUS_INFO_DB_DSN" + )] + pub info_db_dsn: Option, + + /// How long results are stored in Redis info storage in seconds. + #[arg(long, env = "RUSTUS_REDIS_INFO_EXPIRATION")] + pub redis_info_expiration: Option, +} + +#[derive(Parser, Clone, Debug)] +pub struct DataStorageConfig { /// Rustus storage type. /// /// Storages are used to store /// uploads. #[arg(long, short, default_value = "file-storage", env = "RUSTUS_STORAGE")] - pub storage: AvailableStores, + pub storage: AvailableStorages, /// Rustus data directory /// @@ -121,102 +155,47 @@ pub struct StorageOptions { pub s3_headers: Option, } -#[derive(Parser, Debug, Clone)] -pub struct InfoStoreOptions { - /// Type of info storage. - /// - /// Info storages are used - /// to store information about - /// uploads. - /// - /// This information is used in - /// HEAD requests. - #[arg( - long, - short, - default_value = "file-info-storage", - env = "RUSTUS_INFO_STORAGE" - )] - pub info_storage: AvailableInfoStores, - - /// Rustus info directory - /// - /// This directory is used to store .info files - /// for `file_info_storage`. - #[arg(long, default_value = "./data", env = "RUSTUS_INFO_DIR")] - pub info_dir: PathBuf, - - /// Connection string for remote info storages. - /// - /// This connection string is used for storages - /// which require connection. Examples of such storages - /// are `Postgres`, `MySQL` or `Redis`. - /// - /// Value must include all connection details. - #[cfg(any(feature = "redis_info_storage", feature = "db_info_storage"))] - #[arg( - long, - required_if_eq_any([("info_storage", "db-info-storage"), ("info_storage", "redis-info-storage")]), - env = "RUSTUS_INFO_DB_DSN" - )] - pub info_db_dsn: Option, - - #[cfg(feature = "redis_info_storage")] - #[arg(long, env = "RUSTUS_REDIS_INFO_EXPIRATION")] - pub redis_info_expiration: Option, -} -#[derive(Parser, Debug, Clone)] +#[derive(Parser, Clone, Debug)] #[allow(clippy::struct_excessive_bools)] - pub struct AMQPHooksOptions { /// Url for AMQP server. - #[cfg(feature = "amqp_notifier")] #[arg(long, env = "RUSTUS_HOOKS_AMQP_URL")] pub hooks_amqp_url: Option, /// Rustus will create exchange if enabled. - #[cfg(feature = "amqp_notifier")] #[arg(long, env = "RUSTUS_HOOKS_AMQP_DECLARE_EXCHANGE")] pub hooks_amqp_declare_exchange: bool, /// Rustus will create all queues for communication and bind them /// to exchange if enabled. - #[cfg(feature = "amqp_notifier")] #[arg(long, env = "RUSTUS_HOOKS_AMQP_DECLARE_QUEUES")] pub hooks_amqp_declare_queues: bool, /// Durability type of exchange. - #[cfg(feature = "amqp_notifier")] #[arg(long, env = "RUSTUS_HOOKS_AMQP_DURABLE_EXCHANGE")] pub hooks_amqp_durable_exchange: bool, /// Durability type of queues. - #[cfg(feature = "amqp_notifier")] #[arg(long, env = "RUSTUS_HOOKS_AMQP_DURABLE_QUEUES")] pub hooks_amqp_durable_queues: bool, /// Adds celery specific headers. - #[cfg(feature = "amqp_notifier")] #[arg(long, env = "RUSTUS_HOOKS_AMQP_CELERY")] pub hooks_amqp_celery: bool, /// Name of amqp exchange. - #[cfg(feature = "amqp_notifier")] #[arg(long, env = "RUSTUS_HOOKS_AMQP_EXCHANGE", default_value = "rustus")] pub hooks_amqp_exchange: String, /// Exchange kind. - #[cfg(feature = "amqp_notifier")] #[arg(long, env = "RUSTUS_HOOKS_AMQP_EXCHANGE_KIND", default_value = "topic")] pub hooks_amqp_exchange_kind: String, /// Routing key to use when sending message to an exchange. - #[cfg(feature = "amqp_notifier")] #[arg(long, env = "RUSTUS_HOOKS_AMQP_ROUTING_KEY")] pub hooks_amqp_routing_key: Option, /// Prefix for all AMQP queues. - #[cfg(feature = "amqp_notifier")] #[arg( long, env = "RUSTUS_HOOKS_AMQP_QUEUES_PREFIX", @@ -225,43 +204,38 @@ pub struct AMQPHooksOptions { pub hooks_amqp_queues_prefix: String, /// Maximum number of connections for RabbitMQ. - #[cfg(feature = "amqp_notifier")] #[arg( long, env = "RUSTUS_HOOKS_AMQP_CONNECTION_POOL_SIZE", default_value = "10" )] - pub hooks_amqp_connection_pool_size: u32, + pub hooks_amqp_connection_pool_size: u64, /// Maximum number of opened channels for each connection. - #[cfg(feature = "amqp_notifier")] #[arg( long, env = "RUSTUS_HOOKS_AMQP_CHANNEL_POOL_SIZE", default_value = "10" )] - pub hooks_amqp_channel_pool_size: u32, + pub hooks_amqp_channel_pool_size: u64, /// After this amount of time the connection will be dropped. - #[cfg(feature = "amqp_notifier")] #[arg(long, env = "RUSTUS_HOOKS_AMQP_IDLE_CONNECTION_TIMEOUT")] pub hooks_amqp_idle_connection_timeout: Option, /// After this amount of time in seconds, the channel will be closed. - #[cfg(feature = "amqp_notifier")] #[arg(long, env = "RUSTUS_HOOKS_AMQP_IDLE_CHANNELS_TIMEOUT")] pub hooks_amqp_idle_channels_timeout: Option, } -#[derive(Parser, Debug, Clone)] -#[allow(clippy::struct_excessive_bools)] -pub struct NotificationsOptions { +#[derive(Parser, Clone, Debug)] +pub struct NotificationConfig { /// Notifications format. /// /// This format will be used in all /// messages about hooks. #[arg(long, default_value = "default", env = "RUSTUS_HOOKS_FORMAT")] - pub hooks_format: Format, + pub hooks_format: notifiers::Format, /// Enabled hooks for notifications. #[arg( @@ -272,11 +246,6 @@ pub struct NotificationsOptions { )] pub hooks: Vec, - /// Use this option if you use rustus - /// behind any proxy. Like Nginx or Traefik. - #[arg(long, env = "RUSTUS_BEHIND_PROXY")] - pub behind_proxy: bool, - /// List of URLS to send webhooks to. #[arg(long, env = "RUSTUS_HOOKS_HTTP_URLS", use_value_delimiter = true)] pub hooks_http_urls: Vec, @@ -307,52 +276,52 @@ pub struct NotificationsOptions { pub amqp_hook_opts: AMQPHooksOptions, } -#[derive(Debug, Parser, Clone)] -pub struct SentryOptions { - #[arg(name = "sentry-dsn", long, env = "RUSTUS_SENTRY_DSN")] - pub dsn: Option, - - #[arg( - name = "sentry-sample-rate", - long, - default_value = "1.0", - env = "RUSTUS_SENTRY_SAMPLE_RATE" - )] - pub sample_rate: f32, -} - -#[derive(Debug, Parser, Clone)] -#[command(name = "Rustus")] -/// Tus protocol implementation. -/// -/// This program is a web-server that -/// implements protocol for resumable uploads. -/// -/// You can read more about protocol -/// [here](https://tus.io/). -pub struct RustusConf { - /// Rustus server host +#[derive(Parser, Clone, Debug)] +#[command(author, version, about, long_about = None)] +#[allow(clippy::struct_excessive_bools)] +pub struct Config { + /// Rustus server host. #[arg(long, default_value = "0.0.0.0", env = "RUSTUS_SERVER_HOST")] pub host: String, - /// Rustus server port + /// Rustus server port. #[arg(long, default_value = "1081", env = "RUSTUS_SERVER_PORT")] pub port: u16, + /// Log level for the server. + #[arg(long, default_value = "INFO", env = "RUSTUS_LOG_LEVEL")] + pub log_level: log::LevelFilter, + + /// Number of worker threads for the server. + /// + /// By default it is equal to the number of cores. + #[arg(long, env = "RUSTUS_WORKERS")] + pub workers: Option, + + /// Base URL for all endpoints. + #[arg(long, default_value = "/files", env = "RUSTUS_PREFIX")] + pub url: String, + + /// Disable access log for health endpoint. + /// By default it is enabled. #[arg(long, env = "RUSTUS_DISABLE_HEALTH_ACCESS_LOG")] pub disable_health_access_log: bool, - /// Rustus base API url - #[arg(long, default_value = "/files", env = "RUSTUS_URL")] - pub url: String, + /// Log level for the server. + /// Enabling this parameter + /// Will allow creation of empty files + /// when Upload-Length header equals to 0. + #[arg(long, env = "RUSTUS_ALLOW_EMPTY")] + pub allow_empty: bool, - /// Allowed hosts for CORS protocol. + /// Remove part files after concatenation is done. + /// By default rustus does nothing with part files after concatenation. /// - /// By default all hosts are allowed. - #[arg(long, env = "RUSTUS_CORS", use_value_delimiter = true)] - pub cors: Vec, + /// This parameter is only needed if concatenation extension is enabled. + #[arg(long, env = "RUSTUS_REMOVE_PARTS")] + pub remove_parts: bool, - /// Maximum payload size. + /// Maximum payload size in bytes. /// /// This limit used to reduce amount of consumed memory. #[arg( @@ -363,120 +332,81 @@ pub struct RustusConf { )] pub max_body_size: usize, - /// Rustus maximum log level - #[arg(long, default_value = "INFO", env = "RUSTUS_LOG_LEVEL")] - pub log_level: log::LevelFilter, - - /// Number of actix workers default value = number of cpu cores. - #[arg(long, short, env = "RUSTUS_WORKERS")] - pub workers: Option, + /// Maximum size of file that can be uploaded. + /// + /// If not set, file size is unlimited. + #[arg(long, env = "RUSTUS_MAX_FILE_SIZE")] + pub max_file_size: Option, - /// Enabled extensions for TUS protocol. #[arg( long, default_value = "getting,creation,termination,creation-with-upload,creation-defer-length,concatenation,checksum", env = "RUSTUS_TUS_EXTENSIONS", use_value_delimiter = true )] - pub tus_extensions: Vec, - - /// Enabling this parameter - /// Will allow creation of empty files - /// when Upload-Length header equals to 0. - #[arg(long, env = "RUSTUS_ALLOW_EMPTY")] - pub allow_empty: bool, + pub tus_extensions: Vec, - /// Remove part files after concatenation is done. - /// By default rustus does nothing with part files after concatenation. + /// Allowed hosts for CORS protocol. /// - /// This parameter is only needed if concatenation extension is enabled. - #[arg(long, env = "RUSTUS_REMOVE_PARTS")] - pub remove_parts: bool, + /// By default all hosts are allowed. + #[arg(long, env = "RUSTUS_CORS", use_value_delimiter = true)] + pub cors: Vec, - /// Maximum size of file that can be uploaded. - /// - /// If not set, file size is unlimited. - #[arg(long, env = "RUSTUS_MAX_FILE_SIZE")] - pub max_file_size: Option, + /// Use this option if you use rustus + /// behind any proxy. Like Nginx or Traefik. + #[arg(long, env = "RUSTUS_BEHIND_PROXY")] + pub behind_proxy: bool, - #[command(flatten)] - pub storage_opts: StorageOptions, + // We skip this argument, because we won't going to + // fullfill it from CLI. This argument is populated based + // on `tus_extensions` argument. + #[arg(skip)] + pub tus_extensions_set: rustc_hash::FxHashSet, + + #[arg(skip)] + pub notification_hooks_set: rustc_hash::FxHashSet, #[command(flatten)] - pub info_storage_opts: InfoStoreOptions, + pub info_storage_config: InfoStorageConfig, #[command(flatten)] - pub notification_opts: NotificationsOptions, + pub data_storage_config: DataStorageConfig, #[command(flatten)] - pub sentry_opts: SentryOptions, + pub notification_config: NotificationConfig, } -#[cfg_attr(coverage, no_coverage)] -impl RustusConf { - /// Function to parse CLI parametes. - /// - /// This is a workaround for issue mentioned - /// [here](https://www.reddit.com/r/rust/comments/8ddd19/confusion_with_splitting_mainrs_into_smaller/). - pub fn from_args() -> RustusConf { - let mut conf = RustusConf::parse(); - conf.normalize_extentions(); - conf +impl Config { + #[must_use] + pub fn parse() -> Self { + let mut config = ::parse(); + config.prepare(); + config } - pub fn from_iter(iter: I) -> RustusConf - where - I: IntoIterator, - I::Item: Into + Clone, - { - ::parse_from(iter) - } - - /// Base API url. - pub fn base_url(&self) -> String { - let stripped_prefix = self.url.strip_prefix('/').unwrap_or(self.url.as_str()); - String::from(stripped_prefix.strip_suffix('/').unwrap_or(stripped_prefix)) - } + pub fn prepare(&mut self) { + // Update URL prefix. This is needed to make sure that + // URLs are correctly generated. + self.url = self.url.trim_end_matches('/').to_string(); - /// Helper for generating URI for test files. - #[cfg(test)] - pub fn file_url(&self, file_id: &str) -> String { - format!("/{}/{}/", self.base_url(), file_id) - } - - #[cfg(test)] - pub fn test_url(&self) -> String { - format!("/{}/", self.base_url()) - } - - /// Check if hook is enabled by user. - pub fn hook_is_active(&self, hook: Hook) -> bool { - self.notification_opts.hooks.contains(&hook) - } - - /// Normalize extension vec. - /// - /// Nomralization consists of two parts: - /// 1. Adding dependent extentions (e.g. creation-with-upload depends on creation); - /// 2. Sorting the resulting extentions; - /// - /// Protocol extensions must be sorted, - /// because Actix doesn't override - /// existing methods. - pub fn normalize_extentions(&mut self) { - let ext = &mut self.tus_extensions; - // If create-with-upload extension is enabled - // creation extension must be enabled too. - if ext.contains(&Extensions::CreationWithUpload) && !ext.contains(&Extensions::Creation) { - ext.push(Extensions::Creation); + for hook in &self.notification_config.hooks { + self.notification_hooks_set.insert(*hook); } - // If create-defer-length extension is enabled - // creation extension must be enabled too. - if ext.contains(&Extensions::CreationDeferLength) && !ext.contains(&Extensions::Creation) { - ext.push(Extensions::Creation); + // We want to build a hashmap with all extensions. Because it + // is going to be much faster to work with in the future. + for extension in self.tus_extensions.clone() { + if extension == TusExtensions::CreationWithUpload + || extension == TusExtensions::CreationDeferLength + { + self.tus_extensions_set.insert(TusExtensions::Creation); + } + self.tus_extensions_set.insert(extension); } + } - ext.sort(); + #[must_use] + pub fn get_url(&self, url: &str) -> String { + format!("{}/{url}", self.url) } } diff --git a/src/storages/models/storage.rs b/src/data_storage/base.rs similarity index 79% rename from src/storages/models/storage.rs rename to src/data_storage/base.rs index 56d0563..6868feb 100644 --- a/src/storages/models/storage.rs +++ b/src/data_storage/base.rs @@ -1,12 +1,14 @@ -use crate::{errors::RustusResult, info_storages::FileInfo}; -use actix_web::{HttpRequest, HttpResponse}; -use async_trait::async_trait; use bytes::Bytes; -use dyn_clone::DynClone; -use std::fmt::Display; -#[async_trait(?Send)] -pub trait Storage: Display + DynClone { +use crate::{errors::RustusResult, models::file_info::FileInfo}; + +pub trait Storage { + /// Get name of a storage. + /// + /// Used to store storage reference in + /// file information. + fn get_name(&self) -> &'static str; + /// Prepare storage before starting up server. /// /// Function to check if configuration is correct @@ -20,17 +22,12 @@ pub trait Storage: Display + DynClone { /// Get contents of a file. /// - /// This method must return HttpResponse. + /// This method must return `HttpResponse`. /// This resposne would be sent directly. /// /// # Params /// `file_info` - info about current file. - /// `request` - this parameter is needed to construct responses in some case - async fn get_contents( - &self, - file_info: &FileInfo, - request: &HttpRequest, - ) -> RustusResult; + async fn get_contents(&self, file_info: &FileInfo) -> RustusResult; /// Add bytes to the file. /// @@ -82,5 +79,3 @@ pub trait Storage: Display + DynClone { /// `file_info` - info about current file. async fn remove_file(&self, file_info: &FileInfo) -> RustusResult<()>; } - -dyn_clone::clone_trait_object!(Storage); diff --git a/src/data_storage/impls/file_storage.rs b/src/data_storage/impls/file_storage.rs new file mode 100644 index 0000000..55ff30a --- /dev/null +++ b/src/data_storage/impls/file_storage.rs @@ -0,0 +1,182 @@ +use std::{io::Write, path::PathBuf}; + +use axum::response::{IntoResponse, Response}; +use bytes::Bytes; +use log::error; +use std::{ + fs::{remove_file, DirBuilder, OpenOptions}, + io::{copy, BufReader, BufWriter}, +}; + +use crate::{ + data_storage::base::Storage, + errors::{RustusError, RustusResult}, + models::file_info::FileInfo, + utils::{dir_struct::substr_now, headers::HeaderMapExt}, +}; + +#[derive(Clone)] +pub struct FileStorage { + data_dir: PathBuf, + dir_struct: String, + force_fsync: bool, +} + +impl FileStorage { + #[must_use] + pub fn new(data_dir: PathBuf, dir_struct: String, force_fsync: bool) -> FileStorage { + FileStorage { + data_dir, + dir_struct, + force_fsync, + } + } + + /// Create path to file in a data directory. + /// + /// This function is using template from `dir_struct` field + /// and based on it creates path to file. + /// + /// # Errors + /// + /// Might retur an error, if path is invalid, or directory cannot be created. + pub fn data_file_path(&self, file_id: &str) -> RustusResult { + let dir = self + .data_dir + // We're working wit absolute paths, because tus.io says so. + .canonicalize()? + .join(substr_now(self.dir_struct.as_str())); + DirBuilder::new().recursive(true).create(dir.as_path())?; + Ok(dir.join(file_id)) + } +} + +impl Storage for FileStorage { + fn get_name(&self) -> &'static str { + "file" + } + + async fn prepare(&mut self) -> RustusResult<()> { + // We're creating directory for new files + // if it doesn't already exist. + if !self.data_dir.exists() { + DirBuilder::new() + .recursive(true) + .create(self.data_dir.as_path())?; + } + Ok(()) + } + + async fn get_contents(&self, file_info: &FileInfo) -> RustusResult { + if file_info.path.is_none() { + return Err(RustusError::FileNotFound); + }; + let file = tokio::fs::File::open(file_info.path.clone().unwrap().as_str()) + .await + .map_err(|_| RustusError::FileNotFound)?; + let buf_file = tokio::io::BufReader::new(file); + let reader = tokio_util::io::ReaderStream::new(buf_file); + let mut resp = axum::body::Body::from_stream(reader).into_response(); + resp.headers_mut() + .generate_disposition(file_info.get_filename()); + Ok(resp) + } + + async fn add_bytes(&self, file_info: &FileInfo, bytes: Bytes) -> RustusResult<()> { + // In normal situation this `if` statement is not + // gonna be called, but what if it is ... + if file_info.path.is_none() { + return Err(RustusError::FileNotFound); + } + let path = file_info.path.as_ref().unwrap().clone(); + let force_sync = self.force_fsync; + tokio::task::spawn_blocking(move || { + // Opening file in w+a mode. + // It means that we're going to append some + // bytes to the end of a file. + let file = OpenOptions::new() + .write(true) + .append(true) + .create(false) + .read(false) + .truncate(false) + .open(path.as_str())?; + let mut writer = BufWriter::new(file); + writer.write_all(bytes.as_ref())?; + writer.flush()?; + if force_sync { + writer.get_ref().sync_data()?; + } + Ok(()) + }) + .await? + } + + async fn create_file(&self, file_info: &FileInfo) -> RustusResult { + // New path to file. + let file_path = self.data_file_path(file_info.id.as_str())?; + OpenOptions::new() + .create(true) + .write(true) + .truncate(true) + .create_new(true) + .open(file_path.as_path())?; + Ok(file_path.display().to_string()) + } + + async fn concat_files( + &self, + file_info: &FileInfo, + parts_info: Vec, + ) -> RustusResult<()> { + let force_fsync = self.force_fsync; + if file_info.path.is_none() { + return Err(RustusError::FileNotFound); + } + let path = file_info.path.as_ref().unwrap().clone(); + tokio::task::spawn_blocking(move || { + let file = OpenOptions::new() + .write(true) + .append(true) + .create(true) + .open(path)?; + let mut writer = BufWriter::new(file); + for part in parts_info { + if part.path.is_none() { + return Err(RustusError::FileNotFound); + } + let part_file = OpenOptions::new() + .read(true) + .open(part.path.as_ref().unwrap())?; + let mut reader = BufReader::new(part_file); + copy(&mut reader, &mut writer)?; + } + writer.flush()?; + if force_fsync { + writer.get_ref().sync_data()?; + } + Ok(()) + }) + .await? + } + + async fn remove_file(&self, file_info: &FileInfo) -> RustusResult<()> { + let info = file_info.clone(); + if info.path.is_none() { + return Err(RustusError::FileNotFound); + } + tokio::task::spawn_blocking(move || { + // Let's remove the file itself. + let data_path = PathBuf::from(info.path.as_ref().unwrap().clone()); + if !data_path.exists() { + return Err(RustusError::FileNotFound); + } + remove_file(data_path).map_err(|err| { + error!("{:?}", err); + RustusError::UnableToRemove(info.id.clone()) + })?; + Ok(()) + }) + .await? + } +} diff --git a/src/data_storage/impls/mod.rs b/src/data_storage/impls/mod.rs new file mode 100644 index 0000000..54c3b3f --- /dev/null +++ b/src/data_storage/impls/mod.rs @@ -0,0 +1,2 @@ +pub mod file_storage; +pub mod s3_hybrid; diff --git a/src/storages/s3_hybrid_storage.rs b/src/data_storage/impls/s3_hybrid.rs similarity index 77% rename from src/storages/s3_hybrid_storage.rs rename to src/data_storage/impls/s3_hybrid.rs index 7c6139f..d6e7821 100644 --- a/src/storages/s3_hybrid_storage.rs +++ b/src/data_storage/impls/s3_hybrid.rs @@ -1,19 +1,23 @@ use std::{collections::HashMap, path::PathBuf}; use crate::{ + data_storage::base::Storage, errors::{RustusError, RustusResult}, - info_storages::FileInfo, - utils::headers::generate_disposition, + models::file_info::FileInfo, + utils::{headers::HeaderMapExt, result::MonadLogger}, }; -use super::Storage; -use crate::{storages::file_storage::FileStorage, utils::dir_struct::substr_time}; +use crate::utils::dir_struct::substr_time; -use actix_web::{HttpRequest, HttpResponse, HttpResponseBuilder}; -use async_trait::async_trait; +use axum::response::{IntoResponse, Response}; use bytes::Bytes; -use derive_more::Display; -use s3::{command::Command, request::Reqwest, request_trait::Request, Bucket}; +use s3::{ + command::Command, + request::{tokio_backend::Reqwest, Request as S3Request}, + Bucket, +}; + +use super::file_storage::FileStorage; /// This storage is useful for small files when you have chunks less than 5MB. /// This restriction is based on the S3 API limitations. @@ -22,8 +26,7 @@ use s3::{command::Command, request::Reqwest, request_trait::Request, Bucket}; /// complete, it uploads file to S3. /// /// It's not intended to use this storage for large files. -#[derive(Display, Clone)] -#[display(fmt = "s3_storage")] +#[derive(Clone)] pub struct S3HybridStorage { bucket: Bucket, local_storage: FileStorage, @@ -31,7 +34,14 @@ pub struct S3HybridStorage { } impl S3HybridStorage { + /// Create new `S3HybridStorage` instance. + /// + /// # Panics + /// + /// Might panic if credentials are invalid and cannot be parsed. + /// Or if bucket instance cannot be created. #[allow(clippy::too_many_arguments)] + #[must_use] pub fn new( endpoint: String, region: String, @@ -55,23 +65,17 @@ impl S3HybridStorage { session_token.as_deref(), profile.as_deref(), ); - if let Err(err) = creds { - panic!("Cannot build credentials: {err}") - } - log::debug!("Parsed credentials"); - let credentials = creds.unwrap(); + let credentials = creds.mlog_err("Cannot parse S3 credentials").unwrap(); let bucket = Bucket::new( bucket_name, s3::Region::Custom { region, endpoint }, credentials, ); - if let Err(error) = bucket { - panic!("Cannot create bucket instance {error}"); - } - let mut bucket = bucket.unwrap(); + let mut bucket = bucket.mlog_err("Cannot create bucket instance").unwrap(); if let Some(raw_s3_headers) = custom_headers { let headers_map = serde_json::from_str::>(raw_s3_headers) - .expect("Cannot parse s3 headers. Please provide valid JSON object."); + .mlog_err("Cannot parse s3 headers. Please provide valid JSON object.") + .unwrap(); log::debug!("Found extra s3 headers."); for (key, value) in &headers_map { log::debug!("Adding header `{key}` with value `{value}`."); @@ -118,29 +122,28 @@ impl S3HybridStorage { } } -#[async_trait(?Send)] impl Storage for S3HybridStorage { + fn get_name(&self) -> &'static str { + "s3_hybrid" + } + async fn prepare(&mut self) -> RustusResult<()> { Ok(()) } - async fn get_contents( - &self, - file_info: &FileInfo, - request: &HttpRequest, - ) -> RustusResult { + async fn get_contents(&self, file_info: &FileInfo) -> RustusResult { if file_info.length != Some(file_info.offset) { log::debug!("File isn't uploaded. Returning from local storage."); - return self.local_storage.get_contents(file_info, request).await; + return self.local_storage.get_contents(file_info).await; } let key = self.get_s3_key(file_info); let command = Command::GetObject; - let s3_request = Reqwest::new(&self.bucket, &key, command); - let s3_response = s3_request.response().await?; - let mut response = HttpResponseBuilder::new(actix_web::http::StatusCode::OK); - Ok(response - .insert_header(generate_disposition(file_info.get_filename())) - .streaming(s3_response.bytes_stream())) + let s3_request = Reqwest::new(&self.bucket, &key, command).unwrap(); + let s3_response = s3_request.response().await.unwrap(); + let mut resp = axum::body::Body::from_stream(s3_response.bytes_stream()).into_response(); + resp.headers_mut() + .generate_disposition(file_info.get_filename()); + Ok(resp) } async fn add_bytes(&self, file_info: &FileInfo, bytes: Bytes) -> RustusResult<()> { diff --git a/src/data_storage/mod.rs b/src/data_storage/mod.rs new file mode 100644 index 0000000..6007bcd --- /dev/null +++ b/src/data_storage/mod.rs @@ -0,0 +1,159 @@ +use std::{ + fs::File, + io::{BufReader, Read}, + path::PathBuf, +}; + +use crate::{config::Config, errors::RustusResult, from_str, utils::result::MonadLogger}; + +use self::impls::{file_storage::FileStorage, s3_hybrid::S3HybridStorage}; + +pub mod base; +pub mod impls; + +#[derive(Clone, Debug, strum::Display, strum::EnumIter)] +pub enum AvailableStorages { + #[strum(serialize = "file-storage")] + File, + #[strum(serialize = "hybrid-s3")] + S3Hybrid, +} + +from_str!(AvailableStorages, "storages"); + +#[derive(Clone)] +pub enum DataStorageImpl { + File(FileStorage), + S3Hybrid(S3HybridStorage), +} + +impl DataStorageImpl { + /// Create `DataStorage` from config. + /// + /// This function creates a generic storage, which might hold any kind of data storage. + /// + /// # Panics + /// + /// Might panic if one of required fields is not set for `S3Hybrid` storage, + /// and `S3Hybrid` is selected as data storage. + #[must_use] + pub fn new(config: &Config) -> Self { + let data_conf = config.data_storage_config.clone(); + match data_conf.storage { + AvailableStorages::File => Self::File(FileStorage::new( + data_conf.data_dir, + data_conf.dir_structure, + data_conf.force_fsync, + )), + AvailableStorages::S3Hybrid => { + let access_key = + from_string_or_path(&data_conf.s3_access_key, &data_conf.s3_access_key_path); + let secret_key = + from_string_or_path(&data_conf.s3_secret_key, &data_conf.s3_secret_key_path); + Self::S3Hybrid(S3HybridStorage::new( + data_conf.s3_url.clone().mlog_err("S3 URL").unwrap(), + data_conf.s3_region.clone().mlog_err("S3 Region").unwrap(), + &Some(access_key), + &Some(secret_key), + &data_conf.s3_security_token, + &data_conf.s3_session_token, + &data_conf.s3_profile, + &data_conf.s3_headers, + data_conf + .s3_bucket + .clone() + .mlog_err("S3 bucket") + .unwrap() + .as_str(), + data_conf.s3_force_path_style, + data_conf.data_dir.clone(), + data_conf.dir_structure.clone(), + data_conf.force_fsync, + )) + } + } + } +} + +impl base::Storage for DataStorageImpl { + fn get_name(&self) -> &'static str { + match self { + Self::File(file) => file.get_name(), + Self::S3Hybrid(s3) => s3.get_name(), + } + } + + async fn prepare(&mut self) -> RustusResult<()> { + match self { + Self::File(file) => file.prepare().await, + Self::S3Hybrid(s3) => s3.prepare().await, + } + } + + async fn get_contents( + &self, + file_info: &crate::models::file_info::FileInfo, + ) -> crate::errors::RustusResult { + match self { + Self::File(file) => file.get_contents(file_info).await, + Self::S3Hybrid(s3) => s3.get_contents(file_info).await, + } + } + + async fn add_bytes( + &self, + file_info: &crate::models::file_info::FileInfo, + bytes: bytes::Bytes, + ) -> RustusResult<()> { + match self { + Self::File(file) => file.add_bytes(file_info, bytes).await, + Self::S3Hybrid(s3) => s3.add_bytes(file_info, bytes).await, + } + } + + async fn create_file( + &self, + file_info: &crate::models::file_info::FileInfo, + ) -> RustusResult { + match self { + Self::File(file) => file.create_file(file_info).await, + Self::S3Hybrid(s3) => s3.create_file(file_info).await, + } + } + + async fn concat_files( + &self, + file_info: &crate::models::file_info::FileInfo, + parts_info: Vec, + ) -> RustusResult<()> { + match self { + Self::File(file) => file.concat_files(file_info, parts_info).await, + Self::S3Hybrid(s3) => s3.concat_files(file_info, parts_info).await, + } + } + + async fn remove_file( + &self, + file_info: &crate::models::file_info::FileInfo, + ) -> RustusResult<()> { + match self { + Self::File(file) => file.remove_file(file_info).await, + Self::S3Hybrid(s3) => s3.remove_file(file_info).await, + } + } +} +fn from_string_or_path(variable: &Option, path: &Option) -> String { + if let Some(variable) = variable { + variable.to_string() + } else if let Some(path) = path { + let file = + File::open(path).unwrap_or_else(|_| panic!("failed to open path {}", path.display())); + let mut contents = String::new(); + BufReader::new(file) + .read_to_string(&mut contents) + .unwrap_or_else(|_| panic!("failed to read from path {}", path.display())); + contents + } else { + panic!("can't find {variable:?} or path {path:?}") + } +} diff --git a/src/errors.rs b/src/errors.rs index 0b40092..7fdd2b7 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,8 +1,10 @@ use std::io::{Error, ErrorKind}; -use actix_web::{http::StatusCode, HttpResponse, HttpResponseBuilder, ResponseError}; +use axum::response::IntoResponse; use log::error; +use axum::http::StatusCode; + pub type RustusResult = Result; #[derive(thiserror::Error, Debug)] @@ -23,15 +25,10 @@ pub enum RustusError { SizeAlreadyKnown, #[error("Unable to serialize object")] UnableToSerialize(#[from] serde_json::Error), - #[cfg(feature = "db_info_storage")] - #[error("Database error: {0}")] - DatabaseError(#[from] rbatis::error::Error), - #[cfg(feature = "redis_info_storage")] #[error("Redis error: {0}")] RedisError(#[from] redis::RedisError), - #[cfg(feature = "redis_info_storage")] #[error("Redis pooling error: {0}")] - MobcError(#[from] bb8::RunError), + MobcError(#[from] mobc::Error), #[error("Unable to get file information")] UnableToReadInfo, #[error("Unable to write file {0}")] @@ -50,12 +47,10 @@ pub enum RustusError { HookError(String), #[error("Unable to configure logging: {0}")] LogConfigError(#[from] log::SetLoggerError), - #[cfg(feature = "amqp_notifier")] #[error("AMQP error: {0}")] AMQPError(#[from] lapin::Error), - #[cfg(feature = "amqp_notifier")] #[error("AMQP pooling error error: {0}")] - AMQPPoolError(#[from] bb8::RunError), + AMQPPoolError(#[from] mobc::Error), #[error("Std error: {0}")] StdError(#[from] std::io::Error), #[error("Can't spawn task: {0}")] @@ -66,14 +61,14 @@ pub enum RustusError { WrongChecksum, #[error("The header value is incorrect")] WrongHeaderValue, - #[error("Metrics error: {0}")] - PrometheusError(#[from] prometheus::Error), - #[error("Blocking error: {0}")] - BlockingError(#[from] actix_web::error::BlockingError), #[error("HTTP hook error. Returned status: {0}, Response text: {1}")] HTTPHookError(u16, String, Option), #[error("Found S3 error: {0}")] S3Error(#[from] s3::error::S3Error), + #[error("Found invalid header: {0}")] + InvalidHeader(#[from] axum::http::header::InvalidHeaderValue), + #[error("HTTP error: {0}")] + AxumHTTPError(#[from] axum::http::Error), } /// This conversion allows us to use `RustusError` in the `main` function. @@ -84,29 +79,8 @@ impl From for Error { } } -/// Trait to convert errors to http-responses. -#[cfg_attr(coverage, no_coverage)] -impl ResponseError for RustusError { - fn error_response(&self) -> HttpResponse { - error!("{}", self); - match self { - RustusError::HTTPHookError(_, proxy_response, content_type) => { - HttpResponseBuilder::new(self.status_code()) - .insert_header(( - "Content-Type", - content_type - .as_deref() - .unwrap_or("text/plain; charset=utf-8"), - )) - .body(proxy_response.clone()) - } - _ => HttpResponseBuilder::new(self.status_code()) - .insert_header(("Content-Type", "text/html; charset=utf-8")) - .body(format!("{self}")), - } - } - - fn status_code(&self) -> StatusCode { +impl RustusError { + fn get_status_code(&self) -> StatusCode { match self { RustusError::FileNotFound => StatusCode::NOT_FOUND, RustusError::WrongOffset => StatusCode::CONFLICT, @@ -123,3 +97,27 @@ impl ResponseError for RustusError { } } } + +impl IntoResponse for RustusError { + fn into_response(self) -> axum::response::Response { + log::error!("{self}"); + let status_code = self.get_status_code(); + match self { + RustusError::HTTPHookError(_, proxy_response, content_type) => { + axum::response::IntoResponse::into_response(( + status_code, + [( + "Content-Type", + content_type.unwrap_or("text/plain; charset=utf-8".into()), + )], + proxy_response, + )) + } + _ => axum::response::IntoResponse::into_response(( + status_code, + [("Content-Type", "text/html; charset=utf-8")], + format!("{self}"), + )), + } + } +} diff --git a/src/extensions.rs b/src/extensions.rs new file mode 100644 index 0000000..cd9f813 --- /dev/null +++ b/src/extensions.rs @@ -0,0 +1,19 @@ +#[derive(Copy, strum::Display, Debug, strum::EnumIter, Clone, PartialEq, Eq, Hash)] +pub enum TusExtensions { + #[strum(serialize = "creation-defer-length")] + CreationDeferLength, + #[strum(serialize = "creation-with-upload")] + CreationWithUpload, + #[strum(serialize = "creation")] + Creation, + #[strum(serialize = "termination")] + Termination, + #[strum(serialize = "concatenation")] + Concatenation, + #[strum(serialize = "getting")] + Getting, + #[strum(serialize = "checksum")] + Checksum, +} + +crate::from_str!(TusExtensions, "extensions"); diff --git a/src/info_storages/models/info_store.rs b/src/info_storages/base.rs similarity index 82% rename from src/info_storages/models/info_store.rs rename to src/info_storages/base.rs index c7ffb25..3e480da 100644 --- a/src/info_storages/models/info_store.rs +++ b/src/info_storages/base.rs @@ -1,13 +1,9 @@ -use crate::{errors::RustusResult, info_storages::FileInfo}; -use async_trait::async_trait; -use dyn_clone::DynClone; - +use crate::{errors::RustusResult, models::file_info::FileInfo}; /// Trait for every info storage. /// /// This trait defines required functions /// for building your own info storage. -#[async_trait(?Send)] -pub trait InfoStorage: DynClone { +pub trait InfoStorage { /// Prepare storage for storing files. /// /// In this function you can prepare @@ -18,7 +14,7 @@ pub trait InfoStorage: DynClone { /// Set information about an upload. /// /// This function **must** persist information - /// about given upload so it can be accessed again by file_id. + /// about given upload so it can be accessed again by `file_id`. /// /// The `create` parameter is for optimizations. /// It's here, because some storages like databases have to @@ -40,5 +36,3 @@ pub trait InfoStorage: DynClone { /// associated with the given `file_id`. async fn remove_info(&self, file_id: &str) -> RustusResult<()>; } - -dyn_clone::clone_trait_object!(InfoStorage); diff --git a/src/info_storages/db_info_storage.rs b/src/info_storages/db_info_storage.rs deleted file mode 100644 index c2d599a..0000000 --- a/src/info_storages/db_info_storage.rs +++ /dev/null @@ -1,144 +0,0 @@ -use std::{sync::Arc, time::Duration}; - -use async_trait::async_trait; -use rbatis::{crud::CRUD, crud_table, db::DBPoolOptions, rbatis::Rbatis}; - -use crate::{ - errors::{RustusError, RustusResult}, - info_storages::{FileInfo, InfoStorage}, -}; - -#[crud_table] -struct DbModel { - pub id: String, - pub info: String, -} - -impl TryFrom<&FileInfo> for DbModel { - type Error = RustusError; - - fn try_from(value: &FileInfo) -> Result { - Ok(DbModel { - id: value.id.clone(), - info: serde_json::to_string(value)?, - }) - } -} - -#[derive(Clone)] -pub struct DBInfoStorage { - db: Arc, -} - -impl DBInfoStorage { - pub async fn new(dsn: &str) -> RustusResult { - let db = Rbatis::new(); - let mut opts = DBPoolOptions::new(); - opts.connect_timeout = Duration::new(2, 0); - db.link_opt(dsn, opts).await?; - Ok(Self { db: Arc::new(db) }) - } -} - -#[async_trait(?Send)] -impl InfoStorage for DBInfoStorage { - async fn prepare(&mut self) -> RustusResult<()> { - self.db - .exec( - "CREATE TABLE IF NOT EXISTS db_model (id VARCHAR(40) PRIMARY KEY, info TEXT);", - Vec::new(), - ) - .await?; - Ok(()) - } - - async fn set_info(&self, file_info: &FileInfo, create: bool) -> RustusResult<()> { - let model = DbModel::try_from(file_info)?; - if create { - self.db.save(&model, &[]).await?; - } else { - self.db.update_by_column("id", &model).await?; - } - Ok(()) - } - - async fn get_info(&self, file_id: &str) -> RustusResult { - let model: Option = self.db.fetch_by_column("id", file_id).await?; - if let Some(info) = model { - FileInfo::from_json(info.info.to_string()).await - } else { - Err(RustusError::FileNotFound) - } - } - - async fn remove_info(&self, file_id: &str) -> RustusResult<()> { - self.db - .remove_by_column::("id", file_id) - .await?; - Ok(()) - } -} - -#[cfg(feature = "test_db")] -#[cfg(test)] -mod tests { - use super::{DBInfoStorage, DbModel}; - use crate::{info_storages::FileInfo, InfoStorage}; - use rbatis::crud::CRUD; - - async fn get_info_storage() -> DBInfoStorage { - let db_url = std::env::var("TEST_DB_URL").unwrap(); - let mut storage = DBInfoStorage::new(db_url.as_str()).await.unwrap(); - storage.prepare().await.unwrap(); - storage - } - - #[actix_rt::test] - async fn success() { - let info_storage = get_info_storage().await; - let file_info = FileInfo::new_test(); - info_storage.set_info(&file_info, true).await.unwrap(); - let info = info_storage - .db - .fetch_by_column::, &str>("id", file_info.id.as_str()) - .await - .unwrap(); - assert!(info.is_some()); - let info = info_storage.get_info(file_info.id.as_str()).await.unwrap(); - assert_eq!(file_info.id, info.id); - assert_eq!(file_info.storage, info.storage); - assert_eq!(file_info.length, info.length); - } - - #[actix_rt::test] - async fn success_deletion() { - let info_storage = get_info_storage().await; - let file_info = FileInfo::new_test(); - info_storage.set_info(&file_info, true).await.unwrap(); - info_storage - .remove_info(file_info.id.as_str()) - .await - .unwrap(); - let info = info_storage - .db - .fetch_by_column::, &str>("id", file_info.id.as_str()) - .await - .unwrap(); - assert!(info.is_none()); - } - - #[actix_rt::test] - async fn deletion_not_found() { - let info_storage = get_info_storage().await; - let res = info_storage.remove_info("unknown").await; - // We don't care if it doesn't exist. - assert!(res.is_ok()); - } - - #[actix_rt::test] - async fn getting_not_found() { - let info_storage = get_info_storage().await; - let res = info_storage.get_info("unknown").await; - assert!(res.is_err()); - } -} diff --git a/src/info_storages/file_info_storage.rs b/src/info_storages/file_info_storage.rs deleted file mode 100644 index 15f58d2..0000000 --- a/src/info_storages/file_info_storage.rs +++ /dev/null @@ -1,175 +0,0 @@ -use std::{ - io::{Read, Write}, - path::PathBuf, -}; - -use async_trait::async_trait; -use log::error; -use std::{ - fs::{remove_file, File, OpenOptions}, - io::{BufReader, BufWriter}, -}; -use tokio::fs::DirBuilder; - -use crate::{ - errors::{RustusError, RustusResult}, - info_storages::{FileInfo, InfoStorage}, -}; - -#[derive(Clone)] -pub struct FileInfoStorage { - info_dir: PathBuf, -} - -impl FileInfoStorage { - pub fn new(info_dir: PathBuf) -> Self { - Self { info_dir } - } - - pub fn info_file_path(&self, file_id: &str) -> PathBuf { - self.info_dir.join(format!("{file_id}.info")) - } -} - -#[async_trait(?Send)] -impl InfoStorage for FileInfoStorage { - async fn prepare(&mut self) -> RustusResult<()> { - if !self.info_dir.exists() { - DirBuilder::new() - .create(self.info_dir.as_path()) - .await - .map_err(|err| RustusError::UnableToPrepareInfoStorage(err.to_string()))?; - } - Ok(()) - } - - async fn set_info(&self, file_info: &FileInfo, create: bool) -> RustusResult<()> { - let info = file_info.clone(); - let path = self.info_file_path(info.id.as_str()); - tokio::task::spawn_blocking(move || { - let file = OpenOptions::new() - .write(true) - .create(create) - .truncate(true) - .open(path) - .map_err(|err| { - error!("{:?}", err); - RustusError::UnableToWrite(err.to_string()) - })?; - let data = serde_json::to_string(&info).map_err(RustusError::from)?; - { - let mut writer = BufWriter::new(file); - writer.write_all(data.as_bytes())?; - writer.flush()?; - } - Ok(()) - }) - .await? - } - - async fn get_info(&self, file_id: &str) -> RustusResult { - let info_path = self.info_file_path(file_id); - tokio::task::spawn_blocking(move || { - if !info_path.exists() { - return Err(RustusError::FileNotFound); - } - let info = File::open(info_path)?; - let mut contents = String::new(); - let mut reader = BufReader::new(info); - reader.read_to_string(&mut contents)?; - serde_json::from_str::(contents.as_str()).map_err(RustusError::from) - }) - .await? - } - - async fn remove_info(&self, file_id: &str) -> RustusResult<()> { - let id = String::from(file_id); - let info_path = self.info_file_path(id.as_str()); - tokio::task::spawn_blocking(move || { - if !info_path.exists() { - return Err(RustusError::FileNotFound); - } - remove_file(info_path).map_err(|err| { - error!("{:?}", err); - RustusError::UnableToRemove(id) - }) - }) - .await? - } -} - -#[cfg(test)] -mod tests { - use super::FileInfoStorage; - use crate::{info_storages::FileInfo, InfoStorage}; - use std::{ - collections::HashMap, - fs::File, - io::{Read, Write}, - }; - - #[actix_rt::test] - async fn preparation() { - let dir = tempdir::TempDir::new("file_info").unwrap(); - let target_path = dir.into_path().join("not_exist"); - let mut storage = FileInfoStorage::new(target_path.clone()); - assert!(!target_path.exists()); - storage.prepare().await.unwrap(); - assert!(target_path.exists()); - } - - #[actix_rt::test] - async fn setting_info() { - let dir = tempdir::TempDir::new("file_info").unwrap(); - let storage = FileInfoStorage::new(dir.into_path()); - let file_info = FileInfo::new( - uuid::Uuid::new_v4().to_string().as_str(), - Some(10), - Some("random_path".into()), - "random_storage".into(), - None, - ); - storage.set_info(&file_info, true).await.unwrap(); - let info_path = storage.info_file_path(file_info.id.as_str()); - let mut buffer = String::new(); - File::open(info_path) - .unwrap() - .read_to_string(&mut buffer) - .unwrap(); - assert!(buffer.len() > 0); - } - - #[actix_rt::test] - async fn set_get_info() { - let dir = tempdir::TempDir::new("file_info").unwrap(); - let storage = FileInfoStorage::new(dir.into_path()); - let file_info = FileInfo::new( - uuid::Uuid::new_v4().to_string().as_str(), - Some(10), - Some("random_path".into()), - "random_storage".into(), - { - let mut a = HashMap::new(); - a.insert("test".into(), "pest".into()); - Some(a) - }, - ); - storage.set_info(&file_info, true).await.unwrap(); - let read_info = storage.get_info(file_info.id.as_str()).await.unwrap(); - assert_eq!(read_info.id, read_info.id); - assert_eq!(read_info.length, read_info.length); - assert_eq!(read_info.path, read_info.path); - assert_eq!(read_info.metadata, read_info.metadata); - } - - #[actix_rt::test] - async fn get_broken_info() { - let dir = tempdir::TempDir::new("file_info").unwrap(); - let storage = FileInfoStorage::new(dir.into_path()); - let file_id = "random_file"; - let mut file = File::create(storage.info_file_path(file_id)).unwrap(); - file.write_all("{not a json}".as_bytes()).unwrap(); - let read_info = storage.get_info(file_id).await; - assert!(read_info.is_err()); - } -} diff --git a/src/info_storages/impls/file_info_storage.rs b/src/info_storages/impls/file_info_storage.rs new file mode 100644 index 0000000..8d44c61 --- /dev/null +++ b/src/info_storages/impls/file_info_storage.rs @@ -0,0 +1,74 @@ +use std::path::PathBuf; + +use tokio::fs::DirBuilder; + +use crate::{ + errors::{RustusError, RustusResult}, + info_storages::base::InfoStorage, + models::file_info::FileInfo, + utils::result::MonadLogger, +}; + +#[derive(Clone)] +pub struct FileInfoStorage { + info_dir: PathBuf, +} + +impl FileInfoStorage { + #[must_use] + pub fn new(info_dir: PathBuf) -> Self { + Self { info_dir } + } + + #[must_use] + pub fn info_file_path(&self, file_id: &str) -> PathBuf { + self.info_dir.join(format!("{file_id}.info")) + } +} + +impl InfoStorage for FileInfoStorage { + async fn prepare(&mut self) -> RustusResult<()> { + if !self.info_dir.exists() { + DirBuilder::new().create(self.info_dir.as_path()).await?; + } + Ok(()) + } + + async fn set_info(&self, file_info: &FileInfo, create: bool) -> RustusResult<()> { + let info = file_info.clone(); + let path = self.info_file_path(info.id.as_str()); + let file = tokio::fs::OpenOptions::new() + .write(true) + .create(create) + .truncate(true) + .open(path) + .await?; + let str_data = serde_json::to_string(file_info)?; + let mut writer = tokio::io::BufWriter::new(file); + tokio::io::copy_buf(&mut str_data.as_bytes(), &mut writer).await?; + Ok(()) + } + + async fn get_info(&self, file_id: &str) -> RustusResult { + let info_path = self.info_file_path(file_id); + let file = tokio::fs::File::open(info_path) + .await + .mlog_dbg("Cannot get info") + .map_err(|_| RustusError::FileNotFound)?; + let mut reader = tokio::io::BufReader::new(file); + let mut contents: Vec = vec![]; + tokio::io::copy_buf(&mut reader, &mut contents) + .await + .mlog_dbg("Cannot write bytes")?; + Ok(serde_json::from_slice::(contents.as_slice())?) + } + + async fn remove_info(&self, file_id: &str) -> RustusResult<()> { + let id = String::from(file_id); + let info_path = self.info_file_path(id.as_str()); + tokio::fs::remove_file(info_path) + .await + .map_err(|_| RustusError::FileNotFound)?; + Ok(()) + } +} diff --git a/src/info_storages/impls/mod.rs b/src/info_storages/impls/mod.rs new file mode 100644 index 0000000..73e8856 --- /dev/null +++ b/src/info_storages/impls/mod.rs @@ -0,0 +1,2 @@ +pub mod file_info_storage; +pub mod redis_info_storage; diff --git a/src/info_storages/impls/redis_info_storage.rs b/src/info_storages/impls/redis_info_storage.rs new file mode 100644 index 0000000..8d351f6 --- /dev/null +++ b/src/info_storages/impls/redis_info_storage.rs @@ -0,0 +1,101 @@ +use mobc::{Manager, Pool}; +use redis::aio::Connection; + +use crate::{ + errors::{RustusError, RustusResult}, + info_storages::base::InfoStorage, + models::file_info::FileInfo, +}; + +struct RedisConnectionManager { + client: redis::Client, +} + +impl RedisConnectionManager { + pub fn new(client: redis::Client) -> Self { + Self { client } + } +} + +#[async_trait::async_trait] +impl Manager for RedisConnectionManager { + type Connection = redis::aio::Connection; + type Error = redis::RedisError; + + async fn connect(&self) -> Result { + Ok(self.client.get_async_connection().await?) + } + + async fn check(&self, mut conn: Self::Connection) -> Result { + let pong: String = redis::cmd("PING").query_async(&mut conn).await?; + if pong.as_str() != "PONG" { + return Err((redis::ErrorKind::ResponseError, "pong response error").into()); + } + Ok(conn) + } +} + +#[derive(Clone)] +pub struct RedisStorage { + pool: Pool, + expiration: Option, +} + +impl RedisStorage { + /// Create new `RedisStorage`. + /// + /// # Errors + /// + /// Might return an error, if redis client cannot be created. + pub fn new(db_dsn: &str, expiration: Option) -> RustusResult { + let client = redis::Client::open(db_dsn)?; + let manager = RedisConnectionManager::new(client); + let pool = mobc::Pool::builder().max_open(100).build(manager); + Ok(Self { pool, expiration }) + } +} + +impl InfoStorage for RedisStorage { + async fn prepare(&mut self) -> RustusResult<()> { + Ok(()) + } + + async fn set_info(&self, file_info: &FileInfo, _create: bool) -> RustusResult<()> { + let mut conn = self.pool.get().await?; + let mut cmd = redis::cmd("SET"); + let mut cmd = cmd + .arg(file_info.id.as_str()) + .arg(serde_json::to_string(file_info)?); + if let Some(expiration) = self.expiration.as_ref() { + cmd = cmd.arg("EX").arg(expiration); + } + cmd.query_async::(&mut conn).await?; + Ok(()) + } + + async fn get_info(&self, file_id: &str) -> RustusResult { + let mut conn = self.pool.get().await?; + let res = redis::cmd("GET") + .arg(file_id) + .query_async::>(&mut conn) + .await?; + + if let Some(res) = res { + serde_json::from_str::(res.as_str()).map_err(RustusError::from) + } else { + Err(RustusError::FileNotFound) + } + } + + async fn remove_info(&self, file_id: &str) -> RustusResult<()> { + let mut conn = self.pool.get().await?; + let resp = redis::cmd("DEL") + .arg(file_id) + .query_async::>(&mut conn) + .await?; + match resp { + None | Some(0) => Err(RustusError::FileNotFound), + _ => Ok(()), + } + } +} diff --git a/src/info_storages/mod.rs b/src/info_storages/mod.rs index fe5d56d..8015583 100644 --- a/src/info_storages/mod.rs +++ b/src/info_storages/mod.rs @@ -1,12 +1,90 @@ -pub mod file_info_storage; +use crate::{config::Config, errors::RustusResult, from_str, utils::result::MonadLogger}; -#[cfg(feature = "db_info_storage")] -pub mod db_info_storage; -#[cfg(feature = "redis_info_storage")] -pub mod redis_info_storage; +pub mod base; +pub mod impls; -pub mod models; +use strum::{Display, EnumIter}; -pub use models::{ - available_info_storages::AvailableInfoStores, file_info::FileInfo, info_store::InfoStorage, -}; +use self::impls::{file_info_storage::FileInfoStorage, redis_info_storage::RedisStorage}; + +#[derive(Clone, Display, Debug, EnumIter)] +pub enum AvailableInfoStorages { + #[strum(serialize = "redis-info-storage")] + Redis, + #[strum(serialize = "file-info-storage")] + File, +} + +from_str!(AvailableInfoStorages, "info storage"); + +#[derive(Clone)] +pub enum InfoStorageImpl { + Redis(RedisStorage), + File(FileInfoStorage), +} + +impl InfoStorageImpl { + /// Create infoStorage from config. + /// + /// This is a generic storage, which might hold any kind of info storage. + /// + /// It implements the `InfoStorage` trait as well, so we don't need to use + /// boxes to call `InfoStorage` methods dynamically. + /// + /// # Errors + /// + /// Might return an error, if one if info storages cannot be created. + /// + /// # Panics + /// + /// This function panics if redis dsn is not set, and redis is selected as + /// info storage. + pub fn new(config: &Config) -> RustusResult { + let info_conf = config.info_storage_config.clone(); + match info_conf.info_storage { + AvailableInfoStorages::Redis => Ok(Self::Redis(RedisStorage::new( + info_conf + .info_db_dsn + .mlog_err("Cannot construct redis. DB DSN") + .unwrap() + .as_str(), + info_conf.redis_info_expiration, + )?)), + AvailableInfoStorages::File => Ok(Self::File(FileInfoStorage::new(info_conf.info_dir))), + } + } +} + +impl base::InfoStorage for InfoStorageImpl { + async fn prepare(&mut self) -> RustusResult<()> { + match self { + Self::Redis(redis) => redis.prepare().await, + Self::File(file) => file.prepare().await, + } + } + + async fn set_info( + &self, + file_info: &crate::models::file_info::FileInfo, + create: bool, + ) -> RustusResult<()> { + match self { + Self::Redis(redis) => redis.set_info(file_info, create).await, + Self::File(file) => file.set_info(file_info, create).await, + } + } + + async fn get_info(&self, file_id: &str) -> RustusResult { + match self { + Self::Redis(redis) => redis.get_info(file_id).await, + Self::File(file) => file.get_info(file_id).await, + } + } + + async fn remove_info(&self, file_id: &str) -> RustusResult<()> { + match self { + Self::Redis(redis) => redis.remove_info(file_id).await, + Self::File(file) => file.remove_info(file_id).await, + } + } +} diff --git a/src/info_storages/models/available_info_storages.rs b/src/info_storages/models/available_info_storages.rs deleted file mode 100644 index 4e83c1c..0000000 --- a/src/info_storages/models/available_info_storages.rs +++ /dev/null @@ -1,70 +0,0 @@ -use derive_more::{Display, From}; - -use crate::{errors::RustusResult, from_str, RustusConf}; - -use crate::info_storages::{file_info_storage, InfoStorage}; -use strum::EnumIter; - -#[cfg(feature = "db_info_storage")] -use crate::info_storages::db_info_storage; - -#[cfg(feature = "redis_info_storage")] -use crate::info_storages::redis_info_storage; - -#[derive(PartialEq, Eq, From, Display, Clone, Debug, EnumIter)] -pub enum AvailableInfoStores { - #[display(fmt = "file-info-storage")] - Files, - #[cfg(feature = "db_info_storage")] - #[display(fmt = "db-info-storage")] - DB, - #[cfg(feature = "redis_info_storage")] - #[display(fmt = "redis-info-storage")] - Redis, -} - -from_str!(AvailableInfoStores, "info storage"); - -impl AvailableInfoStores { - /// Convert `AvailableInfoStores` to the impl `InfoStorage`. - /// - /// # Params - /// `config` - Rustus configuration. - /// - #[cfg_attr(coverage, no_coverage)] - pub async fn get( - &self, - config: &RustusConf, - ) -> RustusResult> { - match self { - Self::Files => Ok(Box::new(file_info_storage::FileInfoStorage::new( - config.info_storage_opts.info_dir.clone(), - ))), - #[cfg(feature = "db_info_storage")] - Self::DB => Ok(Box::new( - db_info_storage::DBInfoStorage::new( - config - .info_storage_opts - .info_db_dsn - .clone() - .unwrap() - .as_str(), - ) - .await?, - )), - #[cfg(feature = "redis_info_storage")] - AvailableInfoStores::Redis => Ok(Box::new( - redis_info_storage::RedisStorage::new( - config - .info_storage_opts - .info_db_dsn - .clone() - .unwrap() - .as_str(), - config.info_storage_opts.redis_info_expiration, - ) - .await?, - )), - } - } -} diff --git a/src/info_storages/models/mod.rs b/src/info_storages/models/mod.rs deleted file mode 100644 index 3ed80cf..0000000 --- a/src/info_storages/models/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod available_info_storages; -pub mod file_info; -pub mod info_store; diff --git a/src/info_storages/redis_info_storage.rs b/src/info_storages/redis_info_storage.rs deleted file mode 100644 index 9539df1..0000000 --- a/src/info_storages/redis_info_storage.rs +++ /dev/null @@ -1,151 +0,0 @@ -use async_trait::async_trait; -// use mobc_redis::{mobc::Pool, redis, RedisConnectionManager}; -// use redis::aio::Connection; - -use bb8::Pool; -use bb8_redis::RedisConnectionManager; -use redis::aio::Connection; - -use crate::{ - errors::{RustusError, RustusResult}, - info_storages::{FileInfo, InfoStorage}, -}; - -#[derive(Clone)] -pub struct RedisStorage { - pool: Pool, - expiration: Option, -} - -impl RedisStorage { - #[allow(clippy::unused_async)] - pub async fn new(db_dsn: &str, expiration: Option) -> RustusResult { - let manager = RedisConnectionManager::new(db_dsn)?; - let pool = bb8::Pool::builder().max_size(100).build(manager).await?; - Ok(Self { pool, expiration }) - } -} - -#[async_trait(?Send)] -impl InfoStorage for RedisStorage { - async fn prepare(&mut self) -> RustusResult<()> { - Ok(()) - } - - async fn set_info(&self, file_info: &FileInfo, _create: bool) -> RustusResult<()> { - let mut conn = self.pool.get().await?; - let mut cmd = redis::cmd("SET"); - let mut cmd = cmd - .arg(file_info.id.as_str()) - .arg(file_info.json().await?.as_str()); - if let Some(expiration) = self.expiration.as_ref() { - cmd = cmd.arg("EX").arg(expiration); - } - cmd.query_async::(&mut conn) - .await - .map_err(RustusError::from)?; - Ok(()) - } - - async fn get_info(&self, file_id: &str) -> RustusResult { - let mut conn = self.pool.get().await?; - let res = redis::cmd("GET") - .arg(file_id) - .query_async::>(&mut conn) - .await?; - if res.is_none() { - return Err(RustusError::FileNotFound); - } - FileInfo::from_json(res.unwrap()).await - } - - async fn remove_info(&self, file_id: &str) -> RustusResult<()> { - let mut conn = self.pool.get().await?; - let resp = redis::cmd("DEL") - .arg(file_id) - .query_async::>(&mut conn) - .await?; - match resp { - None | Some(0) => Err(RustusError::FileNotFound), - _ => Ok(()), - } - } -} - -#[cfg(test)] -#[cfg(feature = "test_redis")] -mod tests { - use super::RedisStorage; - use crate::{info_storages::FileInfo, InfoStorage}; - use redis::AsyncCommands; - - async fn get_storage() -> RedisStorage { - let redis_url = std::env::var("TEST_REDIS_URL").unwrap(); - RedisStorage::new(redis_url.as_str(), None).await.unwrap() - } - - async fn get_redis() -> redis::aio::Connection { - let redis_url = std::env::var("TEST_REDIS_URL").unwrap(); - let redis = redis::Client::open(redis_url).unwrap(); - redis.get_async_connection().await.unwrap() - } - - #[actix_rt::test] - async fn success() { - let info_storage = get_storage().await; - let file_info = FileInfo::new_test(); - info_storage.set_info(&file_info, true).await.unwrap(); - let mut redis = get_redis().await; - let value: Option = redis.get(file_info.id.as_str()).await.unwrap(); - assert!(value.is_some()); - - let file_info_from_storage = info_storage.get_info(file_info.id.as_str()).await.unwrap(); - - assert_eq!(file_info.id, file_info_from_storage.id); - assert_eq!(file_info.path, file_info_from_storage.path); - assert_eq!(file_info.storage, file_info_from_storage.storage); - } - - #[actix_rt::test] - async fn no_connection() { - let info_storage = RedisStorage::new("redis://unknonwn_url/0", None) - .await - .unwrap(); - let file_info = FileInfo::new_test(); - let res = info_storage.set_info(&file_info, true).await; - assert!(res.is_err()); - } - - #[actix_rt::test] - async fn unknown_id() { - let info_storage = get_storage().await; - let res = info_storage - .get_info(uuid::Uuid::new_v4().to_string().as_str()) - .await; - assert!(res.is_err()); - } - - #[actix_rt::test] - async fn expiration() { - let info_storage = get_storage().await; - let res = info_storage - .get_info(uuid::Uuid::new_v4().to_string().as_str()) - .await; - assert!(res.is_err()); - } - - #[actix_rt::test] - async fn deletion_success() { - let mut info_storage = get_storage().await; - info_storage.expiration = Some(1); - let mut redis = get_redis().await; - let file_info = FileInfo::new_test(); - info_storage.set_info(&file_info, true).await.unwrap(); - tokio::time::sleep(std::time::Duration::from_secs(2)).await; - assert!(redis - .get::<&str, Option>(file_info.id.as_str()) - .await - .unwrap() - .is_none()); - } -} diff --git a/src/main.rs b/src/main.rs index 228383d..5abed8f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,234 +1,28 @@ -#![cfg_attr(coverage, feature(no_coverage))] +#![allow(async_fn_in_trait)] -#[global_allocator] -static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; - -use std::str::FromStr; - -use actix_cors::Cors; -use actix_web::{ - dev::{Server, Service}, - http::{KeepAlive, Method}, - middleware, web, App, HttpServer, -}; +use errors::RustusResult; use fern::{ colors::{Color, ColoredLevelConfig}, Dispatch, }; -use log::{error, LevelFilter}; - -use config::RustusConf; - -use metrics::RustusMetrics; -use wildmatch::WildMatch; - -use crate::{ - errors::{RustusError, RustusResult}, - info_storages::InfoStorage, - notifiers::models::notification_manager::NotificationManager, - server::rustus_service, - state::State, - storages::Storage, -}; - -mod config; -mod errors; -mod info_storages; -mod metrics; -mod notifiers; -mod protocol; -mod routes; -mod server; -mod state; -mod storages; -mod utils; - -#[cfg_attr(coverage, no_coverage)] -fn greeting(app_conf: &RustusConf) { - let extensions = app_conf - .tus_extensions - .clone() - .into_iter() - .map(|x| x.to_string()) - .collect::>() - .join(", "); - let hooks = app_conf - .notification_opts - .hooks - .iter() - .map(ToString::to_string) - .collect::>() - .join(", "); - let rustus_logo = include_str!("../imgs/rustus_startup_logo.txt"); - eprintln!("\n\n{rustus_logo}"); - eprintln!("Welcome to rustus!"); - eprintln!("Base URL: /{}", app_conf.base_url()); - eprintln!("Available extensions: {extensions}"); - eprintln!("Enabled hooks: {hooks}"); - eprintln!(); - eprintln!(); -} - -/// Create CORS rules for the server. -/// -/// CORS rules are applied to every handler. -/// -/// If the origins vector is empty all origins are -/// welcome, otherwise it will create a wildcard match for -/// every host. -fn create_cors(origins: Vec, additional_headers: Vec) -> Cors { - let mut cors = Cors::default() - .allowed_methods(vec!["OPTIONS", "GET", "HEAD", "POST", "PATCH", "DELETE"]) - .allowed_headers(vec![ - "Content-Type", - "Upload-Offset", - "Upload-Checksum", - "Upload-Length", - "Upload-Metadata", - "Upload-Concat", - "Upload-Defer-Length", - "Tus-Resumable", - "Tus-Version", - "X-HTTP-Method-Override", - "Authorization", - "Origin", - "X-Requested-With", - "X-Request-ID", - "X-HTTP-Method-Override", - ]) - .allowed_headers(additional_headers) - .expose_headers(vec![ - "Location", - "Tus-Version", - "Tus-Resumable", - "Tus-Max-Size", - "Tus-Extension", - "Tus-Checksum-Algorithm", - "Content-Type", - "Content-Length", - "Upload-Length", - "Upload-Metadata", - "Upload-Defer-Length", - "Upload-Concat", - "Upload-Offset", - ]) - .max_age(86400); - - // We allow any origin by default if no origin is specified. - if origins.is_empty() { - return cors.allow_any_origin(); - } - - // Adding origins. - for origin in origins { - cors = cors.allowed_origin_fn(move |request_origin, _| { - WildMatch::new(&origin) == request_origin.to_str().unwrap_or_default() - }); - } - - cors -} - -/// Creates Actix server. -/// -/// This function is parametrized with -/// Storage class. -/// -/// This storage can later be used in -/// handlers. -/// -/// # Errors -/// -/// This function may throw an error -/// if the server can't be bound to the -/// given address. -#[cfg_attr(coverage, no_coverage)] -#[allow(clippy::too_many_lines)] -pub fn create_server(state: State) -> RustusResult { - let host = state.config.host.clone(); - let port = state.config.port; - let disable_health_log = state.config.disable_health_access_log; - let cors_hosts = state.config.cors.clone(); - let workers = state.config.workers; - let proxy_headers = state - .config - .notification_opts - .hooks_http_proxy_headers - .clone(); - let metrics = RustusMetrics::new()?; - let metrics_middleware = actix_web_prom::PrometheusMetricsBuilder::new("") - .endpoint("/metrics") - .registry(metrics.registry.clone()) - .build() - .map_err(|err| { - error!("{}", err); - RustusError::Unknown - })?; - let mut server = HttpServer::new(move || { - let mut logger = middleware::Logger::new("\"%r\" \"-\" \"%s\" \"%a\" \"%D\""); - if disable_health_log { - logger = logger.exclude("/health"); - } - let error_metrics = metrics.found_errors.clone(); - App::new() - .app_data(web::Data::new(metrics.clone())) - .route("/health", web::get().to(routes::health_check)) - .configure(rustus_service(state.clone())) - .wrap(metrics_middleware.clone()) - .wrap(logger) - .wrap(create_cors(cors_hosts.clone(), proxy_headers.clone())) - .wrap(sentry_actix::Sentry::new()) - // Middleware that overrides method of a request if - // "X-HTTP-Method-Override" header is provided. - .wrap_fn(|mut req, srv| { - if let Some(header_value) = req.headers_mut().get("X-HTTP-Method-Override") { - if let Ok(method_name) = header_value.to_str() { - if let Ok(method) = Method::from_str(method_name) { - req.head_mut().method = method; - } - } - } - srv.call(req) - }) - // This is middleware that registers found errors. - .wrap_fn(move |req, srv| { - // Call the service to resolve handler and return response. - let fut = srv.call(req); - // We need this copy, since we use it in moved closure later. - let error_counter = error_metrics.clone(); - async move { - let srv_response = fut.await?; - if let Some(err) = srv_response.response().error() { - let url = match srv_response.request().match_pattern() { - Some(pattern) => pattern, - None => String::new(), - }; - let err_desc = format!("{err}"); - error_counter - .clone() - .with_label_values(&[url.as_str(), err_desc.as_str()]) - .inc(); - } - Ok(srv_response) - } - }) - // Default response for unknown requests. - // It returns 404 status_code. - .default_service(web::route().to(routes::not_found)) - }) - .keep_alive(KeepAlive::Disabled) - .bind((host, port))?; - - // If custom workers count variable is provided. - if let Some(workers_count) = workers { - server = server.workers(workers_count); - } +use log::LevelFilter; + +pub mod config; +pub mod data_storage; +pub mod errors; +pub mod extensions; +pub mod info_storages; +pub mod models; +pub mod notifiers; +pub mod server; +pub mod state; +pub mod utils; - Ok(server.run()) -} +#[global_allocator] +static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; #[cfg_attr(coverage, no_coverage)] -fn setup_logging(app_config: &RustusConf) -> RustusResult<()> { +fn setup_logging(app_config: &config::Config) -> RustusResult<()> { let colors = ColoredLevelConfig::new() // use builder methods .info(Color::Green) @@ -252,58 +46,48 @@ fn setup_logging(app_config: &RustusConf) -> RustusResult<()> { .apply()?; Ok(()) } - -/// Main program entrypoint. #[cfg_attr(coverage, no_coverage)] -#[tokio::main] -async fn main() -> std::io::Result<()> { - dotenvy::dotenv().ok(); - let app_conf = RustusConf::from_args(); - // Configuring logging. - // I may change it to another log system like `fern` later, idk. - setup_logging(&app_conf)?; - - #[allow(clippy::no_effect_underscore_binding)] - let mut _guard = None; - if let Some(dsn) = &app_conf.sentry_opts.dsn { - log::info!("Setting up sentry ."); - _guard = Some(sentry::init(( - dsn.as_str(), - sentry::ClientOptions { - debug: true, - sample_rate: app_conf.sentry_opts.sample_rate, - ..Default::default() - }, - ))); - } - - // Printing cool message. - greeting(&app_conf); - - // Creating info storage. - // It's used to store info about files. - let mut info_storage = app_conf - .info_storage_opts - .info_storage - .get(&app_conf) - .await?; - // Preparing it, lol. - info_storage.prepare().await?; - - // Creating file storage. - let mut storage = app_conf.storage_opts.storage.get(&app_conf); - // Preparing it. - storage.prepare().await?; - - // Creating notification manager. - let notification_manager = NotificationManager::new(&app_conf).await?; +fn greeting(app_conf: &config::Config) { + let extensions = app_conf + .tus_extensions + .clone() + .into_iter() + .map(|x| x.to_string()) + .collect::>() + .join(", "); + let hooks = app_conf + .notification_config + .hooks + .iter() + .map(ToString::to_string) + .collect::>() + .join(", "); + let rustus_logo = include_str!("../imgs/rustus_startup_logo.txt"); + eprintln!("\n\n{rustus_logo}"); + eprintln!("Welcome to rustus!"); + eprintln!("Base URL: {}", app_conf.get_url("")); + eprintln!("Available extensions: {extensions}"); + eprintln!("Enabled hooks: {hooks}"); + eprintln!(); + eprintln!(); +} - // Creating actual server and running it. - let server = create_server(State::new( - app_conf.clone(), - storage, - info_storage, - notification_manager, - ))?; - server.await +fn main() -> RustusResult<()> { + let args = config::Config::parse(); + setup_logging(&args)?; + greeting(&args); + let mut builder = if Some(1) == args.workers { + tokio::runtime::Builder::new_current_thread() + } else { + let mut mtbuilder = tokio::runtime::Builder::new_multi_thread(); + if let Some(workers) = args.workers { + mtbuilder.worker_threads(workers); + } + mtbuilder + }; + builder + .enable_all() + .build()? + .block_on(server::start(args))?; + Ok(()) } diff --git a/src/metrics.rs b/src/metrics.rs deleted file mode 100644 index 90b0e7c..0000000 --- a/src/metrics.rs +++ /dev/null @@ -1,61 +0,0 @@ -use std::collections::HashMap; - -use crate::errors::RustusResult; - -#[allow(clippy::module_name_repetitions)] -#[derive(Clone)] -pub struct RustusMetrics { - pub started_uploads: prometheus::IntCounter, - pub finished_uploads: prometheus::IntCounter, - pub active_uploads: prometheus::IntGauge, - pub upload_sizes: prometheus::Histogram, - pub terminated_uploads: prometheus::IntCounter, - pub found_errors: prometheus::IntCounterVec, - pub registry: prometheus::Registry, -} - -impl RustusMetrics { - pub fn new() -> RustusResult { - let registry = prometheus::Registry::new(); - let started_uploads = - prometheus::IntCounter::new("started_uploads", "Number of created uploads")?; - let finished_uploads = - prometheus::IntCounter::new("finished_uploads", "Number of finished uploads")?; - let active_uploads = - prometheus::IntGauge::new("active_uploads", "Number of active file uploads")?; - let upload_sizes = prometheus::Histogram::with_opts( - prometheus::HistogramOpts::new("uploads_sizes", "Size of uploaded files in bytes") - .buckets(prometheus::exponential_buckets(2., 2., 40)?), - )?; - let terminated_uploads = - prometheus::IntCounter::new("terminated_uploads", "Number of terminated uploads")?; - let found_errors = prometheus::IntCounterVec::new( - prometheus::Opts { - namespace: String::new(), - subsystem: String::new(), - name: "errors".into(), - help: "Found errors".into(), - const_labels: HashMap::new(), - variable_labels: Vec::new(), - }, - &["path", "description"], - )?; - - registry.register(Box::new(started_uploads.clone()))?; - registry.register(Box::new(finished_uploads.clone()))?; - registry.register(Box::new(active_uploads.clone()))?; - registry.register(Box::new(upload_sizes.clone()))?; - registry.register(Box::new(terminated_uploads.clone()))?; - registry.register(Box::new(found_errors.clone()))?; - - Ok(Self { - started_uploads, - finished_uploads, - active_uploads, - upload_sizes, - terminated_uploads, - found_errors, - registry, - }) - } -} diff --git a/src/info_storages/models/file_info.rs b/src/models/file_info.rs similarity index 71% rename from src/info_storages/models/file_info.rs rename to src/models/file_info.rs index 905eba7..9f56a46 100644 --- a/src/info_storages/models/file_info.rs +++ b/src/models/file_info.rs @@ -1,9 +1,6 @@ -use std::collections::HashMap; - -use crate::{errors::RustusError, RustusResult}; use base64::{engine::general_purpose, Engine}; use chrono::{serde::ts_seconds, DateTime, Utc}; -use log::error; +use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; /// Information about file. @@ -21,7 +18,7 @@ pub struct FileInfo { pub is_final: bool, pub parts: Option>, pub storage: String, - pub metadata: HashMap, + pub metadata: FxHashMap, } impl FileInfo { @@ -34,12 +31,13 @@ impl FileInfo { /// `file_size` - Size of a file if it's known; /// `path` - local path of a file; /// `initial_metadata` - meta information, that could be omitted. + #[must_use] pub fn new( file_id: &str, length: Option, path: Option, storage: String, - initial_metadata: Option>, + initial_metadata: Option>, ) -> FileInfo { let id = String::from(file_id); @@ -49,7 +47,7 @@ impl FileInfo { } let metadata = match initial_metadata { Some(meta) => meta, - None => HashMap::new(), + None => FxHashMap::default(), }; FileInfo { @@ -72,6 +70,7 @@ impl FileInfo { /// /// This algorithm can be found at /// [protocol page](https://tus.io/protocols/resumable-upload.html#upload-metadata). + #[must_use] pub fn get_metadata_string(&self) -> Option { let mut result = Vec::new(); @@ -90,31 +89,12 @@ impl FileInfo { } } + #[must_use] pub fn get_filename(&self) -> &str { - self.metadata.get("filename").unwrap_or(&self.id) - } - - pub async fn json(&self) -> RustusResult { - let info_clone = self.clone(); - tokio::task::spawn_blocking(move || { - serde_json::to_string(&info_clone).map_err(RustusError::from) - }) - .await - .map_err(|err| { - error!("{}", err); - RustusError::UnableToWrite("Can't serialize info".into()) - })? - } - - pub async fn from_json(data: String) -> RustusResult { - tokio::task::spawn_blocking(move || { - serde_json::from_str::(data.as_str()).map_err(RustusError::from) - }) - .await - .map_err(|err| { - error!("{}", err); - RustusError::UnableToWrite("Can't serialize info".into()) - })? + self.metadata + .get("filename") + .or_else(|| self.metadata.get("name")) + .unwrap_or(&self.id) } #[cfg(test)] diff --git a/src/models/mod.rs b/src/models/mod.rs new file mode 100644 index 0000000..711d863 --- /dev/null +++ b/src/models/mod.rs @@ -0,0 +1 @@ +pub mod file_info; diff --git a/src/notifiers/amqp_notifier.rs b/src/notifiers/amqp_notifier.rs deleted file mode 100644 index 4272b29..0000000 --- a/src/notifiers/amqp_notifier.rs +++ /dev/null @@ -1,314 +0,0 @@ -use crate::{ - config::AMQPHooksOptions, - notifiers::{Hook, Notifier}, - RustusResult, -}; -use actix_web::http::header::HeaderMap; -use async_trait::async_trait; -use bb8::Pool; -use bb8_lapin::LapinConnectionManager; -use lapin::{ - options::{BasicPublishOptions, ExchangeDeclareOptions, QueueBindOptions, QueueDeclareOptions}, - types::{AMQPValue, FieldTable, LongString}, - BasicProperties, ChannelState, ConnectionProperties, ExchangeKind, -}; -use std::time::Duration; -use strum::IntoEnumIterator; - -#[allow(clippy::struct_excessive_bools)] -#[derive(Clone)] -pub struct DeclareOptions { - pub declare_exchange: bool, - pub durable_exchange: bool, - pub declare_queues: bool, - pub durable_queues: bool, -} - -#[derive(Clone)] -pub struct AMQPNotifier { - exchange_name: String, - channel_pool: Pool, - queues_prefix: String, - exchange_kind: String, - routing_key: Option, - declare_options: DeclareOptions, - celery: bool, -} - -/// Channel manager for lapin channels. -/// -/// This manager is used with bb8 pool, -/// so it maintains opened channels for every connections. -/// -/// This pool uses connection pool -/// and issues new connections from it. -#[derive(Clone)] -pub struct ChannelPool { - pool: Pool, -} - -impl ChannelPool { - pub fn new(pool: Pool) -> Self { - ChannelPool { pool } - } -} - -/// ManagerConnection for ChannelPool. -/// -/// This manager helps you maintain opened channels. -#[async_trait::async_trait] -impl bb8::ManageConnection for ChannelPool { - type Connection = lapin::Channel; - type Error = lapin::Error; - - async fn connect(&self) -> Result { - Ok(self - .pool - .get() - .await - .map_err(|err| match err { - bb8::RunError::TimedOut => lapin::Error::ChannelsLimitReached, - bb8::RunError::User(user_err) => user_err, - })? - .create_channel() - .await?) - } - - async fn is_valid(&self, conn: &mut Self::Connection) -> Result<(), Self::Error> { - let valid_states = vec![ChannelState::Initial, ChannelState::Connected]; - if valid_states.contains(&conn.status().state()) { - Ok(()) - } else { - Err(lapin::Error::InvalidChannel(conn.id())) - } - } - - fn has_broken(&self, conn: &mut Self::Connection) -> bool { - let broken_states = vec![ChannelState::Closed, ChannelState::Error]; - broken_states.contains(&conn.status().state()) - } -} - -impl AMQPNotifier { - #[allow(clippy::fn_params_excessive_bools)] - pub async fn new(options: AMQPHooksOptions) -> RustusResult { - let manager = LapinConnectionManager::new( - options.hooks_amqp_url.unwrap().as_str(), - ConnectionProperties::default(), - ); - let connection_pool = bb8::Pool::builder() - .idle_timeout( - options - .hooks_amqp_idle_connection_timeout - .map(Duration::from_secs), - ) - .max_size(options.hooks_amqp_connection_pool_size) - .build(manager) - .await?; - let channel_pool = bb8::Pool::builder() - .idle_timeout( - options - .hooks_amqp_idle_channels_timeout - .map(Duration::from_secs), - ) - .max_size(options.hooks_amqp_channel_pool_size) - .build(ChannelPool::new(connection_pool)) - .await?; - - Ok(Self { - channel_pool, - celery: options.hooks_amqp_celery, - routing_key: options.hooks_amqp_routing_key, - declare_options: DeclareOptions { - declare_exchange: options.hooks_amqp_declare_exchange, - durable_exchange: options.hooks_amqp_durable_exchange, - declare_queues: options.hooks_amqp_declare_queues, - durable_queues: options.hooks_amqp_durable_queues, - }, - exchange_kind: options.hooks_amqp_exchange_kind, - exchange_name: options.hooks_amqp_exchange, - queues_prefix: options.hooks_amqp_queues_prefix, - }) - } - - /// Generate queue name based on hook type. - /// - /// If specific routing key is not empty, it returns it. - /// Otherwise it will generate queue name based on hook name. - pub fn get_queue_name(&self, hook: Hook) -> String { - if let Some(routing_key) = self.routing_key.as_ref() { - routing_key.into() - } else { - format!("{}.{hook}", self.queues_prefix.as_str()) - } - } -} - -#[async_trait(?Send)] -impl Notifier for AMQPNotifier { - async fn prepare(&mut self) -> RustusResult<()> { - let chan = self.channel_pool.get().await?; - if self.declare_options.declare_exchange { - chan.exchange_declare( - self.exchange_name.as_str(), - ExchangeKind::Custom(self.exchange_kind.clone()), - ExchangeDeclareOptions { - durable: self.declare_options.durable_exchange, - ..ExchangeDeclareOptions::default() - }, - FieldTable::default(), - ) - .await?; - } - if self.declare_options.declare_queues { - for hook in Hook::iter() { - let queue_name = self.get_queue_name(hook); - chan.queue_declare( - queue_name.as_str(), - QueueDeclareOptions { - durable: self.declare_options.durable_queues, - ..QueueDeclareOptions::default() - }, - FieldTable::default(), - ) - .await?; - chan.queue_bind( - queue_name.as_str(), - self.exchange_name.as_str(), - queue_name.as_str(), - QueueBindOptions::default(), - FieldTable::default(), - ) - .await?; - } - } - Ok(()) - } - - async fn send_message( - &self, - message: String, - hook: Hook, - _header_map: &HeaderMap, - ) -> RustusResult<()> { - let chan = self.channel_pool.get().await?; - let queue = self.get_queue_name(hook); - let routing_key = self.routing_key.as_ref().unwrap_or(&queue); - let payload = if self.celery { - format!("[[{message}], {{}}, {{}}]").as_bytes().to_vec() - } else { - message.as_bytes().to_vec() - }; - let mut headers = FieldTable::default(); - if self.celery { - headers.insert( - "id".into(), - AMQPValue::LongString(LongString::from(uuid::Uuid::new_v4().to_string())), - ); - headers.insert( - "task".into(), - AMQPValue::LongString(LongString::from(format!("rustus.{hook}"))), - ); - } - chan.basic_publish( - self.exchange_name.as_str(), - routing_key.as_str(), - BasicPublishOptions::default(), - payload.as_slice(), - BasicProperties::default() - .with_headers(headers) - .with_content_type("application/json".into()) - .with_content_encoding("utf-8".into()), - ) - .await?; - Ok(()) - } -} - -#[cfg(feature = "test_rmq")] -#[cfg(test)] -mod tests { - use super::AMQPNotifier; - use crate::notifiers::{amqp_notifier::DeclareOptions, Hook, Notifier}; - use actix_web::http::header::HeaderMap; - use lapin::options::{BasicAckOptions, BasicGetOptions}; - - async fn get_notifier() -> AMQPNotifier { - let amqp_url = std::env::var("TEST_AMQP_URL").unwrap(); - let mut notifier = AMQPNotifier::new(crate::config::AMQPHooksOptions { - hooks_amqp_url: Some(amqp_url), - hooks_amqp_declare_exchange: true, - hooks_amqp_declare_queues: true, - hooks_amqp_durable_exchange: false, - hooks_amqp_durable_queues: false, - hooks_amqp_celery: true, - hooks_amqp_exchange: uuid::Uuid::new_v4().to_string(), - hooks_amqp_exchange_kind: String::from("topic"), - hooks_amqp_routing_key: None, - hooks_amqp_queues_prefix: uuid::Uuid::new_v4().to_string(), - hooks_amqp_connection_pool_size: 1, - hooks_amqp_channel_pool_size: 1, - hooks_amqp_idle_connection_timeout: None, - hooks_amqp_idle_channels_timeout: None, - }) - .await - .unwrap(); - notifier.prepare().await.unwrap(); - notifier - } - - #[actix_rt::test] - async fn success() { - let notifier = get_notifier().await; - let hook = Hook::PostCreate; - let test_msg = String::from("Test Message"); - notifier - .send_message(test_msg.clone(), hook.clone(), &HeaderMap::new()) - .await - .unwrap(); - let chan = notifier.channel_pool.get().await.unwrap(); - let message = chan - .basic_get( - format!("{}.{}", notifier.queues_prefix.as_str(), hook).as_str(), - BasicGetOptions::default(), - ) - .await - .unwrap(); - assert!(message.is_some()); - assert_eq!( - String::from_utf8(message.as_ref().unwrap().data.clone()).unwrap(), - format!("[[{}], {{}}, {{}}]", test_msg) - ); - message - .unwrap() - .ack(BasicAckOptions::default()) - .await - .unwrap(); - } - - #[actix_rt::test] - async fn unknown_url() { - let notifier = AMQPNotifier::new(crate::config::AMQPHooksOptions { - hooks_amqp_url: Some(String::from("http://unknown")), - hooks_amqp_declare_exchange: true, - hooks_amqp_declare_queues: true, - hooks_amqp_durable_exchange: false, - hooks_amqp_durable_queues: false, - hooks_amqp_celery: false, - hooks_amqp_exchange: uuid::Uuid::new_v4().to_string(), - hooks_amqp_exchange_kind: String::from("topic"), - hooks_amqp_routing_key: None, - hooks_amqp_queues_prefix: uuid::Uuid::new_v4().to_string(), - hooks_amqp_connection_pool_size: 1, - hooks_amqp_channel_pool_size: 1, - hooks_amqp_idle_connection_timeout: None, - hooks_amqp_idle_channels_timeout: None, - }) - .await - .unwrap(); - let res = notifier - .send_message("Test Message".into(), Hook::PostCreate, &HeaderMap::new()) - .await; - assert!(res.is_err()); - } -} diff --git a/src/notifiers/models/notifier.rs b/src/notifiers/base.rs similarity index 52% rename from src/notifiers/models/notifier.rs rename to src/notifiers/base.rs index 599116d..fe9c14e 100644 --- a/src/notifiers/models/notifier.rs +++ b/src/notifiers/base.rs @@ -1,12 +1,10 @@ +use axum::http::HeaderMap; + use crate::errors::RustusResult; -use actix_web::http::header::HeaderMap; -use crate::notifiers::Hook; -use async_trait::async_trait; -use dyn_clone::DynClone; +use super::hooks::Hook; -#[async_trait(?Send)] -pub trait Notifier: DynClone { +pub trait Notifier { async fn prepare(&mut self) -> RustusResult<()>; async fn send_message( &self, @@ -15,5 +13,3 @@ pub trait Notifier: DynClone { headers_map: &HeaderMap, ) -> RustusResult<()>; } - -dyn_clone::clone_trait_object!(Notifier); diff --git a/src/notifiers/dir_notifier.rs b/src/notifiers/dir_notifier.rs deleted file mode 100644 index d921974..0000000 --- a/src/notifiers/dir_notifier.rs +++ /dev/null @@ -1,105 +0,0 @@ -use crate::{ - errors::RustusError, - notifiers::{Hook, Notifier}, - RustusResult, -}; -use actix_web::http::header::HeaderMap; -use async_trait::async_trait; -use log::debug; -use std::path::PathBuf; -use tokio::process::Command; - -#[derive(Clone)] -pub struct DirNotifier { - pub dir: PathBuf, -} - -impl DirNotifier { - pub fn new(dir: PathBuf) -> Self { - Self { dir } - } -} - -#[async_trait(?Send)] -impl Notifier for DirNotifier { - #[cfg_attr(coverage, no_coverage)] - async fn prepare(&mut self) -> RustusResult<()> { - Ok(()) - } - - async fn send_message( - &self, - message: String, - hook: Hook, - _headers_map: &HeaderMap, - ) -> RustusResult<()> { - let hook_path = self.dir.join(hook.to_string()); - if !hook_path.exists() { - debug!("Hook {} not found.", hook.to_string()); - return Err(RustusError::HookError(format!( - "Hook file {hook} not found." - ))); - } - debug!("Running hook: {}", hook_path.as_path().display()); - let mut command = Command::new(hook_path).arg(message).spawn()?; - let stat = command.wait().await?; - if !stat.success() { - return Err(RustusError::HookError("Returned wrong status code".into())); - } - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::DirNotifier; - use crate::notifiers::{Hook, Notifier}; - use actix_web::http::header::HeaderMap; - #[cfg(unix)] - use std::os::unix::fs::PermissionsExt; - use std::{ - fs::File, - io::{Read, Write}, - }; - use tempdir::TempDir; - - #[actix_rt::test] - async fn no_such_hook_file() { - let hook_dir = TempDir::new("dir_notifier").unwrap().into_path(); - let notifier = DirNotifier::new(hook_dir); - let res = notifier - .send_message("test".into(), Hook::PostCreate, &HeaderMap::new()) - .await; - assert!(res.is_err()); - } - - #[cfg(unix)] - #[actix_rt::test] - async fn success() { - let hook = Hook::PostCreate; - let dir = tempdir::TempDir::new("dir_notifier").unwrap().into_path(); - let hook_path = dir.join(hook.to_string()); - { - let mut file = File::create(hook_path.clone()).unwrap(); - let mut permissions = file.metadata().unwrap().permissions(); - permissions.set_mode(0o755); - file.set_permissions(permissions).unwrap(); - let script = r#"#!/bin/sh - echo "$1" > "$(dirname $0)/output""#; - file.write_all(script.as_bytes()).unwrap(); - file.sync_all().unwrap(); - } - let notifier = DirNotifier::new(dir.to_path_buf()); - let test_message = uuid::Uuid::new_v4().to_string(); - notifier - .send_message(test_message.clone(), hook.clone(), &HeaderMap::new()) - .await - .unwrap(); - let output_path = dir.join("output"); - assert!(output_path.exists()); - let mut buffer = String::new(); - let mut out_file = File::open(output_path).unwrap(); - out_file.read_to_string(&mut buffer).unwrap(); - assert_eq!(buffer, format!("{}\n", test_message)); - } -} diff --git a/src/notifiers/file_notifier.rs b/src/notifiers/file_notifier.rs deleted file mode 100644 index 32f581a..0000000 --- a/src/notifiers/file_notifier.rs +++ /dev/null @@ -1,123 +0,0 @@ -use crate::{ - errors::RustusError, - notifiers::{Hook, Notifier}, - RustusResult, -}; -use actix_web::http::header::HeaderMap; -use async_trait::async_trait; -use log::debug; -use tokio::process::Command; - -#[derive(Clone)] -pub struct FileNotifier { - pub command: String, -} - -impl FileNotifier { - pub fn new(command: String) -> Self { - Self { command } - } -} - -#[async_trait(?Send)] -impl Notifier for FileNotifier { - #[cfg_attr(coverage, no_coverage)] - async fn prepare(&mut self) -> RustusResult<()> { - Ok(()) - } - - async fn send_message( - &self, - message: String, - hook: Hook, - _headers_map: &HeaderMap, - ) -> RustusResult<()> { - debug!("Running command: {}", self.command.as_str()); - let mut command = Command::new(self.command.as_str()) - .arg(hook.to_string()) - .arg(message) - .spawn()?; - let stat = command.wait().await?; - if !stat.success() { - return Err(RustusError::HookError("Returned wrong status code".into())); - } - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::FileNotifier; - use crate::notifiers::{Hook, Notifier}; - use actix_web::http::header::HeaderMap; - #[cfg(unix)] - use std::os::unix::fs::PermissionsExt; - use std::{ - fs::File, - io::{Read, Write}, - }; - - #[cfg(unix)] - #[actix_rt::test] - async fn success() { - let dir = tempdir::TempDir::new("file_notifier").unwrap().into_path(); - let hook_path = dir.join("executable.sh"); - { - let mut file = File::create(hook_path.clone()).unwrap(); - let mut permissions = file.metadata().unwrap().permissions(); - permissions.set_mode(0o755); - file.set_permissions(permissions).unwrap(); - let script = r#"#!/bin/sh - HOOK_NAME="$1"; - MESSAGE="$2"; - echo "$HOOK_NAME $MESSAGE" > "$(dirname $0)/output""#; - file.write_all(script.as_bytes()).unwrap(); - file.sync_all().unwrap(); - } - let notifier = FileNotifier::new(hook_path.display().to_string()); - let hook = Hook::PostCreate; - let test_message = uuid::Uuid::new_v4().to_string(); - notifier - .send_message(test_message.clone(), hook.clone(), &HeaderMap::new()) - .await - .unwrap(); - let output_path = dir.join("output"); - assert!(output_path.exists()); - let mut buffer = String::new(); - let mut out_file = File::open(output_path).unwrap(); - out_file.read_to_string(&mut buffer).unwrap(); - assert_eq!(buffer, format!("{} {}\n", hook.to_string(), test_message)); - } - - #[cfg(unix)] - #[actix_rt::test] - async fn error_status() { - let dir = tempdir::TempDir::new("file_notifier").unwrap().into_path(); - let hook_path = dir.join("error_executable.sh"); - { - let mut file = File::create(hook_path.clone()).unwrap(); - let mut permissions = file.metadata().unwrap().permissions(); - permissions.set_mode(0o755); - file.set_permissions(permissions).unwrap(); - let script = r#"#!/bin/sh - read -t 0.1 MESSAGE - exit 1"#; - file.write_all(script.as_bytes()).unwrap(); - file.sync_all().unwrap(); - } - let notifier = FileNotifier::new(hook_path.display().to_string()); - let res = notifier - .send_message("test".into(), Hook::PostCreate, &HeaderMap::new()) - .await; - assert!(res.is_err()); - } - - #[actix_rt::test] - async fn no_such_file() { - let notifier = FileNotifier::new(format!("/{}.sh", uuid::Uuid::new_v4())); - let res = notifier - .send_message("test".into(), Hook::PreCreate, &HeaderMap::new()) - .await; - assert!(res.is_err()); - } -} diff --git a/src/notifiers/hooks.rs b/src/notifiers/hooks.rs new file mode 100644 index 0000000..26bf12f --- /dev/null +++ b/src/notifiers/hooks.rs @@ -0,0 +1,20 @@ +use crate::from_str; + +/// Hooks for notifications. +#[derive(Copy, Clone, Debug, strum::Display, strum::EnumIter, Eq, PartialEq, Hash)] +pub enum Hook { + #[strum(serialize = "pre-create")] + PreCreate, + #[strum(serialize = "post-create")] + PostCreate, + #[strum(serialize = "post-receive")] + PostReceive, + #[strum(serialize = "pre-terminate")] + PreTerminate, + #[strum(serialize = "post-terminate")] + PostTerminate, + #[strum(serialize = "post-finish")] + PostFinish, +} + +from_str!(Hook, "hook"); diff --git a/src/notifiers/http_notifier.rs b/src/notifiers/http_notifier.rs deleted file mode 100644 index cc0fe1a..0000000 --- a/src/notifiers/http_notifier.rs +++ /dev/null @@ -1,171 +0,0 @@ -use crate::errors::{RustusError, RustusResult}; - -use crate::notifiers::{Hook, Notifier}; - -use actix_web::http::header::HeaderMap; -use async_trait::async_trait; -use log::debug; -use reqwest::Client; -use std::time::Duration; - -#[derive(Clone)] -pub struct HttpNotifier { - urls: Vec, - client: Client, - forward_headers: Vec, - timeout_secs: u64, -} - -impl HttpNotifier { - pub fn new(urls: Vec, forward_headers: Vec, timeout_secs: Option) -> Self { - let client = Client::new(); - Self { - urls, - client, - forward_headers, - timeout_secs: timeout_secs.unwrap_or(2), - } - } -} - -#[async_trait(?Send)] -impl Notifier for HttpNotifier { - #[cfg_attr(coverage, no_coverage)] - async fn prepare(&mut self) -> RustusResult<()> { - Ok(()) - } - - async fn send_message( - &self, - message: String, - hook: Hook, - header_map: &HeaderMap, - ) -> RustusResult<()> { - debug!("Starting HTTP Hook."); - let idempotency_key = uuid::Uuid::new_v4().to_string(); - let requests_vec = self.urls.iter().map(|url| { - debug!("Preparing request for {}", url); - let mut request = self - .client - .post(url.as_str()) - .header("Idempotency-Key", idempotency_key.as_str()) - .header("Hook-Name", hook.to_string()) - .header("Content-Type", "application/json") - .timeout(Duration::from_secs(self.timeout_secs)); - for item in &self.forward_headers { - if let Some(value) = header_map.get(item.as_str()) { - request = request.header(item.as_str(), value.as_bytes()); - } - } - request.body(message.clone()).send() - }); - for response in requests_vec { - let real_resp = response.await?; - if !real_resp.status().is_success() { - let content_type = real_resp - .headers() - .get("Content-Type") - .and_then(|hval| hval.to_str().ok().map(String::from)); - let status = real_resp.status().as_u16(); - let text = real_resp.text().await.unwrap_or_default(); - log::warn!( - "Got wrong response for `{hook}`. Status code: `{status}`, body: `{body}`", - hook = hook, - status = status, - body = text, - ); - return Err(RustusError::HTTPHookError(status, text, content_type)); - } - } - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::HttpNotifier; - use crate::notifiers::{Hook, Notifier}; - use actix_web::http::header::{HeaderMap, HeaderName, HeaderValue}; - use httptest::{matchers::contains, responders::status_code}; - use std::{str::FromStr, time::Duration}; - - #[actix_rt::test] - async fn success_request() { - let server = httptest::Server::run(); - server.expect( - httptest::Expectation::matching(httptest::matchers::request::method_path( - "POST", "/hook", - )) - .respond_with(httptest::responders::status_code(200)), - ); - let hook_url = server.url_str("/hook"); - - let notifier = HttpNotifier::new(vec![hook_url], vec![], None); - notifier - .send_message("test_message".into(), Hook::PostCreate, &HeaderMap::new()) - .await - .unwrap(); - } - - #[actix_rt::test] - async fn timeout_request() { - let server = httptest::Server::run(); - server.expect( - httptest::Expectation::matching(httptest::matchers::request::method_path( - "POST", "/hook", - )) - .respond_with(httptest::responders::delay_and_then( - Duration::from_secs(3), - status_code(200), - )), - ); - let hook_url = server.url_str("/hook"); - - let notifier = HttpNotifier::new(vec![hook_url], vec![], None); - let result = notifier - .send_message("test_message".into(), Hook::PostCreate, &HeaderMap::new()) - .await; - assert!(result.is_err()); - } - - #[actix_rt::test] - async fn unknown_url() { - let server = httptest::Server::run(); - server.expect( - httptest::Expectation::matching(httptest::matchers::request::method_path( - "POST", "/hook", - )) - .respond_with(httptest::responders::status_code(404)), - ); - let hook_url = server.url_str("/hook"); - - let notifier = HttpNotifier::new(vec![hook_url], vec![], None); - let result = notifier - .send_message("test_message".into(), Hook::PostCreate, &HeaderMap::new()) - .await; - assert!(result.is_err()); - } - - #[actix_rt::test] - async fn forwarded_header() { - let server = httptest::Server::run(); - server.expect( - httptest::Expectation::matching(httptest::matchers::all_of![ - httptest::matchers::request::method_path("POST", "/hook",), - httptest::matchers::request::headers(contains(("x-test-header", "meme-value"))) - ]) - .respond_with(httptest::responders::status_code(200)), - ); - let hook_url = server.url_str("/hook"); - let notifier = HttpNotifier::new(vec![hook_url], vec!["X-TEST-HEADER".into()], None); - let mut header_map = HeaderMap::new(); - header_map.insert( - HeaderName::from_str("X-TEST-HEADER").unwrap(), - HeaderValue::from_str("meme-value").unwrap(), - ); - notifier - .send_message("test_message".into(), Hook::PostCreate, &header_map) - .await - .unwrap(); - } -} diff --git a/src/notifiers/impls/amqp_notifier.rs b/src/notifiers/impls/amqp_notifier.rs new file mode 100644 index 0000000..b2907d4 --- /dev/null +++ b/src/notifiers/impls/amqp_notifier.rs @@ -0,0 +1,191 @@ +use std::time::Duration; + +use axum::http::HeaderMap; +use lapin::{ + options::{BasicPublishOptions, ExchangeDeclareOptions, QueueBindOptions, QueueDeclareOptions}, + types::{AMQPValue, FieldTable, LongString}, + BasicProperties, ConnectionProperties, ExchangeKind, +}; +use mobc::Pool; +use strum::IntoEnumIterator; + +use crate::{ + config::AMQPHooksOptions, + errors::RustusResult, + notifiers::{base::Notifier, hooks::Hook}, + utils::{ + lapin_pool::{ChannelPool, ConnnectionPool}, + result::MonadLogger, + }, +}; + +#[allow(clippy::struct_excessive_bools)] +#[derive(Clone)] +pub struct DeclareOptions { + pub declare_exchange: bool, + pub durable_exchange: bool, + pub declare_queues: bool, + pub durable_queues: bool, +} + +#[derive(Clone)] +pub struct AMQPNotifier { + exchange_name: String, + channel_pool: Pool, + queues_prefix: String, + exchange_kind: String, + routing_key: Option, + declare_options: DeclareOptions, + celery: bool, +} + +/// `ManagerConnection` for `ChannelPool`. +/// +/// This manager helps you maintain opened channels. +impl AMQPNotifier { + /// Create new `AMQPNotifier`. + /// + /// This method will create two connection pools for AMQP: + /// * `connection_pool` - for connections + /// * `channel_pool` - for channels + /// + /// The channels pool uses connection pool to get connections + /// sometimes. + /// + /// # Panics + /// + /// This method will panic if `hooks_amqp_url` is not set. + /// But this should not happen, because it's checked before. + /// + /// TODO: add separate type for this structure. + pub fn new(options: AMQPHooksOptions) -> Self { + let manager = ConnnectionPool::new( + options.hooks_amqp_url.mlog_err("AMQP url").unwrap().clone(), + ConnectionProperties::default(), + ); + let connection_pool = mobc::Pool::builder() + .max_idle_lifetime( + options + .hooks_amqp_idle_connection_timeout + .map(Duration::from_secs), + ) + .max_open(options.hooks_amqp_connection_pool_size) + .build(manager); + let channel_pool = mobc::Pool::builder() + .max_idle_lifetime( + options + .hooks_amqp_idle_channels_timeout + .map(Duration::from_secs), + ) + .max_open(options.hooks_amqp_channel_pool_size) + .build(ChannelPool::new(connection_pool)); + + Self { + channel_pool, + celery: options.hooks_amqp_celery, + routing_key: options.hooks_amqp_routing_key, + declare_options: DeclareOptions { + declare_exchange: options.hooks_amqp_declare_exchange, + durable_exchange: options.hooks_amqp_durable_exchange, + declare_queues: options.hooks_amqp_declare_queues, + durable_queues: options.hooks_amqp_durable_queues, + }, + exchange_kind: options.hooks_amqp_exchange_kind, + exchange_name: options.hooks_amqp_exchange, + queues_prefix: options.hooks_amqp_queues_prefix, + } + } + + /// Generate queue name based on hook type. + /// + /// If specific routing key is not empty, it returns it. + /// Otherwise it will generate queue name based on hook name. + #[must_use] + pub fn get_queue_name(&self, hook: &Hook) -> String { + if let Some(routing_key) = self.routing_key.as_ref() { + routing_key.into() + } else { + format!("{}.{hook}", self.queues_prefix.as_str()) + } + } +} + +impl Notifier for AMQPNotifier { + async fn prepare(&mut self) -> RustusResult<()> { + let chan = self.channel_pool.get().await?; + if self.declare_options.declare_exchange { + chan.exchange_declare( + self.exchange_name.as_str(), + ExchangeKind::Custom(self.exchange_kind.clone()), + ExchangeDeclareOptions { + durable: self.declare_options.durable_exchange, + ..ExchangeDeclareOptions::default() + }, + FieldTable::default(), + ) + .await?; + } + if self.declare_options.declare_queues { + for hook in Hook::iter() { + let queue_name = self.get_queue_name(&hook); + chan.queue_declare( + queue_name.as_str(), + QueueDeclareOptions { + durable: self.declare_options.durable_queues, + ..QueueDeclareOptions::default() + }, + FieldTable::default(), + ) + .await?; + chan.queue_bind( + queue_name.as_str(), + self.exchange_name.as_str(), + queue_name.as_str(), + QueueBindOptions::default(), + FieldTable::default(), + ) + .await?; + } + } + Ok(()) + } + + async fn send_message( + &self, + message: String, + hook: Hook, + _header_map: &HeaderMap, + ) -> RustusResult<()> { + let chan = self.channel_pool.get().await?; + let queue = self.get_queue_name(&hook); + let routing_key = self.routing_key.as_ref().unwrap_or(&queue); + let payload = if self.celery { + format!("[[{message}], {{}}, {{}}]").as_bytes().to_vec() + } else { + message.as_bytes().to_vec() + }; + let mut headers = FieldTable::default(); + if self.celery { + headers.insert( + "id".into(), + AMQPValue::LongString(LongString::from(uuid::Uuid::new_v4().to_string())), + ); + headers.insert( + "task".into(), + AMQPValue::LongString(LongString::from(format!("rustus.{hook}"))), + ); + } + chan.basic_publish( + self.exchange_name.as_str(), + routing_key.as_str(), + BasicPublishOptions::default(), + payload.as_slice(), + BasicProperties::default() + .with_headers(headers) + .with_content_type("application/json".into()) + .with_content_encoding("utf-8".into()), + ) + .await?; + Ok(()) + } +} diff --git a/src/notifiers/impls/dir_notifier.rs b/src/notifiers/impls/dir_notifier.rs new file mode 100644 index 0000000..363d914 --- /dev/null +++ b/src/notifiers/impls/dir_notifier.rs @@ -0,0 +1,50 @@ +use crate::{ + errors::RustusError, + notifiers::{base::Notifier, hooks::Hook}, + RustusResult, +}; +use axum::http::HeaderMap; +use log::debug; +use std::path::PathBuf; +use tokio::process::Command; + +#[derive(Clone)] +pub struct DirNotifier { + pub dir: PathBuf, +} + +impl DirNotifier { + #[must_use] + pub fn new(dir: PathBuf) -> Self { + Self { dir } + } +} + +impl Notifier for DirNotifier { + #[cfg_attr(coverage, no_coverage)] + async fn prepare(&mut self) -> RustusResult<()> { + Ok(()) + } + + async fn send_message( + &self, + message: String, + hook: Hook, + _headers_map: &HeaderMap, + ) -> RustusResult<()> { + let hook_path = self.dir.join(hook.to_string()); + if !hook_path.exists() { + debug!("Hook {} not found.", hook.to_string()); + return Err(RustusError::HookError(format!( + "Hook file {hook} not found." + ))); + } + debug!("Running hook: {}", hook_path.as_path().display()); + let mut command = Command::new(hook_path).arg(message).spawn()?; + let stat = command.wait().await?; + if !stat.success() { + return Err(RustusError::HookError("Returned wrong status code".into())); + } + Ok(()) + } +} diff --git a/src/notifiers/impls/file_notifier.rs b/src/notifiers/impls/file_notifier.rs new file mode 100644 index 0000000..d01a497 --- /dev/null +++ b/src/notifiers/impls/file_notifier.rs @@ -0,0 +1,45 @@ +use crate::{ + errors::RustusError, + notifiers::{base::Notifier, hooks::Hook}, + RustusResult, +}; +use axum::http::HeaderMap; +use log::debug; +use tokio::process::Command; + +#[derive(Clone)] +pub struct FileNotifier { + pub command: String, +} + +impl FileNotifier { + #[must_use] + pub fn new(command: String) -> Self { + Self { command } + } +} + +impl Notifier for FileNotifier { + #[cfg_attr(coverage, no_coverage)] + async fn prepare(&mut self) -> RustusResult<()> { + Ok(()) + } + + async fn send_message( + &self, + message: String, + hook: Hook, + _headers_map: &HeaderMap, + ) -> RustusResult<()> { + debug!("Running command: {}", self.command.as_str()); + let mut command = Command::new(self.command.as_str()) + .arg(hook.to_string()) + .arg(message) + .spawn()?; + let stat = command.wait().await?; + if !stat.success() { + return Err(RustusError::HookError("Returned wrong status code".into())); + } + Ok(()) + } +} diff --git a/src/notifiers/impls/http_notifier.rs b/src/notifiers/impls/http_notifier.rs new file mode 100644 index 0000000..f1fd158 --- /dev/null +++ b/src/notifiers/impls/http_notifier.rs @@ -0,0 +1,81 @@ +use crate::{ + errors::{RustusError, RustusResult}, + notifiers::{base::Notifier, hooks::Hook}, +}; + +use axum::http::HeaderMap; +use reqwest::Client; +use std::time::Duration; + +#[derive(Clone)] +pub struct HttpNotifier { + urls: Vec, + client: Client, + forward_headers: Vec, + timeout_secs: u64, +} + +impl HttpNotifier { + #[must_use] + pub fn new(urls: Vec, forward_headers: Vec, timeout_secs: Option) -> Self { + let client = Client::new(); + Self { + urls, + client, + forward_headers, + timeout_secs: timeout_secs.unwrap_or(2), + } + } +} + +impl Notifier for HttpNotifier { + #[cfg_attr(coverage, no_coverage)] + async fn prepare(&mut self) -> RustusResult<()> { + Ok(()) + } + + async fn send_message( + &self, + message: String, + hook: Hook, + header_map: &HeaderMap, + ) -> RustusResult<()> { + log::debug!("Starting HTTP Hook."); + let idempotency_key = uuid::Uuid::new_v4().to_string(); + let requests_vec = self.urls.iter().map(|url| { + log::debug!("Preparing request for {}", url); + let mut request = self + .client + .post(url.as_str()) + .header("Idempotency-Key", idempotency_key.as_str()) + .header("Hook-Name", hook.to_string()) + .header("Content-Type", "application/json") + .timeout(Duration::from_secs(self.timeout_secs)); + for item in &self.forward_headers { + if let Some(value) = header_map.get(item.as_str()) { + request = request.header(item.as_str(), value.as_bytes()); + } + } + request.body(message.clone()).send() + }); + for response in requests_vec { + let real_resp = response.await?; + if !real_resp.status().is_success() { + let content_type = real_resp + .headers() + .get("Content-Type") + .and_then(|hval| hval.to_str().ok().map(String::from)); + let status = real_resp.status().as_u16(); + let text = real_resp.text().await.unwrap_or_default(); + log::warn!( + "Got wrong response for `{hook}`. Status code: `{status}`, body: `{body}`", + hook = hook, + status = status, + body = text, + ); + return Err(RustusError::HTTPHookError(status, text, content_type)); + } + } + Ok(()) + } +} diff --git a/src/notifiers/impls/mod.rs b/src/notifiers/impls/mod.rs new file mode 100644 index 0000000..02be463 --- /dev/null +++ b/src/notifiers/impls/mod.rs @@ -0,0 +1,4 @@ +pub mod amqp_notifier; +pub mod dir_notifier; +pub mod file_notifier; +pub mod http_notifier; diff --git a/src/notifiers/manager.rs b/src/notifiers/manager.rs new file mode 100644 index 0000000..c77cfb7 --- /dev/null +++ b/src/notifiers/manager.rs @@ -0,0 +1,99 @@ +use crate::{ + config::Config, + notifiers::impls::{ + amqp_notifier::AMQPNotifier, dir_notifier::DirNotifier, file_notifier::FileNotifier, + http_notifier::HttpNotifier, + }, +}; + +use super::{base::Notifier, NotifierImpl}; +use axum::http::HeaderMap; + +#[derive(Clone)] +pub struct NotificationManager { + notifiers: Vec, +} + +impl NotificationManager { + /// Construct a new `NotificationManager`. + /// + /// Manager is used to send notification for hooks. + /// It's capable of having multiple notifiers, + /// which are used to send messages. + #[must_use] + pub fn new(rustus_config: &Config) -> Self { + let mut manager = Self { + notifiers: Vec::new(), + }; + log::debug!("Initializing notification manager."); + if let Some(hooks_file) = &rustus_config.notification_config.hooks_file { + log::debug!("Found hooks file"); + manager + .notifiers + .push(NotifierImpl::File(FileNotifier::new(hooks_file.clone()))); + } + if let Some(hooks_dir) = &rustus_config.notification_config.hooks_dir { + log::debug!("Found hooks directory"); + manager + .notifiers + .push(NotifierImpl::Dir(DirNotifier::new(hooks_dir.clone()))); + } + if !rustus_config.notification_config.hooks_http_urls.is_empty() { + log::debug!("Found http hook urls."); + manager.notifiers.push(NotifierImpl::Http(HttpNotifier::new( + rustus_config.notification_config.hooks_http_urls.clone(), + rustus_config + .notification_config + .hooks_http_proxy_headers + .clone(), + rustus_config.notification_config.http_hook_timeout, + ))); + } + if rustus_config + .notification_config + .amqp_hook_opts + .hooks_amqp_url + .is_some() + { + log::debug!("Found AMQP notifier."); + manager.notifiers.push(NotifierImpl::Amqp(AMQPNotifier::new( + rustus_config.notification_config.amqp_hook_opts.clone(), + ))); + } + log::debug!("Notification manager initialized."); + manager + } + + /// Prepares all notifiers. + /// + /// This function prepares all notifiers for sending messages. + /// + /// # Errors + /// + /// This method might fail in case if any of the notifiers fails. + pub async fn prepare(&mut self) -> crate::errors::RustusResult<()> { + for notifier in &mut self.notifiers { + notifier.prepare().await?; + } + Ok(()) + } + + /// Sends a message to all notifiers. + /// + /// # Errors + /// + /// This method might fail in case if any of the notifiers fails. + pub async fn send_message( + &self, + message: String, + hook: super::hooks::Hook, + headers_map: &HeaderMap, + ) -> crate::errors::RustusResult<()> { + for notifier in &self.notifiers { + notifier + .send_message(message.clone(), hook, headers_map) + .await?; + } + Ok(()) + } +} diff --git a/src/notifiers/mod.rs b/src/notifiers/mod.rs index 211329f..5fee8dd 100644 --- a/src/notifiers/mod.rs +++ b/src/notifiers/mod.rs @@ -1,8 +1,40 @@ -#[cfg(feature = "amqp_notifier")] -pub mod amqp_notifier; -pub mod dir_notifier; -mod file_notifier; -pub mod http_notifier; -pub mod models; +pub mod base; +pub mod hooks; +pub mod impls; +pub mod manager; +pub mod serializer; -pub use models::{hooks::Hook, message_format::Format, notifier::Notifier}; +pub use manager::NotificationManager; +pub use serializer::Format; + +#[derive(Clone)] +pub enum NotifierImpl { + Http(impls::http_notifier::HttpNotifier), + File(impls::file_notifier::FileNotifier), + Dir(impls::dir_notifier::DirNotifier), + Amqp(impls::amqp_notifier::AMQPNotifier), +} + +impl base::Notifier for NotifierImpl { + async fn prepare(&mut self) -> crate::errors::RustusResult<()> { + match self { + Self::Http(http) => http.prepare().await, + Self::File(file) => file.prepare().await, + Self::Dir(dir) => dir.prepare().await, + Self::Amqp(amqp) => amqp.prepare().await, + } + } + async fn send_message( + &self, + message: String, + hook: hooks::Hook, + headers_map: &http::HeaderMap, + ) -> crate::errors::RustusResult<()> { + match self { + Self::Http(http) => http.send_message(message, hook, headers_map).await, + Self::File(file) => file.send_message(message, hook, headers_map).await, + Self::Dir(dir) => dir.send_message(message, hook, headers_map).await, + Self::Amqp(amqp) => amqp.send_message(message, hook, headers_map).await, + } + } +} diff --git a/src/notifiers/models/hooks.rs b/src/notifiers/models/hooks.rs deleted file mode 100644 index 297cc64..0000000 --- a/src/notifiers/models/hooks.rs +++ /dev/null @@ -1,22 +0,0 @@ -use crate::from_str; -use derive_more::{Display, From}; -use strum::EnumIter; - -/// Hooks for notifications. -#[derive(Copy, Clone, Debug, Display, From, EnumIter, Eq, PartialEq)] -pub enum Hook { - #[display(fmt = "pre-create")] - PreCreate, - #[display(fmt = "post-create")] - PostCreate, - #[display(fmt = "post-receive")] - PostReceive, - #[display(fmt = "pre-terminate")] - PreTerminate, - #[display(fmt = "post-terminate")] - PostTerminate, - #[display(fmt = "post-finish")] - PostFinish, -} - -from_str!(Hook, "hook"); diff --git a/src/notifiers/models/message_format.rs b/src/notifiers/models/message_format.rs deleted file mode 100644 index 2be27b6..0000000 --- a/src/notifiers/models/message_format.rs +++ /dev/null @@ -1,167 +0,0 @@ -use crate::{from_str, info_storages::FileInfo}; -use actix_web::{http::header::HeaderMap, HttpRequest}; -use derive_more::{Display, From}; -use serde::Serialize; -use serde_json::{json, Value}; -use std::collections::HashMap; -use strum::EnumIter; - -#[derive(Clone, Debug, Eq, Display, From, PartialEq, EnumIter)] -pub enum Format { - #[display(fmt = "default")] - Default, - #[display(fmt = "tusd")] - Tusd, - #[display(fmt = "v2")] - V2, -} - -from_str!(Format, "format"); - -impl Format { - pub fn format( - &self, - request: &HttpRequest, - file_info: &FileInfo, - behind_proxy: bool, - ) -> String { - match self { - Self::Default => default_format(request, file_info, behind_proxy), - Self::Tusd => tusd_format(request, file_info, behind_proxy), - Self::V2 => rustus_format_v2(request, file_info, behind_proxy), - } - } -} - -#[derive(Serialize)] -#[serde(rename_all = "PascalCase")] -struct TusdStorageInfo { - #[serde(rename = "Type")] - storage_type: String, - path: Option, -} - -#[derive(Serialize)] -#[serde(rename_all = "PascalCase")] -struct TusdFileInfo { - #[serde(rename = "ID")] - id: String, - offset: usize, - size: Option, - is_final: bool, - is_partial: bool, - partial_uploads: Option>, - size_is_deferred: bool, - meta_data: HashMap, - storage: TusdStorageInfo, -} - -impl From<&FileInfo> for TusdFileInfo { - fn from(file_info: &FileInfo) -> Self { - let deferred_size = file_info.length.is_none(); - Self { - id: file_info.id.clone(), - offset: file_info.offset, - size: file_info.length, - size_is_deferred: deferred_size, - is_final: file_info.is_final, - is_partial: file_info.is_partial, - partial_uploads: file_info.parts.clone(), - meta_data: file_info.metadata.clone(), - storage: TusdStorageInfo { - storage_type: file_info.storage.clone(), - path: file_info.path.clone(), - }, - } - } -} - -/// Transforms headersmap to `HashMap`. -/// -/// Keys of the resulting map are Strings, -/// Values are serde values. It ca be either string values or -/// arrays. -fn headers_to_value_map(headers: &HeaderMap, use_arrays: bool) -> HashMap { - let mut headers_map = HashMap::new(); - for (name, value) in headers { - if let Ok(header_val) = value.to_str().map(String::from) { - if use_arrays { - headers_map.insert( - name.to_string(), - Value::Array(vec![Value::String(header_val)]), - ); - } else { - headers_map.insert(name.to_string(), Value::String(header_val)); - } - } - } - headers_map -} - -/// Resolves real client's IP. -/// -/// This function is used to get peer's address, -/// but if Rustus is running behind proxy, then you -/// it should check for `Forwarded` or `X-Forwarded-For` headers. -fn get_remote_addr(request: &HttpRequest, behind_proxy: bool) -> Option { - if behind_proxy { - request - .connection_info() - .realip_remote_addr() - .map(String::from) - } else { - request.connection_info().peer_addr().map(String::from) - } -} - -/// Default format is specific for Rustus. -/// -/// This format is a simple serialized `FileInfo` and some parts of the request. -pub fn default_format(request: &HttpRequest, file_info: &FileInfo, behind_proxy: bool) -> String { - let value = json!({ - "upload": file_info, - "request": { - "URI": request.uri().to_string(), - "method": request.method().to_string(), - "remote_addr": get_remote_addr(request, behind_proxy), - "headers": headers_to_value_map(request.headers(), false) - } - }); - value.to_string() -} - -/// Default format is specific for Rustus V2. -/// -/// This format is almost the same as V1, but with some enhancements. -pub fn rustus_format_v2(request: &HttpRequest, file_info: &FileInfo, behind_proxy: bool) -> String { - let value = json!({ - "upload": file_info, - "request": { - "uri": request.uri().to_string(), - "method": request.method().to_string(), - "remote_addr": get_remote_addr(request, behind_proxy), - "headers": headers_to_value_map(request.headers(), false) - } - }); - value.to_string() -} - -/// This format follows TUSD hooks. -/// -/// You can read more about tusd hooks -/// [here](https://github.com/tus/tusd/blob/master/docs/hooks.md). -/// -/// Generally speaking, it's almost the same as the default format, -/// but some variables are ommited and headers are added to the request. -pub fn tusd_format(request: &HttpRequest, file_info: &FileInfo, behind_proxy: bool) -> String { - let value = json!({ - "Upload": TusdFileInfo::from(file_info), - "HTTPRequest": { - "URI": request.uri().to_string(), - "Method": request.method().to_string(), - "RemoteAddr": get_remote_addr(request, behind_proxy), - "Header": headers_to_value_map(request.headers(), true) - } - }); - value.to_string() -} diff --git a/src/notifiers/models/mod.rs b/src/notifiers/models/mod.rs deleted file mode 100644 index e8571be..0000000 --- a/src/notifiers/models/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod hooks; -pub mod message_format; -pub mod notification_manager; -pub mod notifier; diff --git a/src/notifiers/models/notification_manager.rs b/src/notifiers/models/notification_manager.rs deleted file mode 100644 index f84f12e..0000000 --- a/src/notifiers/models/notification_manager.rs +++ /dev/null @@ -1,85 +0,0 @@ -#[cfg(feature = "amqp_notifier")] -use crate::notifiers::amqp_notifier; -use crate::{ - errors::RustusResult, - notifiers::{ - dir_notifier::DirNotifier, file_notifier::FileNotifier, http_notifier, Hook, Notifier, - }, - RustusConf, -}; -use actix_web::http::header::HeaderMap; -use log::debug; - -#[derive(Clone)] -pub struct NotificationManager { - notifiers: Vec>, -} - -impl NotificationManager { - pub async fn new(rustus_config: &RustusConf) -> RustusResult { - let mut manager = Self { - notifiers: Vec::new(), - }; - debug!("Initializing notification manager."); - if rustus_config.notification_opts.hooks_file.is_some() { - debug!("Found hooks file"); - manager.notifiers.push(Box::new(FileNotifier::new( - rustus_config.notification_opts.hooks_file.clone().unwrap(), - ))); - } - if rustus_config.notification_opts.hooks_dir.is_some() { - debug!("Found hooks directory"); - manager.notifiers.push(Box::new(DirNotifier::new( - rustus_config.notification_opts.hooks_dir.clone().unwrap(), - ))); - } - if !rustus_config.notification_opts.hooks_http_urls.is_empty() { - debug!("Found http hook urls."); - manager - .notifiers - .push(Box::new(http_notifier::HttpNotifier::new( - rustus_config.notification_opts.hooks_http_urls.clone(), - rustus_config - .notification_opts - .hooks_http_proxy_headers - .clone(), - rustus_config.notification_opts.http_hook_timeout, - ))); - } - #[cfg(feature = "amqp_notifier")] - if rustus_config - .notification_opts - .amqp_hook_opts - .hooks_amqp_url - .is_some() - { - debug!("Found AMQP notifier."); - manager.notifiers.push(Box::new( - amqp_notifier::AMQPNotifier::new( - rustus_config.notification_opts.amqp_hook_opts.clone(), - ) - .await?, - )); - } - for notifier in &mut manager.notifiers.iter_mut() { - notifier.prepare().await?; - } - debug!("Notification manager initialized."); - Ok(manager) - } - - pub async fn send_message( - &self, - message: String, - hook: Hook, - header_map: &HeaderMap, - ) -> RustusResult<()> { - log::debug!("Sending a `{}` hook with body `{}`", hook, message); - for notifier in &self.notifiers { - notifier - .send_message(message.clone(), hook, header_map) - .await?; - } - Ok(()) - } -} diff --git a/src/notifiers/serializer.rs b/src/notifiers/serializer.rs new file mode 100644 index 0000000..c449a9e --- /dev/null +++ b/src/notifiers/serializer.rs @@ -0,0 +1,174 @@ +use std::{collections::HashMap, hash::BuildHasherDefault, net::SocketAddr}; + +use http::{HeaderMap, Uri}; +use rustc_hash::FxHasher; +use serde_json::{json, Value}; + +use crate::{models::file_info::FileInfo, utils::headers::HeaderMapExt}; + +#[derive(Clone, Debug, Eq, strum::Display, PartialEq, strum::EnumIter)] +pub enum Format { + #[strum(serialize = "default")] + Default, + #[strum(serialize = "tusd")] + Tusd, + #[strum(serialize = "v2")] + V2, +} + +pub struct HookData<'a> { + pub uri: String, + pub method: &'a str, + pub remote_addr: String, + pub headers: &'a HeaderMap, + + pub file_info: &'a FileInfo, +} + +impl Format { + pub fn format( + &self, + uri: &Uri, + method: &http::Method, + addr: &SocketAddr, + headers: &HeaderMap, + proxy_enabled: bool, + file_info: &FileInfo, + ) -> String { + let hook_data = &HookData::new( + uri.path_and_query() + .map(ToString::to_string) + .unwrap_or_default(), + method.as_str(), + headers.get_remote_ip(addr, proxy_enabled), + headers, + file_info, + ); + match self { + Format::Default => default_format(hook_data), + Format::Tusd => tusd_format(hook_data), + Format::V2 => v2_format(hook_data), + } + } +} + +impl<'a> HookData<'a> { + #[must_use] + pub fn new( + uri: String, + method: &'a str, + remote_addr: String, + headers: &'a HeaderMap, + file_info: &'a FileInfo, + ) -> Self { + Self { + uri, + method, + remote_addr, + headers, + file_info, + } + } +} + +crate::from_str!(Format, "format"); +fn headers_to_value_map( + headers: &HeaderMap, + use_arrays: bool, +) -> HashMap> { + let mut headers_map = + HashMap::with_capacity_and_hasher(headers.len(), BuildHasherDefault::::default()); + for (name, value) in headers { + if let Ok(header_val) = value.to_str().map(String::from) { + if use_arrays { + headers_map.insert( + name.to_string(), + Value::Array(vec![Value::String(header_val)]), + ); + } else { + headers_map.insert(name.to_string(), Value::String(header_val)); + } + } + } + headers_map +} + +#[must_use] +pub fn default_format(hook_data: &HookData) -> String { + json!({ + "upload": { + "id": hook_data.file_info.id, + "offset": hook_data.file_info.offset, + "length": hook_data.file_info.length, + "path": hook_data.file_info.path, + "created_at": hook_data.file_info.created_at.timestamp(), + "deferred_size": hook_data.file_info.deferred_size, + "is_partial": hook_data.file_info.is_partial, + "is_final": hook_data.file_info.is_final, + "metadata": hook_data.file_info.metadata, + "storage": hook_data.file_info.storage, + "parts": hook_data.file_info.parts, + }, + "request": { + "URI": hook_data.uri, + "method": hook_data.method, + "remote_addr": hook_data.remote_addr, + "headers": headers_to_value_map(hook_data.headers , false) + } + }) + .to_string() +} + +#[must_use] +pub fn v2_format(hook_data: &HookData) -> String { + json!({ + "upload": { + "id": hook_data.file_info.id, + "offset": hook_data.file_info.offset, + "length": hook_data.file_info.length, + "path": hook_data.file_info.path, + "created_at": hook_data.file_info.created_at.timestamp(), + "deferred_size": hook_data.file_info.deferred_size, + "is_partial": hook_data.file_info.is_partial, + "is_final": hook_data.file_info.is_final, + "metadata": hook_data.file_info.metadata, + "storage": hook_data.file_info.storage, + "parts": hook_data.file_info.parts, + }, + "request": { + "uri": hook_data.uri, + "method": hook_data.method, + "remote_addr": hook_data.remote_addr, + "headers": headers_to_value_map(hook_data.headers , false) + } + }) + .to_string() +} + +#[must_use] +pub fn tusd_format(hook_data: &HookData) -> String { + json!({ + "upload": { + "ID": hook_data.file_info.id, + "Offset": hook_data.file_info.offset, + "Size": hook_data.file_info.length, + "CreatedAt": hook_data.file_info.created_at.timestamp(), + "SizeIsDeferred": hook_data.file_info.deferred_size, + "IsPartial": hook_data.file_info.is_partial, + "IsFinal": hook_data.file_info.is_final, + "MetaData": hook_data.file_info.metadata, + "Storage": { + "Type": hook_data.file_info.storage, + "Path": hook_data.file_info.path, + }, + "Parts": hook_data.file_info.parts, + }, + "HTTPRequest": { + "URI": hook_data.uri, + "Method": hook_data.method, + "RemoteAddr": hook_data.remote_addr, + "Header": headers_to_value_map(hook_data.headers , true) + } + }) + .to_string() +} diff --git a/src/protocol/core/get_info.rs b/src/protocol/core/get_info.rs deleted file mode 100644 index 94bbd3a..0000000 --- a/src/protocol/core/get_info.rs +++ /dev/null @@ -1,240 +0,0 @@ -use crate::errors::RustusError; -use actix_web::{ - http::header::{CacheControl, CacheDirective}, - web, HttpRequest, HttpResponse, -}; -use futures::stream::empty; - -use crate::{RustusResult, State}; - -pub async fn get_file_info( - state: web::Data, - request: HttpRequest, -) -> RustusResult { - // Getting file id from URL. - if request.match_info().get("file_id").is_none() { - return Err(RustusError::FileNotFound); - } - let file_id = request.match_info().get("file_id").unwrap(); - - // Getting file info from info_storage. - let file_info = state.info_storage.get_info(file_id).await?; - if file_info.storage != state.data_storage.to_string() { - return Err(RustusError::FileNotFound); - } - let mut builder = HttpResponse::Ok(); - if file_info.is_partial { - builder.insert_header(("Upload-Concat", "partial")); - } - if file_info.is_final && file_info.parts.is_some() { - #[allow(clippy::or_fun_call)] - let parts = file_info - .parts - .clone() - .unwrap() - .iter() - .map(|file| format!("/{}/{}", state.config.base_url(), file.as_str())) - .collect::>() - .join(" "); - builder.insert_header(("Upload-Concat", format!("final; {parts}"))); - } - builder - .no_chunking(file_info.offset as u64) - .insert_header(("Upload-Offset", file_info.offset.to_string())); - // Upload length is known. - if let Some(upload_len) = file_info.length { - builder - .no_chunking(upload_len as u64) - .insert_header(("Content-Length", file_info.offset.to_string())) - .insert_header(("Upload-Length", upload_len.to_string())); - } else { - builder.insert_header(("Upload-Defer-Length", "1")); - } - if let Some(meta) = file_info.get_metadata_string() { - builder.insert_header(("Upload-Metadata", meta)); - } - builder.insert_header(("Upload-Created", file_info.created_at.timestamp())); - builder.insert_header(CacheControl(vec![CacheDirective::NoCache])); - Ok(builder.streaming(empty::>())) -} - -#[cfg(test)] -mod tests { - use actix_web::http::{Method, StatusCode}; - - use crate::{server::test::get_service, State}; - use actix_web::test::{call_service, TestRequest}; - - use base64::{engine::general_purpose, Engine}; - - #[actix_rt::test] - async fn success() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let mut file_info = state.create_test_file().await; - file_info.offset = 100; - file_info.length = Some(100); - state - .info_storage - .set_info(&file_info, false) - .await - .unwrap(); - let request = TestRequest::with_uri(state.config.file_url(file_info.id.as_str()).as_str()) - .method(Method::HEAD) - .to_request(); - let response = call_service(&mut rustus, request).await; - let offset = response - .headers() - .get("Upload-Offset") - .unwrap() - .to_str() - .unwrap() - .parse::() - .unwrap(); - assert_eq!(file_info.offset, offset) - } - - #[actix_rt::test] - async fn success_metadata() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let mut file_info = state.create_test_file().await; - file_info.offset = 100; - file_info.length = Some(100); - file_info.metadata.insert("test".into(), "value".into()); - state - .info_storage - .set_info(&file_info, false) - .await - .unwrap(); - let request = TestRequest::with_uri(state.config.file_url(file_info.id.as_str()).as_str()) - .method(Method::HEAD) - .to_request(); - let response = call_service(&mut rustus, request).await; - let metadata = response - .headers() - .get("Upload-Metadata") - .unwrap() - .to_str() - .unwrap(); - assert_eq!( - String::from(metadata), - format!("{} {}", "test", general_purpose::STANDARD.encode("value")) - ) - } - - #[actix_rt::test] - async fn success_defer_len() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let mut file_info = state.create_test_file().await; - file_info.deferred_size = true; - file_info.length = None; - state - .info_storage - .set_info(&file_info, false) - .await - .unwrap(); - let request = TestRequest::with_uri(state.config.file_url(file_info.id.as_str()).as_str()) - .method(Method::HEAD) - .to_request(); - let response = call_service(&mut rustus, request).await; - assert_eq!( - response - .headers() - .get("Upload-Defer-Length") - .unwrap() - .to_str() - .unwrap(), - "1" - ); - } - - #[actix_rt::test] - async fn test_get_file_info_partial() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let mut file_info = state.create_test_file().await; - file_info.is_partial = true; - state - .info_storage - .set_info(&file_info, false) - .await - .unwrap(); - let request = TestRequest::with_uri(state.config.file_url(file_info.id.as_str()).as_str()) - .method(Method::HEAD) - .to_request(); - let response = call_service(&mut rustus, request).await; - assert_eq!( - response - .headers() - .get("Upload-Concat") - .unwrap() - .to_str() - .unwrap(), - "partial" - ); - } - - #[actix_rt::test] - async fn success_final() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let mut file_info = state.create_test_file().await; - file_info.is_partial = false; - file_info.is_final = true; - file_info.parts = Some(vec!["test1".into(), "test2".into()]); - state - .info_storage - .set_info(&file_info, false) - .await - .unwrap(); - let request = TestRequest::with_uri(state.config.file_url(file_info.id.as_str()).as_str()) - .method(Method::HEAD) - .to_request(); - let response = call_service(&mut rustus, request).await; - assert_eq!( - response - .headers() - .get("Upload-Concat") - .unwrap() - .to_str() - .unwrap(), - format!( - "final; {} {}", - state.config.file_url("test1").strip_suffix('/').unwrap(), - state.config.file_url("test2").strip_suffix('/').unwrap() - ) - .as_str() - ); - } - - #[actix_rt::test] - async fn no_file() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let request = TestRequest::with_uri(state.config.file_url("unknknown").as_str()) - .method(Method::HEAD) - .to_request(); - let response = call_service(&mut rustus, request).await; - assert_eq!(response.status(), StatusCode::NOT_FOUND); - } - - #[actix_rt::test] - async fn test_get_file_info_wrong_storage() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let mut file_info = state.create_test_file().await; - file_info.storage = String::from("unknown"); - state - .info_storage - .set_info(&file_info, false) - .await - .unwrap(); - let request = TestRequest::with_uri(state.config.file_url(file_info.id.as_str()).as_str()) - .method(Method::HEAD) - .to_request(); - let response = call_service(&mut rustus, request).await; - assert_eq!(response.status(), StatusCode::NOT_FOUND); - } -} diff --git a/src/protocol/core/mod.rs b/src/protocol/core/mod.rs deleted file mode 100644 index 4f438f7..0000000 --- a/src/protocol/core/mod.rs +++ /dev/null @@ -1,44 +0,0 @@ -use actix_web::{guard, middleware, web}; - -mod get_info; -mod server_info; -mod write_bytes; - -/// Add core TUS protocol endpoints. -/// -/// This part of a protocol -/// has several endpoints. -/// -/// OPTIONS /api - to get info about the app. -/// HEAD /api/file - to get info about the file. -/// PATCH /api/file - to add bytes to file. -#[cfg_attr(coverage, no_coverage)] -pub fn add_extension(web_app: &mut web::ServiceConfig) { - web_app - .service( - // PATCH /base/{file_id} - // Main URL for uploading files. - web::resource("/") - .name("core:server_info") - .guard(guard::Options()) - .to(server_info::server_info), - ) - .service( - // PATCH /base/{file_id} - // Main URL for uploading files. - web::resource("/{file_id}/") - .name("core:write_bytes") - .guard(guard::Patch()) - .to(write_bytes::write_bytes), - ) - .service( - // HEAD /base/{file_id} - // Main URL for getting info about files. - web::resource("/{file_id}/") - .name("core:file_info") - .guard(guard::Head()) - // Header to prevent the client and/or proxies from caching the response. - .wrap(middleware::DefaultHeaders::new().add(("Cache-Control", "no-store"))) - .to(get_info::get_file_info), - ); -} diff --git a/src/protocol/core/server_info.rs b/src/protocol/core/server_info.rs deleted file mode 100644 index ca8ba5b..0000000 --- a/src/protocol/core/server_info.rs +++ /dev/null @@ -1,55 +0,0 @@ -use crate::protocol::extensions::Extensions; -use actix_web::{http::StatusCode, web, HttpResponse, HttpResponseBuilder}; - -use crate::State; - -#[allow(clippy::needless_pass_by_value)] -#[allow(clippy::unused_async)] -pub async fn server_info(state: web::Data) -> HttpResponse { - let ext_str = state - .config - .tus_extensions - .iter() - .map(ToString::to_string) - .collect::>() - .join(","); - let mut response_builder = HttpResponseBuilder::new(StatusCode::OK); - response_builder.insert_header(("Tus-Extension", ext_str.as_str())); - if state.config.tus_extensions.contains(&Extensions::Checksum) { - response_builder.insert_header(("Tus-Checksum-Algorithm", "md5,sha1,sha256,sha512")); - } - response_builder.finish() -} - -#[cfg(test)] -mod tests { - use crate::{protocol::extensions::Extensions, server::test::get_service, State}; - use actix_web::test::{call_service, TestRequest}; - - use actix_web::http::Method; - - #[actix_rt::test] - async fn test_server_info() { - let mut state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - state.config.tus_extensions = vec![ - Extensions::Creation, - Extensions::Concatenation, - Extensions::Termination, - ]; - let request = TestRequest::with_uri(state.config.test_url().as_str()) - .method(Method::OPTIONS) - .to_request(); - let response = call_service(&mut rustus, request).await; - let extensions = response - .headers() - .get("Tus-Extension") - .unwrap() - .to_str() - .unwrap() - .clone(); - assert!(extensions.contains(Extensions::Creation.to_string().as_str())); - assert!(extensions.contains(Extensions::Concatenation.to_string().as_str())); - assert!(extensions.contains(Extensions::Termination.to_string().as_str())); - } -} diff --git a/src/protocol/core/write_bytes.rs b/src/protocol/core/write_bytes.rs deleted file mode 100644 index c080715..0000000 --- a/src/protocol/core/write_bytes.rs +++ /dev/null @@ -1,432 +0,0 @@ -use actix_web::{ - http::header::{CacheControl, CacheDirective}, - web, - web::Bytes, - HttpRequest, HttpResponse, -}; - -use crate::{ - errors::RustusError, - metrics, - notifiers::Hook, - protocol::extensions::Extensions, - utils::{ - hashes::verify_chunk_checksum, - headers::{check_header, parse_header}, - }, - RustusResult, State, -}; - -pub async fn write_bytes( - request: HttpRequest, - bytes: Bytes, - state: web::Data, - metrics: web::Data, -) -> RustusResult { - // Checking if request has required headers. - let check_content_type = |val: &str| val == "application/offset+octet-stream"; - if !check_header(&request, "Content-Type", check_content_type) { - return Ok(HttpResponse::UnsupportedMediaType().body("Unknown content-type.")); - } - // Getting current offset. - let offset: Option = parse_header(&request, "Upload-Offset"); - - if offset.is_none() { - return Ok(HttpResponse::UnsupportedMediaType().body("No offset provided.")); - } - - if request.match_info().get("file_id").is_none() { - return Err(RustusError::FileNotFound); - } - - if state.config.tus_extensions.contains(&Extensions::Checksum) { - if let Some(header) = request.headers().get("Upload-Checksum").cloned() { - let cloned_bytes = bytes.clone(); - if !tokio::task::spawn_blocking(move || { - verify_chunk_checksum(&header, cloned_bytes.as_ref()) - }) - .await?? - { - return Err(RustusError::WrongChecksum); - } - } - } - - // New upload length. - // Parses header `Upload-Length` only if the creation-defer-length extension is enabled. - let updated_len = if state - .config - .tus_extensions - .contains(&Extensions::CreationDeferLength) - { - parse_header(&request, "Upload-Length") - } else { - None - }; - - let file_id = request.match_info().get("file_id").unwrap(); - // Getting file info. - let mut file_info = state.info_storage.get_info(file_id).await?; - - // According to TUS protocol you can't update final uploads. - if file_info.is_final { - return Ok(HttpResponse::Forbidden().finish()); - } - - // Checking if file was stored in the same storage. - if file_info.storage != state.data_storage.to_string() { - return Err(RustusError::FileNotFound); - } - // Checking if offset from request is the same as the real offset. - if offset.unwrap() != file_info.offset { - return Ok(HttpResponse::Conflict().finish()); - } - - // If someone want to update file length. - // This required by Upload-Defer-Length extension. - if let Some(new_len) = updated_len { - // Whoop, someone gave us total file length - // less that he had already uploaded. - if new_len < file_info.offset { - return Err(RustusError::WrongOffset); - } - // We already know the exact size of a file. - // Someone want to update it. - // Anyway, it's not allowed, heh. - if file_info.length.is_some() { - return Err(RustusError::SizeAlreadyKnown); - } - - // All checks are ok. Now our file will have exact size. - file_info.deferred_size = false; - file_info.length = Some(new_len); - } - - // Checking if the size of the upload is already equals - // to calculated offset. It means that all bytes were already written. - if Some(file_info.offset) == file_info.length { - return Err(RustusError::FrozenFile); - } - let chunk_len = bytes.len(); - // Appending bytes to file. - state.data_storage.add_bytes(&file_info, bytes).await?; - // bytes.clear() - // Updating offset. - file_info.offset += chunk_len; - // Saving info to info storage. - state.info_storage.set_info(&file_info, false).await?; - - let mut hook = Hook::PostReceive; - - if file_info.length == Some(file_info.offset) { - hook = Hook::PostFinish; - } - if state.config.hook_is_active(hook) { - let message = state.config.notification_opts.hooks_format.format( - &request, - &file_info, - state.config.notification_opts.behind_proxy, - ); - let headers = request.headers().clone(); - tokio::task::spawn_local(async move { - state - .notification_manager - .send_message(message, hook, &headers) - .await - }); - } - - if hook == Hook::PostFinish { - metrics.active_uploads.dec(); - metrics.finished_uploads.inc(); - } - - Ok(HttpResponse::NoContent() - .insert_header(("Upload-Offset", file_info.offset.to_string())) - .insert_header(CacheControl(vec![CacheDirective::NoCache])) - .finish()) -} - -#[cfg(test)] -mod tests { - use crate::{server::test::get_service, State}; - use actix_web::{ - http::StatusCode, - test::{call_service, TestRequest}, - }; - - #[actix_rt::test] - /// Success test for writing bytes. - /// - /// This test creates file and writes bytes to it. - async fn success() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let mut file = state.create_test_file().await; - file.length = Some(100); - file.offset = 0; - state.info_storage.set_info(&file, false).await.unwrap(); - let test_data = "memes"; - let request = TestRequest::patch() - .uri(state.config.file_url(file.id.as_str()).as_str()) - .insert_header(("Content-Type", "application/offset+octet-stream")) - .insert_header(("Upload-Checksum", "md5 xIwpFX4rNYzBRAJ/Pi2MtA==")) - .insert_header(("Upload-Offset", file.offset)) - .set_payload(test_data) - .to_request(); - let resp = call_service(&mut rustus, request).await; - assert_eq!(resp.status(), StatusCode::NO_CONTENT); - assert_eq!( - resp.headers() - .get("Upload-Offset") - .unwrap() - .to_str() - .unwrap(), - test_data.len().to_string().as_str() - ); - let new_info = state - .info_storage - .get_info(file.id.clone().as_str()) - .await - .unwrap(); - assert_eq!(new_info.offset, test_data.len()); - } - - #[actix_rt::test] - /// Testing defer-length extension. - /// - /// During this test we'll try to update - /// file's length while writing bytes to it. - async fn success_update_file_length() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let mut file = state.create_test_file().await; - file.length = None; - file.deferred_size = true; - file.offset = 0; - state.info_storage.set_info(&file, false).await.unwrap(); - let test_data = "memes"; - let request = TestRequest::patch() - .uri(state.config.file_url(file.id.as_str()).as_str()) - .param("file_id", file.id.clone()) - .insert_header(("Content-Type", "application/offset+octet-stream")) - .insert_header(("Upload-Offset", file.offset)) - .insert_header(("Upload-Length", "20")) - .set_payload(test_data) - .to_request(); - let resp = call_service(&mut rustus, request).await; - assert_eq!(resp.status(), StatusCode::NO_CONTENT); - assert_eq!( - resp.headers() - .get("Upload-Offset") - .unwrap() - .to_str() - .unwrap(), - test_data.len().to_string().as_str() - ); - let new_info = state - .info_storage - .get_info(file.id.clone().as_str()) - .await - .unwrap(); - assert_eq!(new_info.offset, test_data.len()); - assert_eq!(new_info.deferred_size, false); - assert_eq!(new_info.length, Some(20)); - } - - #[actix_rt::test] - /// Tests that if new file length - /// is less than current offset, error is thrown. - async fn new_file_length_lt_offset() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let mut file = state.create_test_file().await; - file.length = None; - file.deferred_size = true; - file.offset = 30; - state.info_storage.set_info(&file, false).await.unwrap(); - let test_data = "memes"; - let request = TestRequest::patch() - .uri(state.config.file_url(file.id.as_str()).as_str()) - .insert_header(("Content-Type", "application/offset+octet-stream")) - .insert_header(("Upload-Offset", file.offset)) - .insert_header(("Upload-Length", "20")) - .set_payload(test_data) - .to_request(); - let resp = call_service(&mut rustus, request).await; - assert_eq!(resp.status(), StatusCode::CONFLICT); - } - - #[actix_rt::test] - /// Tests if user tries to update - /// file length with known length, - /// error is thrown. - async fn new_file_length_size_already_known() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let mut file = state.create_test_file().await; - file.length = Some(100); - file.deferred_size = false; - file.offset = 0; - state.info_storage.set_info(&file, false).await.unwrap(); - let test_data = "memes"; - let request = TestRequest::patch() - .uri(state.config.file_url(file.id.as_str()).as_str()) - .insert_header(("Content-Type", "application/offset+octet-stream")) - .insert_header(("Upload-Offset", file.offset)) - .insert_header(("Upload-Length", "120")) - .set_payload(test_data) - .to_request(); - let resp = call_service(&mut rustus, request).await; - assert_eq!(resp.status(), StatusCode::BAD_REQUEST); - } - - #[actix_rt::test] - /// Checks that if Content-Type header missing, - /// wrong status code is returned. - async fn no_content_header() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let mut file = state.create_test_file().await; - file.length = Some(100); - file.offset = 0; - state.info_storage.set_info(&file, false).await.unwrap(); - let request = TestRequest::patch() - .uri(state.config.file_url(file.id.as_str()).as_str()) - .insert_header(("Upload-Offset", "0")) - .set_payload("memes") - .to_request(); - let resp = call_service(&mut rustus, request).await; - assert_eq!(resp.status(), StatusCode::UNSUPPORTED_MEDIA_TYPE); - } - - #[actix_rt::test] - /// Tests that method will return error if no offset header specified. - async fn no_offset_header() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let mut file = state.create_test_file().await; - file.length = Some(100); - file.offset = 0; - state.info_storage.set_info(&file, false).await.unwrap(); - let request = TestRequest::patch() - .uri(state.config.file_url(file.id.as_str()).as_str()) - .insert_header(("Content-Type", "application/offset+octet-stream")) - .set_payload("memes") - .to_request(); - let resp = call_service(&mut rustus, request).await; - assert_eq!(resp.status(), StatusCode::UNSUPPORTED_MEDIA_TYPE); - } - - #[actix_rt::test] - /// Tests that method will return error if wrong offset is passed. - async fn wrong_offset_header() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let mut file = state.create_test_file().await; - file.length = Some(100); - file.offset = 0; - state.info_storage.set_info(&file, false).await.unwrap(); - let request = TestRequest::patch() - .uri(state.config.file_url(file.id.as_str()).as_str()) - .insert_header(("Upload-Offset", "1")) - .insert_header(("Content-Type", "application/offset+octet-stream")) - .set_payload("memes") - .to_request(); - let resp = call_service(&mut rustus, request).await; - assert_eq!(resp.status(), StatusCode::CONFLICT); - } - - #[actix_rt::test] - /// Tests that method would return error if file was already uploaded. - async fn final_upload() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let mut file = state.create_test_file().await; - file.is_final = true; - state.info_storage.set_info(&file, false).await.unwrap(); - let request = TestRequest::patch() - .uri(state.config.file_url(file.id.as_str()).as_str()) - .insert_header(("Upload-Offset", file.offset)) - .insert_header(("Content-Type", "application/offset+octet-stream")) - .set_payload("memes") - .to_request(); - let resp = call_service(&mut rustus, request).await; - assert_eq!(resp.status(), StatusCode::FORBIDDEN); - } - - #[actix_rt::test] - /// Tests that method would return 404 if file was saved in other storage. - async fn wrong_storage() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let mut file = state.create_test_file().await; - file.storage = "unknown".into(); - state.info_storage.set_info(&file, false).await.unwrap(); - let request = TestRequest::patch() - .uri(state.config.file_url(file.id.as_str()).as_str()) - .insert_header(("Upload-Offset", file.offset)) - .insert_header(("Content-Type", "application/offset+octet-stream")) - .set_payload("memes") - .to_request(); - let resp = call_service(&mut rustus, request).await; - assert_eq!(resp.status(), StatusCode::NOT_FOUND); - } - - #[actix_rt::test] - /// Tests that method won't allow you to update - /// file if it's offset already equal to length. - async fn frozen_file() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let mut file = state.create_test_file().await; - file.offset = 10; - file.length = Some(10); - state.info_storage.set_info(&file, false).await.unwrap(); - let request = TestRequest::patch() - .uri(state.config.file_url(file.id.as_str()).as_str()) - .insert_header(("Upload-Offset", file.offset)) - .insert_header(("Content-Type", "application/offset+octet-stream")) - .set_payload("memes") - .to_request(); - let resp = call_service(&mut rustus, request).await; - println!("{:?}", resp.response().body()); - assert_eq!(resp.status(), StatusCode::BAD_REQUEST); - } - - #[actix_rt::test] - /// Tests that method will return 404 if - /// unknown file_id is passed. - async fn unknown_file_id() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let request = TestRequest::patch() - .uri(state.config.file_url("unknown").as_str()) - .insert_header(("Upload-Offset", "0")) - .insert_header(("Content-Type", "application/offset+octet-stream")) - .set_payload("memes") - .to_request(); - let resp = call_service(&mut rustus, request).await; - assert_eq!(resp.status(), StatusCode::NOT_FOUND); - } - - #[actix_rt::test] - /// Tests checksum validation. - async fn wrong_checksum() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let mut file = state.create_test_file().await; - file.offset = 0; - file.length = Some(10); - state.info_storage.set_info(&file, false).await.unwrap(); - let request = TestRequest::patch() - .uri(state.config.file_url(file.id.as_str()).as_str()) - .insert_header(("Upload-Offset", "0")) - .insert_header(("Upload-Checksum", "md5 K9opmNmw7hl9oUKgRH9nJQ==")) - .insert_header(("Content-Type", "application/offset+octet-stream")) - .set_payload("memes") - .to_request(); - let resp = call_service(&mut rustus, request).await; - assert_eq!(resp.status(), StatusCode::EXPECTATION_FAILED); - } -} diff --git a/src/protocol/creation/mod.rs b/src/protocol/creation/mod.rs deleted file mode 100644 index f00f01c..0000000 --- a/src/protocol/creation/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -use actix_web::{guard, web}; -mod routes; - -/// Add creation extensions. -/// -/// This extension allows you -/// to create file before sending data. -#[cfg_attr(coverage, no_coverage)] -pub fn add_extension(web_app: &mut web::ServiceConfig) { - web_app.service( - // Post /base - // URL for creating files. - web::resource("/") - .name("creation:create_file") - .guard(guard::Post()) - .to(routes::create_file), - ); -} diff --git a/src/protocol/creation/routes.rs b/src/protocol/creation/routes.rs deleted file mode 100644 index d5da9c5..0000000 --- a/src/protocol/creation/routes.rs +++ /dev/null @@ -1,584 +0,0 @@ -use actix_web::{web, web::Bytes, HttpRequest, HttpResponse}; -use base64::{engine::general_purpose, Engine}; -use std::collections::HashMap; - -use crate::{ - info_storages::FileInfo, - metrics, - notifiers::Hook, - protocol::extensions::Extensions, - utils::headers::{check_header, parse_header}, - State, -}; - -/// Get metadata info from request. -/// -/// Metadata is located in Upload-Metadata header. -/// Key and values are separated by spaces and -/// pairs are delimited with commas. -/// -/// E.G. -/// `Upload-Metadata: Video bWVtZXM=,Category bWVtZXM=` -/// -/// All values are encoded as base64 strings. -fn get_metadata(request: &HttpRequest) -> Option> { - request - .headers() - .get("Upload-Metadata") - .and_then(|her| match her.to_str() { - Ok(str_val) => Some(String::from(str_val)), - Err(_) => None, - }) - .map(|header_string| { - let mut meta_map = HashMap::new(); - for meta_pair in header_string.split(',') { - let mut split = meta_pair.trim().split(' '); - let key = split.next(); - let b64val = split.next(); - if key.is_none() || b64val.is_none() { - continue; - } - let value = general_purpose::STANDARD - .decode(b64val.unwrap()) - .map(|value| match String::from_utf8(value) { - Ok(val) => Some(val), - Err(_) => None, - }); - if let Ok(Some(res)) = value { - meta_map.insert(String::from(key.unwrap()), res); - } - } - meta_map - }) -} - -fn get_upload_parts(request: &HttpRequest) -> Vec { - let concat_header = request.headers().get("Upload-Concat").unwrap(); - let header_str = concat_header.to_str().unwrap(); - let urls = header_str.strip_prefix("final;").unwrap(); - - urls.split(' ') - .filter_map(|val: &str| val.trim().split('/').last().map(String::from)) - .filter(|val| val.trim() != "") - .collect() -} - -/// Create file. -/// -/// This method allows you to create file to start uploading. -/// -/// This method supports defer-length if -/// you don't know actual file length and -/// you can upload first bytes if creation-with-upload -/// extension is enabled. -#[allow(clippy::too_many_lines)] -pub async fn create_file( - metrics: web::Data, - state: web::Data, - request: HttpRequest, - bytes: Bytes, -) -> actix_web::Result { - // Getting Upload-Length header value as usize. - let length = parse_header(&request, "Upload-Length"); - - // With this option enabled, - // we have to check whether length is a non-zero number. - if !state.config.allow_empty { - if let Some(0) = length { - return Ok(HttpResponse::BadRequest().body("Upload-Length should be greater than zero")); - } - } - - // Checking Upload-Defer-Length header. - let defer_size = check_header(&request, "Upload-Defer-Length", |val| val == "1"); - - // Indicator that creation-defer-length is enabled. - let defer_ext = state - .config - .tus_extensions - .contains(&Extensions::CreationDeferLength); - - let is_final = check_header(&request, "Upload-Concat", |val| val.starts_with("final;")); - - let concat_ext = state - .config - .tus_extensions - .contains(&Extensions::Concatenation); - - // Check that Upload-Length header is provided. - // Otherwise checking that defer-size feature is enabled - // and header provided. - if length.is_none() && !((defer_ext && defer_size) || (concat_ext && is_final)) { - return Ok(HttpResponse::BadRequest().body("Upload-Length header is required")); - } - - if state.config.max_file_size.is_some() && state.config.max_file_size < length { - return Ok(HttpResponse::BadRequest().body(format!( - "Upload-Length should be less than or equal to {}", - state.config.max_file_size.unwrap() - ))); - } - - let meta = get_metadata(&request); - - let file_id = uuid::Uuid::new_v4().to_string(); - let mut file_info = FileInfo::new( - file_id.as_str(), - length, - None, - state.data_storage.to_string(), - meta, - ); - - let is_partial = check_header(&request, "Upload-Concat", |val| val == "partial"); - - if concat_ext { - if is_final { - file_info.is_final = true; - let upload_parts = get_upload_parts(&request); - if upload_parts.is_empty() { - return Ok(HttpResponse::BadRequest() - .body("Upload-Concat header has no parts to create final upload.")); - } - file_info.parts = Some(upload_parts); - file_info.deferred_size = false; - } - if is_partial { - file_info.is_partial = true; - } - } - - if state.config.hook_is_active(Hook::PreCreate) { - let message = state.config.notification_opts.hooks_format.format( - &request, - &file_info, - state.config.notification_opts.behind_proxy, - ); - let headers = request.headers(); - state - .notification_manager - .send_message(message, Hook::PreCreate, headers) - .await?; - } - - // Create file and get the it's path. - file_info.path = Some(state.data_storage.create_file(&file_info).await?); - - // Incrementing number of active uploads - - metrics.active_uploads.inc(); - metrics.started_uploads.inc(); - - if let Some(length) = file_info.length { - #[allow(clippy::cast_precision_loss)] - metrics.upload_sizes.observe(length as f64); - } - - if file_info.is_final { - let mut final_size = 0; - let mut parts_info = Vec::new(); - for part_id in file_info.clone().parts.unwrap() { - let part = state.info_storage.get_info(part_id.as_str()).await?; - if part.length != Some(part.offset) { - return Ok( - HttpResponse::BadRequest().body(format!("{} upload is not complete.", part.id)) - ); - } - if !part.is_partial { - return Ok( - HttpResponse::BadRequest().body(format!("{} upload is not partial.", part.id)) - ); - } - final_size += &part.length.unwrap(); - parts_info.push(part.clone()); - } - state - .data_storage - .concat_files(&file_info, parts_info.clone()) - .await?; - file_info.offset = final_size; - file_info.length = Some(final_size); - if state.config.remove_parts { - for part in parts_info { - state.data_storage.remove_file(&part).await?; - state.info_storage.remove_info(part.id.as_str()).await?; - } - } - } - - // Checking if creation-with-upload extension is enabled. - let with_upload = state - .config - .tus_extensions - .contains(&Extensions::CreationWithUpload); - if with_upload && !bytes.is_empty() && !(concat_ext && is_final) { - let octet_stream = |val: &str| val == "application/offset+octet-stream"; - if check_header(&request, "Content-Type", octet_stream) { - // Writing first bytes. - let chunk_len = bytes.len(); - // Appending bytes to file. - state.data_storage.add_bytes(&file_info, bytes).await?; - // Updating offset. - file_info.offset += chunk_len; - } - } - - state.info_storage.set_info(&file_info, true).await?; - - // It's more intuitive to send post-finish - // hook, when final upload is created. - // https://github.com/s3rius/rustus/issues/77 - let mut post_hook = Hook::PostCreate; - if file_info.is_final || Some(file_info.offset) == file_info.length { - post_hook = Hook::PostFinish; - } - - if state.config.hook_is_active(post_hook) { - let message = state.config.notification_opts.hooks_format.format( - &request, - &file_info, - state.config.notification_opts.behind_proxy, - ); - let headers = request.headers().clone(); - // Adding send_message task to tokio reactor. - // Thin function would be executed in background. - tokio::task::spawn_local(async move { - state - .notification_manager - .send_message(message, post_hook, &headers) - .await - }); - } - - // Create upload URL for this file. - let upload_url = request.url_for("core:write_bytes", [file_info.id.clone()])?; - - Ok(HttpResponse::Created() - .insert_header(( - "Location", - upload_url - .as_str() - .strip_suffix('/') - .unwrap_or(upload_url.as_str()), - )) - .insert_header(("Upload-Offset", file_info.offset.to_string())) - .finish()) -} - -#[cfg(test)] -mod tests { - use crate::{server::test::get_service, State}; - use actix_web::{ - http::StatusCode, - test::{call_service, TestRequest}, - web, - }; - use base64::{engine::general_purpose, Engine}; - - #[actix_rt::test] - async fn success() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let request = TestRequest::post() - .uri(state.config.test_url().as_str()) - .insert_header(("Upload-Length", 100)) - .to_request(); - let resp = call_service(&mut rustus, request).await; - assert_eq!(resp.status(), StatusCode::CREATED); - // Getting file from location header. - let item_id = resp - .headers() - .get("Location") - .unwrap() - .to_str() - .unwrap() - .split('/') - .last() - .unwrap(); - let file_info = state.info_storage.get_info(item_id).await.unwrap(); - assert_eq!(file_info.length, Some(100)); - assert_eq!(file_info.offset, 0); - } - - #[actix_rt::test] - async fn wrong_length() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let request = TestRequest::post() - .uri(state.config.test_url().as_str()) - .insert_header(("Upload-Length", 0)) - .to_request(); - let resp = call_service(&mut rustus, request).await; - assert_eq!(resp.status(), StatusCode::BAD_REQUEST); - } - - #[actix_rt::test] - async fn allow_empty() { - let mut state = State::test_new().await; - state.config.allow_empty = true; - let mut rustus = get_service(state.clone()).await; - let request = TestRequest::post() - .uri(state.config.test_url().as_str()) - .insert_header(("Upload-Length", 0)) - .to_request(); - let resp = call_service(&mut rustus, request).await; - assert_eq!(resp.status(), StatusCode::CREATED); - } - - #[actix_rt::test] - async fn success_with_bytes() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let test_data = "memes"; - let request = TestRequest::post() - .uri(state.config.test_url().as_str()) - .insert_header(("Upload-Length", 100)) - .insert_header(("Content-Type", "application/offset+octet-stream")) - .set_payload(web::Bytes::from(test_data)) - .to_request(); - let resp = call_service(&mut rustus, request).await; - assert_eq!(resp.status(), StatusCode::CREATED); - // Getting file from location header. - let item_id = resp - .headers() - .get("Location") - .unwrap() - .to_str() - .unwrap() - .split('/') - .last() - .unwrap(); - let file_info = state.info_storage.get_info(item_id).await.unwrap(); - assert_eq!(file_info.length, Some(100)); - assert_eq!(file_info.offset, test_data.len()); - } - - #[actix_rt::test] - async fn with_bytes_wrong_content_type() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let test_data = "memes"; - let request = TestRequest::post() - .uri(state.config.test_url().as_str()) - .insert_header(("Upload-Length", 100)) - .insert_header(("Content-Type", "random")) - .set_payload(web::Bytes::from(test_data)) - .to_request(); - let resp = call_service(&mut rustus, request).await; - assert_eq!(resp.status(), StatusCode::CREATED); - // Getting file from location header. - let item_id = resp - .headers() - .get("Location") - .unwrap() - .to_str() - .unwrap() - .split('/') - .last() - .unwrap(); - let file_info = state.info_storage.get_info(item_id).await.unwrap(); - assert_eq!(file_info.length, Some(100)); - assert_eq!(file_info.offset, 0); - } - - #[actix_rt::test] - async fn success_defer_size() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let request = TestRequest::post() - .uri(state.config.test_url().as_str()) - .insert_header(("Upload-Defer-Length", "1")) - .to_request(); - let resp = call_service(&mut rustus, request).await; - assert_eq!(resp.status(), StatusCode::CREATED); - // Getting file from location header. - let item_id = resp - .headers() - .get("Location") - .unwrap() - .to_str() - .unwrap() - .split('/') - .last() - .unwrap(); - let file_info = state.info_storage.get_info(item_id).await.unwrap(); - assert_eq!(file_info.length, None); - assert!(file_info.deferred_size); - } - - #[actix_rt::test] - async fn success_partial_upload() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let request = TestRequest::post() - .uri(state.config.test_url().as_str()) - .insert_header(("Upload-Length", 100)) - .insert_header(("Upload-Concat", "partial")) - .to_request(); - let resp = call_service(&mut rustus, request).await; - assert_eq!(resp.status(), StatusCode::CREATED); - // Getting file from location header. - let item_id = resp - .headers() - .get("Location") - .unwrap() - .to_str() - .unwrap() - .split('/') - .last() - .unwrap(); - let file_info = state.info_storage.get_info(item_id).await.unwrap(); - assert_eq!(file_info.length, Some(100)); - assert!(file_info.is_partial); - assert_eq!(file_info.is_final, false); - } - - #[actix_rt::test] - async fn success_final_upload() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let mut part1 = state.create_test_file().await; - let mut part2 = state.create_test_file().await; - part1.is_partial = true; - part1.length = Some(100); - part1.offset = 100; - - part2.is_partial = true; - part2.length = Some(100); - part2.offset = 100; - - state.info_storage.set_info(&part1, false).await.unwrap(); - state.info_storage.set_info(&part2, false).await.unwrap(); - - let request = TestRequest::post() - .uri(state.config.test_url().as_str()) - .insert_header(("Upload-Length", 100)) - .insert_header(( - "Upload-Concat", - format!("final;/files/{} /files/{}", part1.id, part2.id), - )) - .to_request(); - let resp = call_service(&mut rustus, request).await; - assert_eq!(resp.status(), StatusCode::CREATED); - // Getting file from location header. - let item_id = resp - .headers() - .get("Location") - .unwrap() - .to_str() - .unwrap() - .split('/') - .last() - .unwrap(); - let file_info = state.info_storage.get_info(item_id).await.unwrap(); - assert_eq!(file_info.length, Some(200)); - assert!(file_info.is_final); - } - - #[actix_rt::test] - async fn invalid_final_upload_no_parts() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - - let request = TestRequest::post() - .uri(state.config.test_url().as_str()) - .insert_header(("Upload-Length", 100)) - .insert_header(("Upload-Concat", "final;")) - .to_request(); - let resp = call_service(&mut rustus, request).await; - assert_eq!(resp.status(), StatusCode::BAD_REQUEST); - } - - #[actix_rt::test] - async fn success_with_metadata() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let request = TestRequest::post() - .uri(state.config.test_url().as_str()) - .insert_header(("Upload-Length", 100)) - .insert_header(( - "Upload-Metadata", - format!( - "test {}, pest {}", - general_purpose::STANDARD.encode("data1"), - general_purpose::STANDARD.encode("data2") - ), - )) - .to_request(); - let resp = call_service(&mut rustus, request).await; - assert_eq!(resp.status(), StatusCode::CREATED); - // Getting file from location header. - let item_id = resp - .headers() - .get("Location") - .unwrap() - .to_str() - .unwrap() - .split('/') - .last() - .unwrap(); - let file_info = state.info_storage.get_info(item_id).await.unwrap(); - assert_eq!(file_info.length, Some(100)); - assert_eq!(file_info.metadata.get("test").unwrap(), "data1"); - assert_eq!(file_info.metadata.get("pest").unwrap(), "data2"); - assert_eq!(file_info.offset, 0); - } - - #[actix_rt::test] - async fn success_with_metadata_wrong_encoding() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let request = TestRequest::post() - .uri(state.config.test_url().as_str()) - .insert_header(("Upload-Length", 100)) - .insert_header(( - "Upload-Metadata", - format!( - "test data1, pest {}", - general_purpose::STANDARD.encode("data") - ), - )) - .to_request(); - let resp = call_service(&mut rustus, request).await; - assert_eq!(resp.status(), StatusCode::CREATED); - // Getting file from location header. - let item_id = resp - .headers() - .get("Location") - .unwrap() - .to_str() - .unwrap() - .split('/') - .last() - .unwrap(); - let file_info = state.info_storage.get_info(item_id).await.unwrap(); - assert_eq!(file_info.length, Some(100)); - assert!(file_info.metadata.get("test").is_none()); - assert_eq!(file_info.metadata.get("pest").unwrap(), "data"); - assert_eq!(file_info.offset, 0); - } - - #[actix_rt::test] - async fn no_length_header() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let request = TestRequest::post() - .uri(state.config.test_url().as_str()) - .to_request(); - let resp = call_service(&mut rustus, request).await; - assert_eq!(resp.status(), StatusCode::BAD_REQUEST); - } - - #[actix_rt::test] - async fn max_file_size_exceeded() { - let mut state = State::test_new().await; - state.config.max_file_size = Some(1000); - let mut rustus = get_service(state.clone()).await; - let request = TestRequest::post() - .uri(state.config.test_url().as_str()) - .insert_header(("Upload-Length", 1001)) - .to_request(); - let resp = call_service(&mut rustus, request).await; - assert_eq!(resp.status(), StatusCode::BAD_REQUEST); - } -} diff --git a/src/protocol/extensions.rs b/src/protocol/extensions.rs deleted file mode 100644 index 9847523..0000000 --- a/src/protocol/extensions.rs +++ /dev/null @@ -1,25 +0,0 @@ -use derive_more::{Display, From}; -use strum::EnumIter; - -use crate::from_str; - -/// Enum of available Protocol Extensions -#[derive(PartialEq, Debug, PartialOrd, Display, EnumIter, From, Clone, Ord, Eq)] -pub enum Extensions { - #[display(fmt = "creation-defer-length")] - CreationDeferLength, - #[display(fmt = "creation-with-upload")] - CreationWithUpload, - #[display(fmt = "creation")] - Creation, - #[display(fmt = "termination")] - Termination, - #[display(fmt = "concatenation")] - Concatenation, - #[display(fmt = "getting")] - Getting, - #[display(fmt = "checksum")] - Checksum, -} - -from_str!(Extensions, "extension"); diff --git a/src/protocol/getting/mod.rs b/src/protocol/getting/mod.rs deleted file mode 100644 index d6f306b..0000000 --- a/src/protocol/getting/mod.rs +++ /dev/null @@ -1,20 +0,0 @@ -use actix_web::{guard, web}; - -mod routes; - -/// Add getting extension. -/// -/// This extension allows you -/// to get uploaded file. -/// -/// This is unofficial extension. -#[cfg_attr(coverage, no_coverage)] -pub fn add_extension(web_app: &mut web::ServiceConfig) { - web_app.service( - // GET /base/file - web::resource("/{file_id}/") - .name("getting:get") - .guard(guard::Get()) - .to(routes::get_file), - ); -} diff --git a/src/protocol/getting/routes.rs b/src/protocol/getting/routes.rs deleted file mode 100644 index 999f412..0000000 --- a/src/protocol/getting/routes.rs +++ /dev/null @@ -1,75 +0,0 @@ -use actix_web::{web, HttpRequest, HttpResponse}; - -use crate::{errors::RustusError, RustusResult, State}; - -/// Retrieve actual file. -/// -/// This method allows you to download files directly from storage. -pub async fn get_file(request: HttpRequest, state: web::Data) -> RustusResult { - let file_id_opt = request.match_info().get("file_id").map(String::from); - if let Some(file_id) = file_id_opt { - let file_info = state.info_storage.get_info(file_id.as_str()).await?; - if file_info.storage != state.data_storage.to_string() { - return Err(RustusError::FileNotFound); - } - state.data_storage.get_contents(&file_info, &request).await - } else { - Err(RustusError::FileNotFound) - } -} - -#[cfg(test)] -mod test { - use crate::{server::test::get_service, State}; - use actix_web::{ - http::StatusCode, - test::{call_service, TestRequest}, - }; - use bytes::Bytes; - - #[actix_rt::test] - async fn success() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let file_info = state.create_test_file().await; - state - .data_storage - .add_bytes(&file_info, Bytes::from("testing")) - .await - .unwrap(); - let request = TestRequest::get() - .uri(state.config.file_url(file_info.id.as_str()).as_str()) - .to_request(); - let resp = call_service(&mut rustus, request).await; - assert!(resp.status().is_success()); - } - - #[actix_rt::test] - async fn unknown_file_id() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let request = TestRequest::get() - .uri(state.config.file_url("random_str").as_str()) - .to_request(); - let resp = call_service(&mut rustus, request).await; - assert_eq!(resp.status(), StatusCode::NOT_FOUND); - } - - #[actix_rt::test] - async fn unknown_storage() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let mut file_info = state.create_test_file().await; - file_info.storage = "unknown_storage".into(); - state - .info_storage - .set_info(&file_info, false) - .await - .unwrap(); - let request = TestRequest::get() - .uri(state.config.file_url(file_info.id.as_str()).as_str()) - .to_request(); - let resp = call_service(&mut rustus, request).await; - assert_eq!(resp.status(), StatusCode::NOT_FOUND); - } -} diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs deleted file mode 100644 index c11cd0b..0000000 --- a/src/protocol/mod.rs +++ /dev/null @@ -1,32 +0,0 @@ -use actix_web::web; - -use crate::RustusConf; - -mod core; -mod creation; -pub mod extensions; -mod getting; -mod termination; - -/// Configure TUS web application. -/// -/// This function resolves all protocol extensions -/// provided by CLI into services and adds it to the application. -#[cfg_attr(coverage, no_coverage)] -pub fn setup(app_conf: RustusConf) -> impl Fn(&mut web::ServiceConfig) { - move |web_app| { - for extension in &app_conf.tus_extensions { - match extension { - extensions::Extensions::Creation => creation::add_extension(web_app), - extensions::Extensions::Termination => { - termination::add_extension(web_app); - } - extensions::Extensions::Getting => { - getting::add_extension(web_app); - } - _ => {} - } - } - core::add_extension(web_app); - } -} diff --git a/src/protocol/termination/mod.rs b/src/protocol/termination/mod.rs deleted file mode 100644 index c7fee5c..0000000 --- a/src/protocol/termination/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -use actix_web::{guard, web}; - -mod routes; - -/// Add termination extension. -/// -/// This extension allows you -/// to terminate file upload. -#[cfg_attr(coverage, no_coverage)] -pub fn add_extension(web_app: &mut web::ServiceConfig) { - web_app.service( - // DELETE /base/file - web::resource("/{file_id}/") - .name("termination:terminate") - .guard(guard::Delete()) - .to(routes::terminate), - ); -} diff --git a/src/protocol/termination/routes.rs b/src/protocol/termination/routes.rs deleted file mode 100644 index 067e239..0000000 --- a/src/protocol/termination/routes.rs +++ /dev/null @@ -1,113 +0,0 @@ -use actix_web::{web, HttpRequest, HttpResponse}; - -use crate::{ - errors::{RustusError, RustusResult}, - metrics, - notifiers::Hook, - State, -}; - -/// Terminate uploading. -/// -/// This method will remove all data by id. -/// It removes info and actual data. -pub async fn terminate( - request: HttpRequest, - state: web::Data, - metrics: web::Data, -) -> RustusResult { - let file_id_opt = request.match_info().get("file_id").map(String::from); - if let Some(file_id) = file_id_opt { - let file_info = state.info_storage.get_info(file_id.as_str()).await?; - if file_info.storage != state.data_storage.to_string() { - return Err(RustusError::FileNotFound); - } - if state.config.hook_is_active(Hook::PreTerminate) { - let message = state.config.notification_opts.hooks_format.format( - &request, - &file_info, - state.config.notification_opts.behind_proxy, - ); - let headers = request.headers(); - state - .notification_manager - .send_message(message, Hook::PreTerminate, headers) - .await?; - } - state.info_storage.remove_info(file_id.as_str()).await?; - state.data_storage.remove_file(&file_info).await?; - metrics.terminated_uploads.inc(); - if state.config.hook_is_active(Hook::PostTerminate) { - let message = state.config.notification_opts.hooks_format.format( - &request, - &file_info, - state.config.notification_opts.behind_proxy, - ); - let headers = request.headers().clone(); - tokio::task::spawn_local(async move { - state - .notification_manager - .send_message(message, Hook::PostTerminate, &headers) - .await - }); - } - } - Ok(HttpResponse::NoContent().finish()) -} - -#[cfg(test)] -mod tests { - use crate::{server::test::get_service, State}; - use actix_web::{ - http::StatusCode, - test::{call_service, TestRequest}, - }; - use std::path::PathBuf; - - #[actix_rt::test] - async fn success() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let file_info = state.create_test_file().await; - let request = TestRequest::delete() - .uri(state.config.file_url(file_info.id.as_str()).as_str()) - .to_request(); - let response = call_service(&mut rustus, request).await; - assert_eq!(response.status(), StatusCode::NO_CONTENT); - assert!(state - .info_storage - .get_info(file_info.id.as_str()) - .await - .is_err()); - assert!(!PathBuf::from(file_info.path.unwrap()).exists()); - } - - #[actix_rt::test] - async fn unknown_file_id() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let request = TestRequest::delete() - .param("file_id", "not_exists") - .to_request(); - let result = call_service(&mut rustus, request).await; - assert_eq!(result.status(), StatusCode::NOT_FOUND); - } - - #[actix_rt::test] - async fn wrong_storage() { - let state = State::test_new().await; - let mut rustus = get_service(state.clone()).await; - let mut file_info = state.create_test_file().await; - file_info.storage = "unknown_storage".into(); - state - .info_storage - .set_info(&file_info, false) - .await - .unwrap(); - let request = TestRequest::delete() - .uri(state.config.file_url(file_info.id.as_str()).as_str()) - .to_request(); - let response = call_service(&mut rustus, request).await; - assert_eq!(response.status(), StatusCode::NOT_FOUND); - } -} diff --git a/src/routes.rs b/src/routes.rs deleted file mode 100644 index fa54631..0000000 --- a/src/routes.rs +++ /dev/null @@ -1,17 +0,0 @@ -use actix_web::HttpResponse; - -/// Default response to all unknown URLs. -/// All protocol urls can be found -/// at `crate::protocol::*`. -#[allow(clippy::unused_async)] -#[cfg_attr(coverage, no_coverage)] -pub async fn not_found() -> HttpResponse { - HttpResponse::NotFound().finish() -} - -/// Checks that application is accepting connections correctly. -#[allow(clippy::unused_async)] -#[cfg_attr(coverage, no_coverage)] -pub async fn health_check() -> HttpResponse { - HttpResponse::Ok().finish() -} diff --git a/src/server.rs b/src/server.rs deleted file mode 100644 index 6a64328..0000000 --- a/src/server.rs +++ /dev/null @@ -1,45 +0,0 @@ -use crate::{protocol, State}; -use actix_web::{middleware, web, web::PayloadConfig}; - -pub fn rustus_service(state: State) -> impl Fn(&mut web::ServiceConfig) { - move |web_app| { - web_app.service( - web::scope(state.config.base_url().as_str()) - .app_data(web::Data::new(state.clone())) - .app_data(PayloadConfig::new(state.config.max_body_size)) - .wrap(middleware::NormalizePath::new( - middleware::TrailingSlash::Always, - )) - // Main middleware that appends TUS headers. - .wrap( - middleware::DefaultHeaders::new() - .add(("Tus-Resumable", "1.0.0")) - .add(("Tus-Version", "1.0.0")), - ) - .configure(protocol::setup(state.config.clone())), - ); - } -} - -#[cfg(test)] -pub mod test { - use super::rustus_service; - use crate::{metrics::RustusMetrics, state::State}; - use actix_web::{dev::ServiceResponse, test::init_service, web, App}; - - pub async fn get_service( - state: State, - ) -> impl actix_web::dev::Service< - actix_http::Request, - Response = ServiceResponse, - Error = actix_web::Error, - > { - let metrics = RustusMetrics::new().unwrap(); - init_service( - App::new() - .app_data(web::Data::new(metrics)) - .configure(rustus_service(state.clone())), - ) - .await - } -} diff --git a/src/server/cors.rs b/src/server/cors.rs new file mode 100644 index 0000000..4d6b0bc --- /dev/null +++ b/src/server/cors.rs @@ -0,0 +1,72 @@ +use std::{str::FromStr, time::Duration}; + +use http::{HeaderName, HeaderValue, Method}; +use tower_http::cors::{AllowOrigin, CorsLayer, MaxAge}; +use wildmatch::WildMatch; + +pub fn layer(origins: Vec, additional_headers: &[String]) -> CorsLayer { + let mut allow_headers = additional_headers + .iter() + .filter_map(|header| HeaderName::from_str(header).ok()) + .collect::>(); + allow_headers.extend_from_slice(&[ + HeaderName::from_static("content-type"), + HeaderName::from_static("upload-offset"), + HeaderName::from_static("upload-checksum"), + HeaderName::from_static("upload-length"), + HeaderName::from_static("upload-metadata"), + HeaderName::from_static("upload-concat"), + HeaderName::from_static("upload-defer-length"), + HeaderName::from_static("tus-resumable"), + HeaderName::from_static("tus-version"), + HeaderName::from_static("x-http-method-override"), + HeaderName::from_static("authorization"), + HeaderName::from_static("origin"), + HeaderName::from_static("x-requested-with"), + HeaderName::from_static("x-request-id"), + HeaderName::from_static("x-http-method-override"), + ]); + let mut cors = tower_http::cors::CorsLayer::new() + .allow_methods([ + Method::OPTIONS, + Method::GET, + Method::HEAD, + Method::POST, + Method::PATCH, + Method::DELETE, + ]) + .allow_headers(allow_headers) + .expose_headers(vec![ + HeaderName::from_static("location"), + HeaderName::from_static("tus-version"), + HeaderName::from_static("tus-resumable"), + HeaderName::from_static("tus-max-size"), + HeaderName::from_static("tus-extension"), + HeaderName::from_static("tus-checksum-algorithm"), + HeaderName::from_static("content-type"), + HeaderName::from_static("content-length"), + HeaderName::from_static("upload-length"), + HeaderName::from_static("upload-metadata"), + HeaderName::from_static("upload-defer-length"), + HeaderName::from_static("upload-concat"), + HeaderName::from_static("upload-offset"), + ]) + .max_age(MaxAge::exact(Duration::from_secs(86400))); + + if origins.is_empty() { + cors = cors.allow_origin(AllowOrigin::any()); + } else { + cors = cors.allow_origin(AllowOrigin::predicate( + move |request_origin: &HeaderValue, _| { + for origin in &origins { + if WildMatch::new(origin) == request_origin.to_str().unwrap_or_default() { + return true; + } + } + false + }, + )); + } + + cors +} diff --git a/src/server/mod.rs b/src/server/mod.rs new file mode 100644 index 0000000..95eb6e0 --- /dev/null +++ b/src/server/mod.rs @@ -0,0 +1,160 @@ +use std::{ + net::{Ipv4Addr, SocketAddr, SocketAddrV4}, + sync::Arc, +}; + +use crate::{ + config::Config, errors::RustusResult, state::RustusState, utils::headers::HeaderMapExt, +}; +use axum::{ + extract::{ConnectInfo, DefaultBodyLimit, State}, + http::HeaderValue, + Router, ServiceExt, +}; +use tower::Layer; + +mod cors; +mod routes; + +async fn logger( + State(config): State>, + req: axum::extract::Request, + next: axum::middleware::Next, +) -> impl axum::response::IntoResponse { + let default_addr = ConnectInfo(SocketAddr::V4(SocketAddrV4::new( + Ipv4Addr::new(0, 0, 0, 0), + 8000, + ))); + let socket = req + .extensions() + .get::>() + .unwrap_or(&default_addr); + let remote = req.headers().get_remote_ip(socket, config.behind_proxy); + let method = req.method().to_string(); + let uri = req + .uri() + .path_and_query() + .map(ToString::to_string) + .unwrap_or_default(); + + let time = std::time::Instant::now(); + let version = req.version(); + let response = next.run(req).await; + #[allow(clippy::cast_precision_loss)] + let elapsed = (time.elapsed().as_micros() as f64) / 1000.0; + let status = response.status().as_u16(); + + // log::log!(log::Level::Info, "ememe"); + if uri != "/health" { + let mut level = log::Level::Info; + if !response.status().is_success() { + level = log::Level::Error; + } + log::log!( + level, + "\"{method} {uri} {version:?}\" \"-\" \"{status}\" \"{remote}\" \"{elapsed}\"" + ); + } + + response +} + +async fn method_replacer( + mut req: axum::extract::Request, + next: axum::middleware::Next, +) -> impl axum::response::IntoResponse { + if let Some(new_method) = req.headers().get_method_override() { + *req.method_mut() = new_method; + req.headers_mut().remove("X-HTTP-Method-Override"); + } + next.run(req).await +} + +async fn add_tus_header( + State(state): State, + req: axum::extract::Request, + next: axum::middleware::Next, +) -> impl axum::response::IntoResponse { + let mut resp = next.run(req).await; + resp.headers_mut() + .insert("Tus-Resumable", HeaderValue::from_static("1.0.0")); + resp.headers_mut() + .insert("Tus-Version", HeaderValue::from_static("1.0.0")); + + let max_file_size = state + .max_file_size + .map(|val| val.to_string()) + .and_then(|val| HeaderValue::from_str(val.as_str()).ok()); + + if let Some(max_size) = max_file_size { + resp.headers_mut().insert("Tus-Max-Size", max_size); + } + + resp +} + +async fn healthcheck() -> impl axum::response::IntoResponse { + axum::http::StatusCode::OK +} + +async fn fallback() -> impl axum::response::IntoResponse { + (axum::http::StatusCode::NOT_FOUND, "Not found") +} + +pub fn get_router(state: Arc) -> Router { + let config = state.config.clone(); + axum::Router::new() + .route("/", axum::routing::post(routes::create::handler)) + .route("/:upload_id", axum::routing::patch(routes::upload::handler)) + .route("/:upload_id", axum::routing::get(routes::get_file::handler)) + .route( + "/:upload_id", + axum::routing::delete(routes::delete::handler), + ) + .route( + "/:upload_id", + axum::routing::head(routes::file_info::handler), + ) + .route_layer(cors::layer( + config.cors.clone(), + &config.notification_config.hooks_http_proxy_headers, + )) + .route("/", axum::routing::options(routes::info::handler)) + .with_state(state) + .route_layer(axum::middleware::from_fn_with_state( + config.clone(), + add_tus_header, + )) + .route_layer(DefaultBodyLimit::max(config.max_body_size)) +} + +/// Start the server. +/// Here we just create a state and router with all routes and middlewares. +/// +/// Then we start accepting incoming requests. +/// +/// # Errors +/// +/// This function returns an error if the server fails to start. +pub async fn start(config: Config) -> RustusResult<()> { + let listener = tokio::net::TcpListener::bind((config.host.clone(), config.port)).await?; + log::info!("Starting server at http://{}:{}", config.host, config.port); + let state = Arc::new(RustusState::from_config(&config).await?); + + let tus_app = get_router(state); + let main_router = axum::Router::new() + .route("/health", axum::routing::get(healthcheck)) + .nest(&config.url, tus_app) + .fallback(fallback); + + let service = axum::middleware::from_fn(method_replacer).layer( + axum::middleware::from_fn_with_state(Arc::new(config.clone()), logger).layer(main_router), + ); + + axum::serve( + listener, + service.into_make_service_with_connect_info::(), + ) + .await?; + Ok(()) +} diff --git a/src/server/routes/create.rs b/src/server/routes/create.rs new file mode 100644 index 0000000..5d9381b --- /dev/null +++ b/src/server/routes/create.rs @@ -0,0 +1,224 @@ +use std::{net::SocketAddr, sync::Arc}; + +use axum::{ + extract::{ConnectInfo, State}, + http::{HeaderMap, StatusCode}, + response::{IntoResponse, Response}, +}; +use bytes::Bytes; +use http::{Method, Uri}; + +use crate::{ + data_storage::base::Storage, + errors::RustusResult, + extensions::TusExtensions, + info_storages::base::InfoStorage, + models::file_info::FileInfo, + notifiers::hooks::Hook, + state::RustusState, + utils::{headers::HeaderMapExt, result::MonadLogger}, +}; + +#[allow(clippy::too_many_lines)] +pub async fn handler( + uri: Uri, + method: Method, + headers: HeaderMap, + ConnectInfo(addr): ConnectInfo, + State(state): State>, + body: Bytes, +) -> RustusResult { + let upload_len: Option = headers.parse("Upload-Length"); + if !state.config.allow_empty { + if let Some(0) = upload_len { + return Ok(( + StatusCode::BAD_REQUEST, + "Upload-Length must be greater than 0", + ) + .into_response()); + } + } + let defer_size = headers.check("Upload-Defer-Length", |val| val == "1"); + let defer_ext = state + .config + .tus_extensions_set + .contains(&TusExtensions::CreationDeferLength); + + let is_final = headers.check("Upload-Concat", |val| val.starts_with("final;")); + let concat_ext = state + .config + .tus_extensions_set + .contains(&TusExtensions::Concatenation); + + if upload_len.is_none() && !((defer_ext && defer_size) || (concat_ext && is_final)) { + return Ok((StatusCode::BAD_REQUEST, "Upload-Length is required").into_response()); + } + + if state.config.max_file_size.is_some() && state.config.max_file_size < upload_len { + return Ok(( + StatusCode::BAD_REQUEST, + format!( + "Upload-Length should be less than or equal to {}", + state.config.max_file_size.unwrap() + ), + ) + .into_response()); + } + + let meta = headers.get_metadata(); + + let file_id = uuid::Uuid::new_v4().to_string(); + let mut file_info = FileInfo::new( + file_id.as_str(), + upload_len, + None, + state.data_storage.get_name().to_string(), + meta, + ); + + let is_partial = headers.check("Upload-Concat", |val| val == "partial"); + + if concat_ext { + if is_final { + file_info.is_final = true; + let upload_parts = headers.get_upload_parts(); + if upload_parts.is_empty() { + return Ok(( + StatusCode::BAD_REQUEST, + "Upload-Concat header has no parts to create final upload.", + ) + .into_response()); + } + file_info.parts = Some(upload_parts); + file_info.deferred_size = false; + } + if is_partial { + file_info.is_partial = true; + } + } + + file_info.path = Some(state.data_storage.create_file(&file_info).await?); + + if file_info.is_final { + let mut final_size = 0; + let mut parts_info = Vec::new(); + for part_id in file_info.clone().parts.unwrap() { + let part = state.info_storage.get_info(part_id.as_str()).await?; + if part.length != Some(part.offset) { + return Ok(( + StatusCode::BAD_REQUEST, + format!("{} upload is not complete.", part.id), + ) + .into_response()); + } + if !part.is_partial { + return Ok(( + StatusCode::BAD_REQUEST, + format!("{} upload is not partial.", part.id), + ) + .into_response()); + } + final_size += &part.length.unwrap(); + parts_info.push(part.clone()); + } + state + .data_storage + .concat_files(&file_info, parts_info.clone()) + .await?; + file_info.offset = final_size; + file_info.length = Some(final_size); + if state.config.remove_parts { + for part in parts_info { + state.data_storage.remove_file(&part).await?; + state.info_storage.remove_info(part.id.as_str()).await?; + } + } + } + + if state + .config + .notification_hooks_set + .contains(&Hook::PreCreate) + { + state + .notificator + .send_message( + state.config.notification_config.hooks_format.format( + &uri, + &method, + &addr, + &headers, + state.config.behind_proxy, + &file_info, + ), + Hook::PreCreate, + &headers, + ) + .await?; + } + + // Checking if creation-with-upload extension is enabled. + let with_upload = state + .config + .tus_extensions + .contains(&TusExtensions::CreationWithUpload); + + if with_upload && !body.is_empty() && !(concat_ext && is_final) { + let octet_stream = |val: &str| val == "application/offset+octet-stream"; + if headers.check("Content-Type", octet_stream) { + // Writing first bytes. + let chunk_len = body.len(); + // Appending bytes to file. + state.data_storage.add_bytes(&file_info, body).await?; + // Updating offset. + file_info.offset += chunk_len; + } + } + + state.info_storage.set_info(&file_info, true).await?; + let upload_url = state.config.get_url(&file_info.id); + + // It's more intuitive to send post-finish + // hook, when final upload is created. + // https://github.com/s3rius/rustus/issues/77 + let mut post_hook = Hook::PostCreate; + if file_info.is_final || Some(file_info.offset) == file_info.length { + post_hook = Hook::PostFinish; + } + + if state.config.notification_hooks_set.contains(&post_hook) { + let message = state.config.notification_config.hooks_format.format( + &uri, + &method, + &addr, + &headers, + state.config.behind_proxy, + &file_info, + ); + let moved_state = state.clone(); + // Adding send_message task to tokio reactor. + // Thin function would be executed in background. + tokio::task::spawn(async move { + moved_state + .notificator + .send_message(message, post_hook, &headers) + .await + .mlog_warn( + format!( + "Failed to send PostReceive hook for upload {}", + file_info.id + ) + .as_str(), + ) + }); + } + + Ok(( + StatusCode::CREATED, + [ + ("Location", upload_url.as_str()), + ("Upload-Offset", file_info.offset.to_string().as_str()), + ], + ) + .into_response()) +} diff --git a/src/server/routes/delete.rs b/src/server/routes/delete.rs new file mode 100644 index 0000000..8a2d8ba --- /dev/null +++ b/src/server/routes/delete.rs @@ -0,0 +1,90 @@ +use std::{net::SocketAddr, sync::Arc}; + +use axum::{ + extract::{ConnectInfo, Path, State}, + http::StatusCode, + response::{IntoResponse, Response}, +}; +use http::{HeaderMap, Method, Uri}; + +use crate::{ + data_storage::base::Storage, + errors::{RustusError, RustusResult}, + extensions::TusExtensions, + info_storages::base::InfoStorage, + notifiers::hooks::Hook, + state::RustusState, + utils::result::MonadLogger, +}; + +pub async fn handler( + uri: Uri, + method: Method, + headers: HeaderMap, + ConnectInfo(addr): ConnectInfo, + State(state): State>, + Path(upload_id): Path, +) -> RustusResult { + if !state + .config + .tus_extensions_set + .contains(&TusExtensions::Termination) + { + return Ok(StatusCode::NOT_FOUND.into_response()); + } + + let file_info = state.info_storage.get_info(&upload_id).await?; + if file_info.storage != state.data_storage.get_name() { + return Err(RustusError::FileNotFound); + } + + if state + .config + .notification_hooks_set + .contains(&Hook::PreTerminate) + { + state + .notificator + .send_message( + state.config.notification_config.hooks_format.format( + &uri, + &method, + &addr, + &headers, + state.config.behind_proxy, + &file_info, + ), + Hook::PreTerminate, + &headers, + ) + .await?; + } + + state.data_storage.remove_file(&file_info).await?; + state.info_storage.remove_info(&file_info.id).await?; + + if state + .config + .notification_hooks_set + .contains(&Hook::PostTerminate) + { + let msg = state.config.notification_config.hooks_format.format( + &uri, + &method, + &addr, + &headers, + state.config.behind_proxy, + &file_info, + ); + let state_cln = state.clone(); + tokio::spawn(async move { + state_cln + .notificator + .send_message(msg, Hook::PostTerminate, &headers) + .await + .mlog_warn("Cannot send PostTerminate hook") + }); + } + + Ok(StatusCode::NO_CONTENT.into_response()) +} diff --git a/src/server/routes/file_info.rs b/src/server/routes/file_info.rs new file mode 100644 index 0000000..747a795 --- /dev/null +++ b/src/server/routes/file_info.rs @@ -0,0 +1,54 @@ +use std::sync::Arc; + +use axum::{ + extract::{Path, State}, + response::Response, +}; +use reqwest::StatusCode; + +use crate::{ + data_storage::base::Storage, errors::RustusResult, info_storages::base::InfoStorage, + state::RustusState, +}; + +pub async fn handler( + State(state): State>, + Path(upload_id): Path, +) -> RustusResult { + let file_info = state.info_storage.get_info(&upload_id).await?; + if file_info.storage != state.data_storage.get_name() { + return Err(crate::errors::RustusError::FileNotFound); + } + let mut response = Response::builder().status(StatusCode::OK); + + if file_info.is_partial { + response = response.header("Upload-Concat", "partial"); + } + if file_info.is_final && file_info.parts.is_some() { + let parts = file_info + .parts + .as_ref() + .unwrap() + .iter() + .map(|file| format!("/{}/{}", state.config.url, file.as_str())) + .collect::>() + .join(" "); + response = response.header("Upload-Concat", format!("final; {parts}")); + } + response = response.header("Upload-Offset", file_info.offset.to_string()); + if let Some(upload_len) = file_info.length { + response = response + .header("Content-Length", file_info.offset.to_string()) + .header("Upload-Length", upload_len.to_string()); + } else { + response = response.header("Upload-Defer-Length", "1"); + } + if let Some(meta) = file_info.get_metadata_string() { + response = response.header("Upload-Metadata", meta); + } + response = response.header( + "Upload-Created", + &file_info.created_at.timestamp().to_string(), + ); + Ok(response.body(axum::body::Body::empty())?) +} diff --git a/src/server/routes/get_file.rs b/src/server/routes/get_file.rs new file mode 100644 index 0000000..668b94e --- /dev/null +++ b/src/server/routes/get_file.rs @@ -0,0 +1,34 @@ +use std::sync::Arc; + +use axum::{ + extract::{Path, State}, + response::{IntoResponse, Response}, +}; +use reqwest::StatusCode; + +use crate::{ + data_storage::base::Storage, + errors::{RustusError, RustusResult}, + extensions::TusExtensions, + info_storages::base::InfoStorage, + state::RustusState, +}; + +pub async fn handler( + State(state): State>, + Path(upload_id): Path, +) -> RustusResult { + if !state + .config + .tus_extensions_set + .contains(&TusExtensions::Getting) + { + return Ok(StatusCode::NOT_FOUND.into_response()); + } + let file_info = state.info_storage.get_info(&upload_id).await?; + if file_info.storage != state.data_storage.get_name() { + return Err(RustusError::FileNotFound); + } + + state.data_storage.get_contents(&file_info).await +} diff --git a/src/server/routes/info.rs b/src/server/routes/info.rs new file mode 100644 index 0000000..2b4217e --- /dev/null +++ b/src/server/routes/info.rs @@ -0,0 +1,34 @@ +use std::sync::Arc; + +use axum::{ + extract::State, + http::{HeaderMap, StatusCode}, + response::IntoResponse, +}; + +use crate::{errors::RustusResult, extensions::TusExtensions, state::RustusState}; + +pub async fn handler( + State(ref state): State>, +) -> RustusResult { + let mut headers = HeaderMap::new(); + let extensions = state + .config + .tus_extensions + .iter() + .map(ToString::to_string) + .collect::>() + .join(","); + + headers.insert("tus-extension", extensions.parse()?); + + if state + .config + .tus_extensions + .contains(&TusExtensions::Checksum) + { + headers.insert("tus-checksum-algorithm", "md5,sha1,sha256,sha512".parse()?); + } + + Ok((StatusCode::NO_CONTENT, headers).into_response()) +} diff --git a/src/server/routes/mod.rs b/src/server/routes/mod.rs new file mode 100644 index 0000000..45e6e28 --- /dev/null +++ b/src/server/routes/mod.rs @@ -0,0 +1,6 @@ +pub mod create; +pub mod delete; +pub mod file_info; +pub mod get_file; +pub mod info; +pub mod upload; diff --git a/src/server/routes/upload.rs b/src/server/routes/upload.rs new file mode 100644 index 0000000..83c81dd --- /dev/null +++ b/src/server/routes/upload.rs @@ -0,0 +1,158 @@ +use std::{net::SocketAddr, sync::Arc}; + +use axum::{ + extract::{ConnectInfo, Path, State}, + http::{HeaderMap, StatusCode}, + response::IntoResponse, +}; +use bytes::Bytes; +use http::{Method, Uri}; + +use crate::{ + data_storage::base::Storage, + errors::{RustusError, RustusResult}, + extensions::TusExtensions, + info_storages::base::InfoStorage, + notifiers::hooks::Hook, + state::RustusState, + utils::{hashes::verify_chunk_checksum, headers::HeaderMapExt, result::MonadLogger}, +}; + +pub async fn handler( + uri: Uri, + method: Method, + headers: HeaderMap, + ConnectInfo(addr): ConnectInfo, + State(state): State>, + Path(upload_id): Path, + body: Bytes, +) -> RustusResult { + if !headers.check("Content-Type", |val| { + val == "application/offset+octet-stream" + }) { + return Ok((StatusCode::UNSUPPORTED_MEDIA_TYPE, "Unsupported media type").into_response()); + } + + let offset: Option = headers.parse("Upload-Offset"); + if offset.is_none() { + return Ok(( + StatusCode::UNSUPPORTED_MEDIA_TYPE, + "Missing Upload-Offset header", + ) + .into_response()); + } + + if state + .config + .tus_extensions_set + .contains(&TusExtensions::Checksum) + { + if let Some(check_sum) = headers.get("Upload-Checksum") { + if !verify_chunk_checksum(check_sum, &body)? { + return Err(RustusError::WrongChecksum); + } + } + } + + // Getting file info. + let mut file_info = state.info_storage.get_info(&upload_id).await?; + // According to TUS protocol you can't update final uploads. + if file_info.is_final { + return Ok((StatusCode::FORBIDDEN, "The upload is finished").into_response()); + } + + // Checking if file was stored in the same storage. + if file_info.storage != state.data_storage.get_name() { + return Err(RustusError::FileNotFound); + } + + // Checking if offset from request is the same as the real offset. + if offset.unwrap() != file_info.offset { + return Err(RustusError::WrongOffset); + } + + // New upload length. + // Parses header `Upload-Length` only if the creation-defer-length extension is enabled. + let updated_len = if state + .config + .tus_extensions + .contains(&TusExtensions::CreationDeferLength) + { + headers.parse("Upload-Length") + } else { + None + }; + + if let Some(new_len) = updated_len { + // Whoop, someone gave us total file length + // less that he had already uploaded. + if new_len < file_info.offset { + return Err(RustusError::WrongOffset); + } + // We already know the exact size of a file. + // Someone want to update it. + // Anyway, it's not allowed, heh. + if file_info.length.is_some() { + return Err(RustusError::SizeAlreadyKnown); + } + + // All checks are ok. Now our file will have exact size. + file_info.deferred_size = false; + file_info.length = Some(new_len); + } + + // Checking if the size of the upload is already equals + // to calculated offset. It means that all bytes were already written. + if Some(file_info.offset) == file_info.length { + return Err(RustusError::FrozenFile); + } + let chunk_len = body.len(); + + // Appending bytes to file. + state.data_storage.add_bytes(&file_info, body).await?; + // bytes.clear() + // Updating offset. + file_info.offset += chunk_len; + // Saving info to info storage. + state.info_storage.set_info(&file_info, false).await?; + + let mut hook = Hook::PostReceive; + + if file_info.length == Some(file_info.offset) { + hook = Hook::PostFinish; + } + + if state.config.notification_hooks_set.contains(&hook) { + let state_clone = state.clone(); + let msg = state.config.notification_config.hooks_format.format( + &uri, + &method, + &addr, + &headers, + state.config.behind_proxy, + &file_info, + ); + let headers_clone = headers.clone(); + + tokio::spawn(async move { + state_clone + .notificator + .send_message(msg, hook, &headers_clone) + .await + .mlog_warn( + format!( + "Failed to send PostReceive hook for upload {}", + file_info.id + ) + .as_str(), + ) + .ok(); + }); + } + + Ok(( + StatusCode::NO_CONTENT, + [("Upload-Offset", file_info.offset.to_string())], + ) + .into_response()) +} diff --git a/src/state.rs b/src/state.rs index c67ff1b..dcc3d16 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,76 +1,43 @@ -#[cfg(test)] -use crate::info_storages::FileInfo; -use crate::{InfoStorage, NotificationManager, RustusConf, Storage}; +use crate::{ + config::Config, + data_storage::{base::Storage, DataStorageImpl}, + errors::RustusResult, + info_storages::{base::InfoStorage, InfoStorageImpl}, + notifiers::NotificationManager, +}; #[derive(Clone)] -pub struct State { - pub config: RustusConf, - pub data_storage: Box, - pub info_storage: Box, - pub notification_manager: NotificationManager, +#[allow(clippy::module_name_repetitions)] +pub struct RustusState { + pub config: Config, + pub info_storage: InfoStorageImpl, + pub data_storage: DataStorageImpl, + pub notificator: NotificationManager, } -impl State { - pub fn new( - config: RustusConf, - data_storage: Box, - info_storage: Box, - notification_manager: NotificationManager, - ) -> Self { - Self { - config, - data_storage, - info_storage, - notification_manager, - } - } +impl RustusState { + /// Creates a new `RustusState` from a Config + /// + /// This function will create the necessary storages and notificator instances. + /// + /// Also it prepares everything before returning new state. + /// + /// # Errors + /// + /// If aything goes wrong, the error is returned. + pub async fn from_config(config: &Config) -> RustusResult { + let mut info_storage = InfoStorageImpl::new(config)?; + let mut data_storage = DataStorageImpl::new(config); + let mut notificator = NotificationManager::new(config); + info_storage.prepare().await?; + data_storage.prepare().await?; + notificator.prepare().await?; - #[cfg(test)] - pub async fn from_config_test(config: RustusConf) -> Self { - Self { + Ok(Self { config: config.clone(), - data_storage: Box::new(crate::storages::file_storage::FileStorage::new( - config.storage_opts.data_dir.clone(), - config.storage_opts.dir_structure.clone(), - config.storage_opts.force_fsync, - )), - info_storage: Box::new( - crate::info_storages::file_info_storage::FileInfoStorage::new( - config.info_storage_opts.info_dir.clone(), - ), - ), - notification_manager: NotificationManager::new(&config).await.unwrap(), - } - } - - #[cfg(test)] - pub async fn test_new() -> Self { - let data_dir = tempdir::TempDir::new("data_dir").unwrap(); - let info_dir = tempdir::TempDir::new("info_dir").unwrap(); - let config = RustusConf::from_iter( - vec![ - "rustus", - "--data-dir", - data_dir.into_path().to_str().unwrap(), - "--info-dir", - info_dir.into_path().to_str().unwrap(), - ] - .into_iter(), - ); - Self::from_config_test(config).await - } - - #[cfg(test)] - pub async fn create_test_file(&self) -> FileInfo { - let mut new_file = FileInfo::new( - uuid::Uuid::new_v4().to_string().as_str(), - Some(10), - None, - self.data_storage.to_string(), - None, - ); - new_file.path = Some(self.data_storage.create_file(&new_file).await.unwrap()); - self.info_storage.set_info(&new_file, true).await.unwrap(); - new_file + info_storage, + data_storage, + notificator, + }) } } diff --git a/src/storages/file_storage.rs b/src/storages/file_storage.rs deleted file mode 100644 index b386b41..0000000 --- a/src/storages/file_storage.rs +++ /dev/null @@ -1,355 +0,0 @@ -use std::{fs::File, io::Write, path::PathBuf}; - -use actix_files::NamedFile; -use actix_web::{HttpRequest, HttpResponse}; -use async_trait::async_trait; -use bytes::Bytes; -use log::error; -use std::{ - fs::{remove_file, DirBuilder, OpenOptions}, - io::{copy, BufReader, BufWriter}, -}; - -use crate::{ - errors::{RustusError, RustusResult}, - info_storages::FileInfo, - storages::Storage, - utils::dir_struct::substr_now, -}; -use derive_more::Display; - -#[derive(Display, Clone)] -#[display(fmt = "file_storage")] -pub struct FileStorage { - data_dir: PathBuf, - dir_struct: String, - force_fsync: bool, -} - -impl FileStorage { - pub fn new(data_dir: PathBuf, dir_struct: String, force_fsync: bool) -> FileStorage { - FileStorage { - data_dir, - dir_struct, - force_fsync, - } - } - - pub fn data_file_path(&self, file_id: &str) -> RustusResult { - let dir = self - .data_dir - // We're working wit absolute paths, because tus.io says so. - .canonicalize() - .map_err(|err| { - error!("{}", err); - RustusError::UnableToWrite(err.to_string()) - })? - .join(substr_now(self.dir_struct.as_str())); - DirBuilder::new() - .recursive(true) - .create(dir.as_path()) - .map_err(|err| { - error!("{}", err); - RustusError::UnableToWrite(err.to_string()) - })?; - Ok(dir.join(file_id)) - } -} - -#[async_trait(?Send)] -impl Storage for FileStorage { - async fn prepare(&mut self) -> RustusResult<()> { - // We're creating directory for new files - // if it doesn't already exist. - if !self.data_dir.exists() { - DirBuilder::new() - .recursive(true) - .create(self.data_dir.as_path()) - .map_err(|err| RustusError::UnableToPrepareStorage(err.to_string()))?; - } - Ok(()) - } - - async fn get_contents( - &self, - file_info: &FileInfo, - request: &HttpRequest, - ) -> RustusResult { - if let Some(path) = &file_info.path { - let file = File::open(path).map_err(|err| { - error!("{:?}", err); - RustusError::FileNotFound - })?; - Ok(NamedFile::from_file(file, file_info.get_filename()) - .map_err(|err| { - error!("{:?}", err); - RustusError::FileNotFound - })? - .into_response(request)) - } else { - Err(RustusError::FileNotFound) - } - } - - async fn add_bytes(&self, file_info: &FileInfo, mut bytes: Bytes) -> RustusResult<()> { - // In normal situation this `if` statement is not - // gonna be called, but what if it is ... - if file_info.path.is_none() { - return Err(RustusError::FileNotFound); - } - let path = file_info.path.as_ref().unwrap().clone(); - let force_sync = self.force_fsync; - tokio::task::spawn_blocking(move || { - // Opening file in w+a mode. - // It means that we're going to append some - // bytes to the end of a file. - let file = OpenOptions::new() - .write(true) - .append(true) - .create(false) - .read(false) - .truncate(false) - .open(path.as_str()) - .map_err(|err| { - error!("{:?}", err); - RustusError::UnableToWrite(err.to_string()) - })?; - let mut writer = BufWriter::new(file); - writer.write_all(bytes.as_ref())?; - writer.flush()?; - if force_sync { - writer.get_ref().sync_data()?; - } - bytes.clear(); - - Ok(()) - }) - .await? - } - - async fn create_file(&self, file_info: &FileInfo) -> RustusResult { - // New path to file. - let file_path = self.data_file_path(file_info.id.as_str())?; - tokio::task::spawn_blocking(move || { - // Creating new file. - OpenOptions::new() - .create(true) - .write(true) - .truncate(true) - .create_new(true) - .open(file_path.as_path()) - .map_err(|err| { - error!("{:?}", err); - RustusError::FileAlreadyExists - })?; - Ok(file_path.display().to_string()) - }) - .await? - } - - async fn concat_files( - &self, - file_info: &FileInfo, - parts_info: Vec, - ) -> RustusResult<()> { - let force_fsync = self.force_fsync; - let path = file_info.path.as_ref().unwrap().clone(); - tokio::task::spawn_blocking(move || { - let file = OpenOptions::new() - .write(true) - .append(true) - .create(true) - .open(path) - .map_err(|err| { - error!("{:?}", err); - RustusError::UnableToWrite(err.to_string()) - })?; - let mut writer = BufWriter::new(file); - for part in parts_info { - if part.path.is_none() { - return Err(RustusError::FileNotFound); - } - let part_file = OpenOptions::new() - .read(true) - .open(part.path.as_ref().unwrap())?; - let mut reader = BufReader::new(part_file); - copy(&mut reader, &mut writer)?; - } - writer.flush()?; - if force_fsync { - writer.get_ref().sync_data()?; - } - Ok(()) - }) - .await? - } - - async fn remove_file(&self, file_info: &FileInfo) -> RustusResult<()> { - let info = file_info.clone(); - tokio::task::spawn_blocking(move || { - // Let's remove the file itself. - let data_path = PathBuf::from(info.path.as_ref().unwrap().clone()); - if !data_path.exists() { - return Err(RustusError::FileNotFound); - } - remove_file(data_path).map_err(|err| { - error!("{:?}", err); - RustusError::UnableToRemove(info.id.clone()) - })?; - Ok(()) - }) - .await? - } -} - -#[cfg(test)] -mod tests { - use super::FileStorage; - use crate::{info_storages::FileInfo, Storage}; - use actix_web::test::TestRequest; - use bytes::Bytes; - use std::{ - fs::File, - io::{Read, Write}, - path::PathBuf, - }; - - #[actix_rt::test] - async fn preparation() { - let dir = tempdir::TempDir::new("file_storage").unwrap(); - let target_path = dir.into_path().join("not_exist"); - let mut storage = FileStorage::new(target_path.clone(), String::new(), false); - assert_eq!(target_path.exists(), false); - storage.prepare().await.unwrap(); - assert_eq!(target_path.exists(), true); - } - - #[actix_rt::test] - async fn create_file() { - let dir = tempdir::TempDir::new("file_storage").unwrap(); - let storage = FileStorage::new(dir.into_path().clone(), String::new(), false); - let file_info = FileInfo::new("test_id", Some(5), None, storage.to_string(), None); - let new_path = storage.create_file(&file_info).await.unwrap(); - assert!(PathBuf::from(new_path).exists()); - } - - #[actix_rt::test] - async fn create_file_but_it_exists() { - let dir = tempdir::TempDir::new("file_storage").unwrap(); - let base_path = dir.into_path().clone(); - let storage = FileStorage::new(base_path.clone(), String::new(), false); - let file_info = FileInfo::new("test_id", Some(5), None, storage.to_string(), None); - File::create(base_path.join("test_id")).unwrap(); - let result = storage.create_file(&file_info).await; - assert!(result.is_err()); - } - - #[actix_rt::test] - async fn adding_bytes() { - let dir = tempdir::TempDir::new("file_storage").unwrap(); - let storage = FileStorage::new(dir.into_path().clone(), String::new(), false); - let mut file_info = FileInfo::new("test_id", Some(5), None, storage.to_string(), None); - let new_path = storage.create_file(&file_info).await.unwrap(); - let test_data = "MyTestData"; - file_info.path = Some(new_path.clone()); - storage - .add_bytes(&file_info, Bytes::from(test_data)) - .await - .unwrap(); - let mut file = File::open(new_path).unwrap(); - let mut contents = String::new(); - file.read_to_string(&mut contents).unwrap(); - assert_eq!(contents, String::from(test_data)) - } - - #[actix_rt::test] - async fn adding_bytes_to_unknown_file() { - let dir = tempdir::TempDir::new("file_storage").unwrap(); - let storage = FileStorage::new(dir.into_path().clone(), String::new(), false); - let file_info = FileInfo::new( - "test_id", - Some(5), - Some(String::from("some_file")), - storage.to_string(), - None, - ); - let test_data = "MyTestData"; - let result = storage.add_bytes(&file_info, Bytes::from(test_data)).await; - assert!(result.is_err()) - } - - #[actix_rt::test] - async fn get_contents_of_unknown_file() { - let dir = tempdir::TempDir::new("file_storage").unwrap(); - let storage = FileStorage::new(dir.into_path().clone(), String::new(), false); - let file_info = FileInfo::new( - "test_id", - Some(5), - Some(storage.data_dir.join("unknown").display().to_string()), - storage.to_string(), - None, - ); - let request = TestRequest::get().to_http_request(); - let file_info = storage.get_contents(&file_info, &request).await; - assert!(file_info.is_err()); - } - - #[actix_rt::test] - async fn remove_unknown_file() { - let dir = tempdir::TempDir::new("file_storage").unwrap(); - let storage = FileStorage::new(dir.into_path().clone(), String::new(), false); - let file_info = FileInfo::new( - "test_id", - Some(5), - Some(storage.data_dir.join("unknown").display().to_string()), - storage.to_string(), - None, - ); - let file_info = storage.remove_file(&file_info).await; - assert!(file_info.is_err()); - } - - #[actix_rt::test] - async fn success_concatenation() { - let dir = tempdir::TempDir::new("file_storage").unwrap(); - let storage = FileStorage::new(dir.into_path().clone(), String::new(), false); - - let mut parts = Vec::new(); - let part1_path = storage.data_dir.as_path().join("part1"); - let mut part1 = File::create(part1_path.clone()).unwrap(); - let size1 = part1.write("hello ".as_bytes()).unwrap(); - - parts.push(FileInfo::new( - "part_id1", - Some(size1), - Some(part1_path.display().to_string()), - storage.to_string(), - None, - )); - - let part2_path = storage.data_dir.as_path().join("part2"); - let mut part2 = File::create(part2_path.clone()).unwrap(); - let size2 = part2.write("world".as_bytes()).unwrap(); - parts.push(FileInfo::new( - "part_id2", - Some(size2), - Some(part2_path.display().to_string()), - storage.to_string(), - None, - )); - - let final_info = FileInfo::new( - "final_id", - None, - Some(storage.data_dir.join("final_info").display().to_string()), - storage.to_string(), - None, - ); - storage.concat_files(&final_info, parts).await.unwrap(); - let mut final_file = File::open(final_info.path.unwrap()).unwrap(); - let mut buffer = String::new(); - final_file.read_to_string(&mut buffer).unwrap(); - - assert_eq!(buffer.as_str(), "hello world"); - } -} diff --git a/src/storages/mod.rs b/src/storages/mod.rs deleted file mode 100644 index e0421eb..0000000 --- a/src/storages/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod file_storage; -mod models; -pub mod s3_hybrid_storage; - -pub use models::{available_stores::AvailableStores, storage::Storage}; diff --git a/src/storages/models/available_stores.rs b/src/storages/models/available_stores.rs deleted file mode 100644 index 6dd9ea0..0000000 --- a/src/storages/models/available_stores.rs +++ /dev/null @@ -1,86 +0,0 @@ -use crate::{ - from_str, - storages::{file_storage, s3_hybrid_storage}, - RustusConf, Storage, -}; -use derive_more::{Display, From}; -use std::{ - fs::File, - io::{BufReader, Read}, - path::PathBuf, -}; -use strum::EnumIter; - -/// Enum of available Storage implementations. -#[derive(PartialEq, Eq, From, Display, EnumIter, Clone, Debug)] -pub enum AvailableStores { - #[display(fmt = "file-storage")] - FileStorage, - #[display(fmt = "hybrid-s3")] - HybridS3, -} - -from_str!(AvailableStores, "storage"); - -impl AvailableStores { - /// Convert `AvailableStores` to the Storage. - /// - /// # Params - /// `config` - Rustus configuration. - /// `info_storage` - Storage for information about files. - /// - #[cfg_attr(coverage, no_coverage)] - pub fn get(&self, config: &RustusConf) -> Box { - #[allow(clippy::single_match)] - match self { - Self::FileStorage => Box::new(file_storage::FileStorage::new( - config.storage_opts.data_dir.clone(), - config.storage_opts.dir_structure.clone(), - config.storage_opts.force_fsync, - )), - Self::HybridS3 => { - log::warn!("Hybrid S3 is an unstable feature. If you ecounter a problem, please raise an issue: https://github.com/s3rius/rustus/issues."); - let access_key = from_string_or_path( - &config.storage_opts.s3_access_key, - &config.storage_opts.s3_access_key_path, - ); - let secret_key = from_string_or_path( - &config.storage_opts.s3_secret_key, - &config.storage_opts.s3_secret_key_path, - ); - Box::new(s3_hybrid_storage::S3HybridStorage::new( - config.storage_opts.s3_url.clone().unwrap(), - config.storage_opts.s3_region.clone().unwrap(), - &Some(access_key), - &Some(secret_key), - &config.storage_opts.s3_security_token, - &config.storage_opts.s3_session_token, - &config.storage_opts.s3_profile, - &config.storage_opts.s3_headers, - config.storage_opts.s3_bucket.clone().unwrap().as_str(), - config.storage_opts.s3_force_path_style, - config.storage_opts.data_dir.clone(), - config.storage_opts.dir_structure.clone(), - config.storage_opts.force_fsync, - )) - } - } - } -} - -// TODO this should probably be a COW -fn from_string_or_path(variable: &Option, path: &Option) -> String { - if let Some(variable) = variable { - variable.to_string() - } else if let Some(path) = path { - let file = - File::open(path).unwrap_or_else(|_| panic!("failed to open path {}", path.display())); - let mut contents = String::new(); - BufReader::new(file) - .read_to_string(&mut contents) - .unwrap_or_else(|_| panic!("failed to read from path {}", path.display())); - contents - } else { - panic!("can't find {variable:?} or path {path:?}") - } -} diff --git a/src/storages/models/mod.rs b/src/storages/models/mod.rs deleted file mode 100644 index 6f58895..0000000 --- a/src/storages/models/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod available_stores; -pub mod storage; diff --git a/src/utils/dir_struct.rs b/src/utils/dir_struct.rs index c9142d7..484a2c4 100644 --- a/src/utils/dir_struct.rs +++ b/src/utils/dir_struct.rs @@ -1,11 +1,13 @@ use chrono::{Datelike, Timelike}; /// Generate directory name with user template. +#[must_use] pub fn substr_now(dir_structure: &str) -> String { let now = chrono::Utc::now(); substr_time(dir_structure, now) } +#[must_use] pub fn substr_time(dir_structure: &str, time: chrono::DateTime) -> String { dir_structure .replace("{day}", time.day().to_string().as_str()) diff --git a/src/utils/enums.rs b/src/utils/enums.rs index 4d90861..48a71ba 100644 --- a/src/utils/enums.rs +++ b/src/utils/enums.rs @@ -2,23 +2,20 @@ #[macro_export] macro_rules! from_str { ($enum_name:ty, $name:literal) => { - use std::str::FromStr; - use strum::IntoEnumIterator; - - impl FromStr for $enum_name { + impl std::str::FromStr for $enum_name { type Err = String; fn from_str(input: &str) -> Result { - let available_stores = <$enum_name>::iter() - .map(|info_store| format!("\t* {}", info_store.to_string())) - .collect::>() - .join("\n"); - let inp_string = String::from(input); - for store in <$enum_name>::iter() { - if inp_string == store.to_string() { + // We iterate over all enum values. + for store in ::iter() { + if input == store.to_string() { return Ok(store); } } + let available_stores = ::iter() + .map(|info_store| format!("\t* {}", info_store.to_string())) + .collect::>() + .join("\n"); Err(format!( "Unknown {} '{}'.\n Available {}s:\n{}", $name, input, $name, available_stores @@ -30,15 +27,16 @@ macro_rules! from_str { #[cfg(test)] mod tests { + use std::str::FromStr; + use crate::from_str; - use derive_more::{Display, From}; - use strum::EnumIter; + use strum::{Display, EnumIter}; - #[derive(PartialEq, Debug, Display, EnumIter, From, Clone, Eq)] + #[derive(PartialEq, Debug, Display, EnumIter, Clone, Eq)] pub enum TestEnum { - #[display(fmt = "test-val-1")] + #[strum(serialize = "test-val-1")] TestVal1, - #[display(fmt = "test-val-2")] + #[strum(serialize = "test-val-2")] TestVal2, } @@ -47,12 +45,12 @@ mod tests { #[test] fn test_from_str_unknown_val() { let result = TestEnum::from_str("unknown"); - assert!(result.is_err()) + assert!(result.is_err()); } #[test] fn test_from_str() { let result = TestEnum::from_str("test-val-1"); - assert_eq!(result.unwrap(), TestEnum::TestVal1) + assert_eq!(result.unwrap(), TestEnum::TestVal1); } } diff --git a/src/utils/hashes.rs b/src/utils/hashes.rs index 8a242d6..826ea18 100644 --- a/src/utils/hashes.rs +++ b/src/utils/hashes.rs @@ -1,5 +1,5 @@ -use crate::{errors::RustusError, RustusResult}; -use actix_web::http::header::HeaderValue; +use crate::errors::{RustusError, RustusResult}; +use axum::http::HeaderValue; use base64::Engine; use digest::Digest; @@ -64,7 +64,7 @@ pub fn verify_chunk_checksum(header: &HeaderValue, data: &[u8]) -> RustusResult< #[cfg(test)] mod tests { use super::{checksum_verify, verify_chunk_checksum}; - use actix_web::http::header::HeaderValue; + use axum::http::HeaderValue; #[test] fn test_success_checksum_verify() { diff --git a/src/utils/headers.rs b/src/utils/headers.rs index 5a2a268..a59f42a 100644 --- a/src/utils/headers.rs +++ b/src/utils/headers.rs @@ -1,115 +1,111 @@ -use std::str::FromStr; +use std::{collections::HashMap, hash::BuildHasherDefault, net::SocketAddr, str::FromStr}; -use actix_web::{ - http::header::{ContentDisposition, DispositionParam, DispositionType}, - HttpRequest, -}; +use axum::http::{HeaderMap, HeaderValue}; +use base64::{engine::general_purpose, Engine}; +use rustc_hash::{FxHashMap, FxHasher}; -/// Parse header's value. -/// -/// This function will try to parse -/// header's value to some type T. -/// -/// If header is not present or value -/// can't be parsed then it returns None. -pub fn parse_header(request: &HttpRequest, header_name: &str) -> Option { - request - .headers() - // Get header - .get(header_name) - .and_then(|value| - // Parsing it to string. - match value.to_str() { - Ok(header_str) => Some(header_str), - Err(_) => None, - }) - .and_then(|val| - // Parsing to type T. - match val.parse::() { - Ok(num) => Some(num), - Err(_) => None, - }) -} +static DISPOSITION_TYPE_INLINE: &str = "inline"; +static DISPOSITION_TYPE_ATTACHMENT: &str = "attachment"; -/// Check that header value satisfies some predicate. -/// -/// Passes header as a parameter to expr if header is present. -pub fn check_header(request: &HttpRequest, header_name: &str, expr: fn(&str) -> bool) -> bool { - request - .headers() - .get(header_name) - .and_then(|header_val| match header_val.to_str() { - Ok(val) => Some(expr(val)), - Err(_) => None, - }) - .unwrap_or(false) +pub trait HeaderMapExt { + fn parse(&self, name: &str) -> Option; + fn check(&self, name: &str, expr: fn(&str) -> bool) -> bool; + fn get_metadata(&self) -> Option>; + fn get_upload_parts(&self) -> Vec; + fn get_method_override(&self) -> Option; + fn generate_disposition(&mut self, filename: &str); + fn get_remote_ip(&self, socket_addr: &SocketAddr, proxy_enabled: bool) -> String; } -/// This function generates content disposition -/// based on file name. -pub fn generate_disposition(filename: &str) -> ContentDisposition { - let mime_type = mime_guess::from_path(filename).first_or_octet_stream(); - let disposition = match mime_type.type_() { - mime::IMAGE | mime::TEXT | mime::AUDIO | mime::VIDEO => DispositionType::Inline, - mime::APPLICATION => match mime_type.subtype() { - mime::JAVASCRIPT | mime::JSON => DispositionType::Inline, - name if name == "wasm" => DispositionType::Inline, - _ => DispositionType::Attachment, - }, - _ => DispositionType::Attachment, - }; - - ContentDisposition { - disposition, - parameters: vec![DispositionParam::Filename(String::from(filename))], +impl HeaderMapExt for HeaderMap { + fn parse(&self, name: &str) -> Option { + self.get(name)?.to_str().ok()?.parse().ok() } -} -#[cfg(test)] -mod tests { - use super::{check_header, parse_header}; - use actix_web::test::TestRequest; + fn check(&self, name: &str, expr: fn(&str) -> bool) -> bool { + self.get(name) + .and_then(|val| match val.to_str() { + Ok(val) => Some(expr(val)), + Err(_) => None, + }) + .unwrap_or(false) + } - #[actix_rt::test] - async fn test_parse_header_unknown_header() { - let request = TestRequest::get().to_http_request(); - let header = parse_header::(&request, "unknown"); - assert!(header.is_none()); + fn get_metadata(&self) -> Option> { + let meta_split = self.get("Upload-Metadata")?.to_str().ok()?.split(','); + let (shint, _) = meta_split.size_hint(); + let mut meta_map = + HashMap::with_capacity_and_hasher(shint, BuildHasherDefault::::default()); + for meta_entry in meta_split { + let mut entry_split = meta_entry.trim().split(' '); + let key = entry_split.next(); + let val = entry_split.next(); + if key.is_none() || val.is_none() { + continue; + } + let value = general_purpose::STANDARD + .decode(val.unwrap()) + .ok() + .and_then(|val| String::from_utf8(val).ok()); + if let Some(value) = value { + meta_map.insert(key.unwrap().to_string(), value); + } + } + Some(meta_map) } - #[actix_rt::test] - async fn test_parse_header_wrong_type() { - let request = TestRequest::get() - .insert_header(("test_header", String::from("test").as_bytes())) - .to_http_request(); - let header = parse_header::(&request, "test_header"); - assert!(header.is_none()); + fn get_upload_parts(&self) -> Vec { + self.get("Upload-Concat") + .and_then(|header| header.to_str().ok()) + .and_then(|header| header.strip_prefix("final;")) + .map(|urls| { + urls.split(' ') + .filter_map(|val: &str| val.trim().split('/').last().map(String::from)) + .filter(|val| val.trim() != "") + .collect() + }) + .unwrap_or_default() } - #[actix_rt::test] - async fn test_parse_header() { - let request = TestRequest::get() - .insert_header(("test_header", String::from("123").as_bytes())) - .to_http_request(); - let header = parse_header::(&request, "test_header"); - assert_eq!(header.unwrap(), 123); + fn get_method_override(&self) -> Option { + self.get("X-HTTP-Method-Override") + .and_then(|header| header.to_str().ok()) + .and_then(|header| header.trim().parse().ok()) } - #[actix_rt::test] - async fn test_check_header_unknown_header() { - let request = TestRequest::get().to_http_request(); - let check = check_header(&request, "unknown", |value| value == "1"); - assert_eq!(check, false); + fn generate_disposition(&mut self, filename: &str) { + let mime_type = mime_guess::from_path(filename).first_or_octet_stream(); + + let disposition = match mime_type.type_() { + mime::IMAGE | mime::TEXT | mime::AUDIO | mime::VIDEO => DISPOSITION_TYPE_INLINE, + mime::APPLICATION => match mime_type.subtype() { + mime::JAVASCRIPT | mime::JSON | mime::PDF => DISPOSITION_TYPE_INLINE, + name if name == "wasm" => DISPOSITION_TYPE_INLINE, + _ => DISPOSITION_TYPE_ATTACHMENT, + }, + _ => DISPOSITION_TYPE_ATTACHMENT, + }; + + format!("{disposition}; filename=\"{filename}\"") + .parse::() + .map(|val| { + self.insert(axum::http::header::CONTENT_DISPOSITION, val); + }) + .ok(); + mime_type + .to_string() + .parse::() + .map(|val| self.insert(axum::http::header::CONTENT_TYPE, val)) + .ok(); } - #[actix_rt::test] - async fn test_check_header() { - let request = TestRequest::get() - .insert_header(("test_header", "1")) - .to_http_request(); - let check = check_header(&request, "test_header", |value| value == "1"); - assert!(check); - let check = check_header(&request, "test_header", |value| value == "2"); - assert!(!check); + fn get_remote_ip(&self, socket_addr: &SocketAddr, proxy_enabled: bool) -> String { + if !proxy_enabled { + return socket_addr.ip().to_string(); + } + self.get("Forwarded") + .or_else(|| self.get("X-Forwarded-For")) + .and_then(|val| val.to_str().ok()) + .map_or_else(|| socket_addr.ip().to_string(), ToString::to_string) } } diff --git a/src/utils/lapin_pool.rs b/src/utils/lapin_pool.rs new file mode 100644 index 0000000..4a03c2e --- /dev/null +++ b/src/utils/lapin_pool.rs @@ -0,0 +1,63 @@ +use lapin::{ChannelState, ConnectionProperties, ConnectionState}; + +pub struct ConnnectionPool { + url: String, + properties: ConnectionProperties, +} + +pub struct ChannelPool { + pool: mobc::Pool, +} + +impl ChannelPool { + #[must_use] + pub fn new(pool: mobc::Pool) -> Self { + ChannelPool { pool } + } +} + +impl ConnnectionPool { + #[must_use] + pub fn new(url: String, properties: ConnectionProperties) -> Self { + ConnnectionPool { url, properties } + } +} + +#[async_trait::async_trait] +impl mobc::Manager for ConnnectionPool { + type Connection = lapin::Connection; + type Error = lapin::Error; + + async fn connect(&self) -> Result { + let conn = lapin::Connection::connect(&self.url, self.properties.clone()).await?; + Ok(conn) + } + + async fn check(&self, conn: Self::Connection) -> Result { + match conn.status().state() { + ConnectionState::Connected => Ok(conn), + other_state => Err(Self::Error::InvalidConnectionState(other_state)), + } + } +} + +#[async_trait::async_trait] +impl mobc::Manager for ChannelPool { + type Connection = lapin::Channel; + type Error = lapin::Error; + + async fn connect(&self) -> Result { + match self.pool.get().await { + Ok(conn) => conn.create_channel().await, + Err(mobc::Error::Inner(inner)) => Err(inner), + _ => Err(lapin::Error::ChannelsLimitReached), + } + } + + async fn check(&self, conn: Self::Connection) -> Result { + match conn.status().state() { + ChannelState::Connected => Ok(conn), + other_state => Err(Self::Error::InvalidChannelState(other_state)), + } + } +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 1b0e194..f4290c3 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -2,3 +2,5 @@ pub mod dir_struct; pub mod enums; pub mod hashes; pub mod headers; +pub mod lapin_pool; +pub mod result; diff --git a/src/utils/result.rs b/src/utils/result.rs new file mode 100644 index 0000000..09a60e8 --- /dev/null +++ b/src/utils/result.rs @@ -0,0 +1,53 @@ +use std::fmt::Display; + +pub trait MonadLogger { + #[must_use] + fn mlog(self, level: log::Level, msg: &str) -> Self; + #[must_use] + fn mlog_err(self, msg: &str) -> Self; + #[must_use] + fn mlog_warn(self, msg: &str) -> Self; + #[must_use] + fn mlog_dbg(self, msg: &str) -> Self; +} + +impl MonadLogger for Result { + fn mlog(self, level: log::Level, msg: &str) -> Self { + if let Err(err) = &self { + log::log!(level, "{msg}: {err}"); + } + self + } + + fn mlog_err(self, msg: &str) -> Self { + self.mlog(log::Level::Error, msg) + } + + fn mlog_warn(self, msg: &str) -> Self { + self.mlog(log::Level::Warn, msg) + } + + fn mlog_dbg(self, msg: &str) -> Self { + self.mlog(log::Level::Debug, msg) + } +} + +impl MonadLogger for Option { + fn mlog(self, level: log::Level, msg: &str) -> Self { + if self.is_none() { + log::log!(level, "{msg}: The value is None"); + } + self + } + fn mlog_err(self, msg: &str) -> Self { + self.mlog(log::Level::Error, msg) + } + + fn mlog_warn(self, msg: &str) -> Self { + self.mlog(log::Level::Warn, msg) + } + + fn mlog_dbg(self, msg: &str) -> Self { + self.mlog(log::Level::Debug, msg) + } +} From 2adbeb8d7343f5e5cddcd38252d8c9ce964dd74e Mon Sep 17 00:00:00 2001 From: Pavel Kirilin Date: Tue, 12 Dec 2023 21:51:00 +0100 Subject: [PATCH 2/9] Added sentry integration. (#147) --- Cargo.lock | 1083 +++++++++++------ Cargo.toml | 27 +- deploy/Dockerfile | 7 +- docs/configuration.md | 4 +- src/config.rs | 66 +- src/data_storage/impls/file_storage.rs | 139 +-- src/data_storage/impls/s3_hybrid.rs | 10 +- src/data_storage/mod.rs | 2 +- src/errors.rs | 9 +- src/info_storages/base.rs | 4 +- src/info_storages/impls/file_info_storage.rs | 7 +- src/info_storages/impls/redis_info_storage.rs | 2 +- src/info_storages/mod.rs | 2 +- src/main.rs | 63 +- src/notifiers/impls/amqp_notifier.rs | 5 +- src/notifiers/impls/dir_notifier.rs | 8 +- src/notifiers/impls/file_notifier.rs | 7 +- src/notifiers/impls/http_notifier.rs | 14 +- src/notifiers/manager.rs | 19 +- src/notifiers/mod.rs | 5 +- src/notifiers/serializer.rs | 4 +- src/server/cors.rs | 2 +- src/server/mod.rs | 137 ++- src/server/routes/create.rs | 42 +- src/server/routes/delete.rs | 23 +- src/server/routes/file_info.rs | 2 +- src/server/routes/get_file.rs | 2 +- src/server/routes/upload.rs | 32 +- src/state.rs | 2 +- src/utils/hashes.rs | 6 +- src/utils/lapin_pool.rs | 2 + src/utils/result.rs | 57 +- 32 files changed, 1112 insertions(+), 682 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 443b531..081cbbd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] @@ -28,6 +28,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + [[package]] name = "amq-protocol" version = "7.1.2" @@ -93,51 +102,50 @@ dependencies = [ [[package]] name = "anstream" -version = "0.3.2" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" +checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", - "is-terminal", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.1" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" +checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" [[package]] name = "anstyle-parse" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +checksum = "a3a318f1f38d2418400f8209655bfd825785afd25aa30bb7ba6cc792e4596748" dependencies = [ - "windows-sys", + "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "1.0.2" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c677ab05e09154296dd37acecd46420c17b9713e8366facafa8fc0885167cf4c" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" dependencies = [ "anstyle", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -148,23 +156,12 @@ checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" [[package]] name = "async-channel" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" -dependencies = [ - "concurrent-queue", - "event-listener 2.5.3", - "futures-core", -] - -[[package]] -name = "async-channel" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d37875bd9915b7d67c2f117ea2c30a0989874d0b2cb694fe25403c85763c0c9e" +checksum = "1ca33f4bc4ed1babef42cad36cc1f51fa88be00420404e5b1e80ab1b18f7678c" dependencies = [ "concurrent-queue", - "event-listener 3.1.0", + "event-listener 4.0.0", "event-listener-strategy", "futures-core", "pin-project-lite", @@ -172,30 +169,30 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0c4a4f319e45986f347ee47fef8bf5e81c9abc3f6f58dc2391439f30df65f0" +checksum = "17ae5ebefcc48e7452b4987947920dac9450be1110cadf34d1b8c116bdbaf97c" dependencies = [ - "async-lock 2.8.0", + "async-lock 3.2.0", "async-task", "concurrent-queue", "fastrand 2.0.1", - "futures-lite 1.13.0", + "futures-lite 2.1.0", "slab", ] [[package]] name = "async-global-executor" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776" +checksum = "9b4353121d5644cdf2beb5726ab752e79a8db1ebb52031770ec47db31d245526" dependencies = [ - "async-channel 1.9.0", + "async-channel", "async-executor", - "async-io", - "async-lock 2.8.0", + "async-io 2.2.1", + "async-lock 3.2.0", "blocking", - "futures-lite 1.13.0", + "futures-lite 2.1.0", "once_cell", ] @@ -223,13 +220,32 @@ dependencies = [ "futures-lite 1.13.0", "log", "parking", - "polling", + "polling 2.8.0", "rustix 0.37.27", "slab", - "socket2 0.4.9", + "socket2 0.4.10", "waker-fn", ] +[[package]] +name = "async-io" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6d3b15875ba253d1110c740755e246537483f152fa334f91abd7fe84c88b3ff" +dependencies = [ + "async-lock 3.2.0", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite 2.1.0", + "parking", + "polling 3.3.1", + "rustix 0.38.26", + "slab", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "async-lock" version = "2.8.0" @@ -241,11 +257,11 @@ dependencies = [ [[package]] name = "async-lock" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deb2ab2aa8a746e221ab826c73f48bc6ba41be6763f0855cb249eb6d154cf1d7" +checksum = "7125e42787d53db9dd54261812ef17e937c95a51e4d291373b670342fa44310c" dependencies = [ - "event-listener 3.1.0", + "event-listener 4.0.0", "event-listener-strategy", "pin-project-lite", ] @@ -256,7 +272,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a6012d170ad00de56c9ee354aef2e358359deb1ec504254e0e5a3774771de0e" dependencies = [ - "async-io", + "async-io 1.13.0", "async-trait", "futures-core", "reactor-trait", @@ -276,7 +292,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.39", ] [[package]] @@ -291,7 +307,7 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fcf00bc6d5abb29b5f97e3c61a90b6d3caa12f3faf897d4a3e3607c050a35a7" dependencies = [ - "http", + "http 0.2.11", "log", "native-tls", "serde", @@ -318,7 +334,7 @@ dependencies = [ "rust-ini", "serde", "thiserror", - "time 0.3.30", + "time", "url", ] @@ -333,17 +349,18 @@ dependencies = [ [[package]] name = "axum" -version = "0.6.16" -source = "git+https://github.com/tokio-rs/axum.git?rev=3ff45d9#3ff45d9c96b5192af6b6ec26eb2a2bfcddd00d7d" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "202651474fe73c62d9e0a56c6133f7a0ff1dc1c8cf7a5b03381af2a26553ac9d" dependencies = [ "async-trait", "axum-core", "bytes", "futures-util", - "http", - "http-body 0.4.5", - "hyper 0.14.27", - "hyper 1.0.0-rc.4", + "http 1.0.0", + "http-body 1.0.0", + "http-body-util", + "hyper 1.0.1", "hyper-util", "itoa", "matchit", @@ -359,21 +376,22 @@ dependencies = [ "sync_wrapper", "tokio", "tower", - "tower-hyper-http-body-compat", "tower-layer", "tower-service", ] [[package]] name = "axum-core" -version = "0.3.4" -source = "git+https://github.com/tokio-rs/axum.git?rev=3ff45d9#3ff45d9c96b5192af6b6ec26eb2a2bfcddd00d7d" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77cb22c689c44d4c07b0ab44ebc25d69d8ae601a2f28fb8d672d344178fa17aa" dependencies = [ "async-trait", "bytes", "futures-util", - "http", - "http-body 0.4.5", + "http 1.0.0", + "http-body 1.0.0", + "http-body-util", "mime", "pin-project-lite", "rustversion", @@ -384,9 +402,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", @@ -417,9 +435,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "block-buffer" @@ -445,21 +463,21 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118" dependencies = [ - "async-channel 2.1.0", - "async-lock 3.1.0", + "async-channel", + "async-lock 3.2.0", "async-task", "fastrand 2.0.1", "futures-io", - "futures-lite 2.0.1", + "futures-lite 2.1.0", "piper", "tracing", ] [[package]] name = "bumpalo" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "bytes" @@ -478,9 +496,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.82" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ "libc", ] @@ -493,18 +511,17 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.26" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "serde", - "time 0.1.45", "wasm-bindgen", - "winapi", + "windows-targets 0.48.5", ] [[package]] @@ -519,20 +536,19 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.21" +version = "4.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c27cdf28c0f604ba3f512b0c9a409f8de8513e4816705deb0498b627e7c3a3fd" +checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2" dependencies = [ "clap_builder", "clap_derive", - "once_cell", ] [[package]] name = "clap_builder" -version = "4.3.21" +version = "4.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08a9f1ab5e9f01a9b81f202e8562eb9a10de70abf9eaeac1be465c28b75aa4aa" +checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" dependencies = [ "anstream", "anstyle", @@ -542,21 +558,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.3.12" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.39", ] [[package]] name = "clap_lex" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "colorchoice" @@ -591,9 +607,9 @@ dependencies = [ [[package]] name = "concurrent-queue" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f057a694a54f12365049b0958a1685bb52d567f5593b355fbf685838e873d400" +checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" dependencies = [ "crossbeam-utils", ] @@ -606,9 +622,9 @@ checksum = "396de984970346b0d9e93d1415082923c679e5ae5c3ee3dcbd104f5610af126b" [[package]] name = "core-foundation" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", @@ -616,15 +632,15 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "cpufeatures" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" dependencies = [ "libc", ] @@ -648,11 +664,21 @@ dependencies = [ "typenum", ] +[[package]] +name = "debugid" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" +dependencies = [ + "serde", + "uuid", +] + [[package]] name = "deranged" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" +checksum = "8eb30d70a07a3b04884d2677f06bec33509dc67ca60d92949e5535352d3191dc" dependencies = [ "powerfmt", "serde", @@ -728,28 +754,23 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.39", ] [[package]] -name = "errno" -version = "0.3.2" +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys", -] +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] -name = "errno-dragonfly" -version = "0.1.2" +name = "errno" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ - "cc", "libc", + "windows-sys 0.52.0", ] [[package]] @@ -760,9 +781,9 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "event-listener" -version = "3.1.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2" +checksum = "770d968249b5d99410d61f5bf89057f3199a077a04d087092f58e7d10692baae" dependencies = [ "concurrent-queue", "parking", @@ -771,11 +792,11 @@ dependencies = [ [[package]] name = "event-listener-strategy" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96b852f1345da36d551b9473fa1e2b1eb5c5195585c6c018118bc92a8d91160" +checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" dependencies = [ - "event-listener 3.1.0", + "event-listener 4.0.0", "pin-project-lite", ] @@ -814,6 +835,18 @@ dependencies = [ "log", ] +[[package]] +name = "findshlibs" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40b9e59cd0f7e0806cca4be089683ecb6434e602038df21fe6bf6711b2f07f64" +dependencies = [ + "cc", + "lazy_static", + "libc", + "winapi", +] + [[package]] name = "flume" version = "0.10.14" @@ -858,9 +891,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] @@ -930,11 +963,14 @@ dependencies = [ [[package]] name = "futures-lite" -version = "2.0.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3831c2651acb5177cbd83943f3d9c8912c5ad03c76afcc0e9511ba568ec5ebb" +checksum = "aeee267a1883f7ebef3700f262d2d54de95dfaf38189015a74fdc4e0c7ad8143" dependencies = [ + "fastrand 2.0.1", "futures-core", + "futures-io", + "parking", "pin-project-lite", ] @@ -946,7 +982,7 @@ checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.39", ] [[package]] @@ -997,33 +1033,52 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", ] [[package]] name = "gimli" -version = "0.27.3" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "h2" -version = "0.3.21" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" +checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" dependencies = [ "bytes", "fnv", "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.11", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "h2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d308f63daf4181410c242d34c11f928dcb3aa105852019e043c9d1f4e4368a" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 1.0.0", "indexmap", "slab", "tokio", @@ -1040,6 +1095,12 @@ dependencies = [ "ahash", ] +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + [[package]] name = "heck" version = "0.4.1" @@ -1048,9 +1109,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] name = "hex" @@ -1067,6 +1128,17 @@ dependencies = [ "digest", ] +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + [[package]] name = "http" version = "0.2.11" @@ -1078,6 +1150,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.5" @@ -1085,25 +1168,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", - "http", + "http 0.2.11", "pin-project-lite", ] [[package]] name = "http-body" -version = "1.0.0-rc.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "951dfc2e32ac02d67c90c0d65bd27009a635dc9b381a2cc7d284ab01e3a0150d" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" dependencies = [ "bytes", - "http", + "http 1.0.0", ] [[package]] -name = "http-range-header" -version = "0.3.1" +name = "http-body-util" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" +checksum = "41cb79eb393015dadd30fc252023adb0b2400a0caee0fa2a077e6e21a551e840" +dependencies = [ + "bytes", + "futures-util", + "http 1.0.0", + "http-body 1.0.0", + "pin-project-lite", +] [[package]] name = "httparse" @@ -1127,14 +1217,14 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2", - "http", + "h2 0.3.22", + "http 0.2.11", "http-body 0.4.5", "httparse", "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.9", + "socket2 0.4.10", "tokio", "tower-service", "tracing", @@ -1143,23 +1233,21 @@ dependencies = [ [[package]] name = "hyper" -version = "1.0.0-rc.4" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d280a71f348bcc670fc55b02b63c53a04ac0bf2daff2980795aeaf53edae10e6" +checksum = "403f9214f3e703236b221f1a9cd88ec8b4adfa5296de01ab96216361f4692f56" dependencies = [ "bytes", "futures-channel", "futures-util", - "h2", - "http", - "http-body 1.0.0-rc.2", + "h2 0.4.0", + "http 1.0.0", + "http-body 1.0.0", "httparse", "httpdate", "itoa", "pin-project-lite", "tokio", - "tracing", - "want", ] [[package]] @@ -1177,18 +1265,18 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.0.0" -source = "git+https://github.com/hyperium/hyper-util?rev=d97181a#d97181a278d9c59f1d7f2713732e400440861216" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ca339002caeb0d159cc6e023dff48e199f081e42fa039895c7c6f38b37f2e9d" dependencies = [ "bytes", "futures-channel", "futures-util", - "http", - "http-body 1.0.0-rc.2", - "hyper 1.0.0-rc.4", - "once_cell", + "http 1.0.0", + "http-body 1.0.0", + "hyper 1.0.1", "pin-project-lite", - "socket2 0.5.3", + "socket2 0.5.5", "tokio", "tower", "tower-service", @@ -1197,16 +1285,16 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.57" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" +checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows", + "windows-core", ] [[package]] @@ -1220,9 +1308,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -1230,12 +1318,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.3" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ - "autocfg", - "hashbrown", + "equivalent", + "hashbrown 0.14.3", ] [[package]] @@ -1265,7 +1353,7 @@ checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ "hermit-abi", "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1281,8 +1369,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", - "rustix 0.38.8", - "windows-sys", + "rustix 0.38.26", + "windows-sys 0.48.0", ] [[package]] @@ -1293,9 +1381,9 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" dependencies = [ "wasm-bindgen", ] @@ -1330,19 +1418,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" - -[[package]] -name = "libmimalloc-sys" -version = "0.1.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3979b5c37ece694f1f5e51e7ecc871fdb0f517ed04ee45f88d15d6d553cb9664" -dependencies = [ - "cc", - "libc", -] +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "libredox" @@ -1350,9 +1428,9 @@ version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "libc", - "redox_syscall 0.4.1", + "redox_syscall", ] [[package]] @@ -1363,9 +1441,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.4.5" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" [[package]] name = "lock_api" @@ -1383,11 +1461,17 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + [[package]] name = "matchit" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed1202b2a6f884ae56f04cff409ab315c5ce26b5e58d7412e484f01fd52f52ef" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" [[package]] name = "maybe-async" @@ -1418,9 +1502,9 @@ checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "metrics" @@ -1443,15 +1527,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "mimalloc" -version = "0.1.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa01922b5ea280a911e323e4d2fd24b7fe5cc4042e0d2cda3c40775cdc4bdc9c" -dependencies = [ - "libmimalloc-sys", -] - [[package]] name = "mime" version = "0.3.17" @@ -1494,13 +1569,13 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", + "wasi", + "windows-sys 0.48.0", ] [[package]] @@ -1562,9 +1637,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", ] @@ -1581,26 +1656,26 @@ dependencies = [ [[package]] name = "object" -version = "0.31.1" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "openssl" -version = "0.10.59" +version = "0.10.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a257ad03cd8fb16ad4172fedf8094451e1af1c4b70097636ef2eac9a5f0cc33" +checksum = "6b8419dc8cc6d866deb801274bba2e6f8f6108c1bb7fcc10ee5ab864931dbb45" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "cfg-if", "foreign-types", "libc", @@ -1617,7 +1692,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.39", ] [[package]] @@ -1628,9 +1703,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.95" +version = "0.9.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40a4130519a360279579c2053038317e40eff64d13fd3f004f9e1b72b8a6aaf9" +checksum = "c3eaad34cdd97d81de97964fc7f29e2d104f483840d906ef56daa1912338460b" dependencies = [ "cc", "libc", @@ -1645,7 +1720,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a" dependencies = [ "dlv-list", - "hashbrown", + "hashbrown 0.12.3", +] + +[[package]] +name = "os_info" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "006e42d5b888366f1880eda20371fedde764ed2213dc8496f49622fa0c99cd5e" +dependencies = [ + "log", + "serde", + "winapi", ] [[package]] @@ -1695,16 +1781,16 @@ checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.4.1", + "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project" @@ -1723,14 +1809,14 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.39", ] [[package]] name = "pin-project-lite" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -1780,7 +1866,21 @@ dependencies = [ "libc", "log", "pin-project-lite", - "windows-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "polling" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf63fa624ab313c11656b4cda960bfc46c410187ad493c41f6ba2d8c1e991c9e" +dependencies = [ + "cfg-if", + "concurrent-queue", + "pin-project-lite", + "rustix 0.38.26", + "tracing", + "windows-sys 0.52.0", ] [[package]] @@ -1797,9 +1897,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" dependencies = [ "unicode-ident", ] @@ -1816,9 +1916,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.32" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -1875,9 +1975,9 @@ dependencies = [ [[package]] name = "redis" -version = "0.23.3" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f49cdc0bb3f412bf8e7d1bd90fe1d9eb10bc5c399ba90973c14662a27b3f8ba" +checksum = "c580d9cbbe1d1b479e8d67cf9daf6a62c957e6846048408b80b43ac3f6af84cd" dependencies = [ "arc-swap", "async-trait", @@ -1890,22 +1990,13 @@ dependencies = [ "pin-project-lite", "ryu", "sha1_smol", - "socket2 0.4.9", + "socket2 0.4.10", "tokio", "tokio-retry", "tokio-util", "url", ] -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.4.1" @@ -1926,6 +2017,35 @@ dependencies = [ "thiserror", ] +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + [[package]] name = "reqwest" version = "0.11.22" @@ -1937,8 +2057,8 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2", - "http", + "h2 0.3.22", + "http 0.2.11", "http-body 0.4.5", "hyper 0.14.27", "hyper-tls", @@ -1968,16 +2088,16 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.3" +version = "0.17.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babe80d5c16becf6594aa32ad2be8fe08498e7ae60b77de8df700e67f191d7e" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" dependencies = [ "cc", "getrandom", "libc", "spin", "untrusted", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2005,7 +2125,7 @@ dependencies = [ "futures", "hex", "hmac", - "http", + "http 0.2.11", "log", "maybe-async", "md5", @@ -2017,7 +2137,7 @@ dependencies = [ "serde_derive", "sha2", "thiserror", - "time 0.3.30", + "time", "tokio", "tokio-stream", "url", @@ -2035,6 +2155,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.37.27" @@ -2046,20 +2175,20 @@ dependencies = [ "io-lifetimes", "libc", "linux-raw-sys 0.3.8", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "rustix" -version = "0.38.8" +version = "0.38.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f" +checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "errno", "libc", - "linux-raw-sys 0.4.5", - "windows-sys", + "linux-raw-sys 0.4.12", + "windows-sys 0.52.0", ] [[package]] @@ -2131,11 +2260,9 @@ dependencies = [ "enum_dispatch", "fern", "futures", - "http", "lapin", "log", "md-5", - "mimalloc", "mime", "mime_guess", "mobc", @@ -2143,16 +2270,22 @@ dependencies = [ "reqwest", "rust-s3", "rustc-hash", + "sentry", + "sentry-tower", + "sentry-tracing", "serde", "serde_json", "sha1", "sha2", "strum", "thiserror", + "tikv-jemallocator", "tokio", "tokio-util", "tower", "tower-http", + "tracing", + "tracing-subscriber", "uuid", "wildmatch", ] @@ -2192,7 +2325,7 @@ version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2234,24 +2367,153 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" + +[[package]] +name = "sentry" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b596ee5f4e76638de6063ca96fd3d923675416461fc7f1b77406dc2f32d1979" +dependencies = [ + "httpdate", + "native-tls", + "reqwest", + "sentry-backtrace", + "sentry-contexts", + "sentry-core", + "sentry-debug-images", + "sentry-panic", + "sentry-tracing", + "tokio", + "ureq", +] + +[[package]] +name = "sentry-backtrace" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6510a97162c288989a6310766bcadfc83ec98ad73121674463b055c42189e85" +dependencies = [ + "backtrace", + "once_cell", + "regex", + "sentry-core", +] + +[[package]] +name = "sentry-contexts" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e2552a4a578aade01bd44691e6805c32bac34fc918f1675739fbbf2add8460" +dependencies = [ + "hostname", + "libc", + "os_info", + "rustc_version", + "sentry-core", + "uname", +] + +[[package]] +name = "sentry-core" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebb7a6ad833035f6b36db3e61e450643eec8a3c5f2839b8e41c74a73e57c6bae" +dependencies = [ + "once_cell", + "rand", + "sentry-types", + "serde", + "serde_json", +] + +[[package]] +name = "sentry-debug-images" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bcd02214397892a3ec25372cc68c210d858f39314535f5d640bdf41294fd441" +dependencies = [ + "findshlibs", + "once_cell", + "sentry-core", +] + +[[package]] +name = "sentry-panic" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0866e2ba7615fe37e0e485f2373bf9dabbb255f82637b5fe47902095790bbbc9" +dependencies = [ + "sentry-backtrace", + "sentry-core", +] + +[[package]] +name = "sentry-tower" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e275f07e9e7d9cf3b85130ab6893a9790c3ab2d8fedca29215aeafad0539c4f4" +dependencies = [ + "axum", + "http 1.0.0", + "pin-project", + "sentry-core", + "tower-layer", + "tower-service", + "url", +] + +[[package]] +name = "sentry-tracing" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53ef38653386354058f30b3c6d0bf764c59ee6270cd769ac4620a2d2fd60c8fe" +dependencies = [ + "sentry-backtrace", + "sentry-core", + "tracing-core", + "tracing-subscriber", +] + +[[package]] +name = "sentry-types" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26342e85c6b3332273b820d5be6b93027fe991ded23a2aa6fb88a5a28c845c40" +dependencies = [ + "debugid", + "hex", + "rand", + "serde", + "serde_json", + "thiserror", + "time", + "url", + "uuid", +] + [[package]] name = "serde" -version = "1.0.192" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.192" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.39", ] [[package]] @@ -2361,9 +2623,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", "winapi", @@ -2371,12 +2633,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.3" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2419,7 +2681,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.28", + "syn 2.0.39", ] [[package]] @@ -2441,9 +2703,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.28" +version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", @@ -2491,15 +2753,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.8.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if", "fastrand 2.0.1", - "redox_syscall 0.3.5", - "rustix 0.38.8", - "windows-sys", + "redox_syscall", + "rustix 0.38.26", + "windows-sys 0.48.0", ] [[package]] @@ -2519,7 +2781,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.39", ] [[package]] @@ -2533,14 +2795,23 @@ dependencies = [ ] [[package]] -name = "time" -version = "0.1.45" +name = "tikv-jemalloc-sys" +version = "0.5.4+5.3.0-patched" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9402443cb8fd499b6f327e40565234ff34dbda27460c5b47db0db77443dd85d1" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "tikv-jemallocator" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +checksum = "965fe0c26be5c56c94e38ba547249074803efd52adfb66de62107d95aab3eaca" dependencies = [ "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", + "tikv-jemalloc-sys", ] [[package]] @@ -2589,9 +2860,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.31.0" +version = "1.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40de3a2ba249dcb097e01be5e67a5ff53cf250397715a071a81543e8a832a920" +checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" dependencies = [ "backtrace", "bytes", @@ -2601,20 +2872,20 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.3", + "socket2 0.5.5", "tokio-macros", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.39", ] [[package]] @@ -2681,35 +2952,20 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.4.4" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" +checksum = "09e12e6351354851911bdf8c2b8f2ab15050c567d70a8b9a37ae7b8301a4080d" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "bytes", - "futures-core", "futures-util", - "http", - "http-body 0.4.5", - "http-range-header", + "http 1.0.0", + "http-body 1.0.0", + "http-body-util", "pin-project-lite", "tower-layer", "tower-service", -] - -[[package]] -name = "tower-hyper-http-body-compat" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7ea3e622710ee44a8255baa6fcb2a34d67450e2ffb48e5e58d5a7bd6ff55a21" -dependencies = [ - "http", - "http-body 0.4.5", - "http-body 1.0.0-rc.2", - "hyper 1.0.0-rc.4", - "pin-project-lite", - "tower", - "tower-service", + "tracing", ] [[package]] @@ -2726,11 +2982,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "log", "pin-project-lite", "tracing-attributes", @@ -2745,14 +3000,14 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.39", ] [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", "valuable", @@ -2776,18 +3031,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "nu-ansi-term", + "parking_lot", "sharded-slab", "smallvec", "thread_local", + "time", "tracing-core", "tracing-log", ] [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typenum" @@ -2795,6 +3052,15 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "uname" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b72f89f0ca32e4db1c04e2a72f5345d59796d4866a1ee0609084569f73683dc8" +dependencies = [ + "libc", +] + [[package]] name = "unicase" version = "2.7.0" @@ -2806,15 +3072,15 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" @@ -2831,15 +3097,29 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "ureq" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cdd25c339e200129fe4de81451814e5228c9b771d57378817d6117cc2b3f97" +dependencies = [ + "base64 0.21.5", + "log", + "native-tls", + "once_cell", + "url", +] + [[package]] name = "url" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] [[package]] @@ -2850,11 +3130,12 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.5.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc" +checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" dependencies = [ "getrandom", + "serde", ] [[package]] @@ -2890,12 +3171,6 @@ dependencies = [ "try-lock", ] -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -2904,9 +3179,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2914,24 +3189,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.39", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" dependencies = [ "cfg-if", "js-sys", @@ -2941,9 +3216,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2951,22 +3226,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.39", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" [[package]] name = "wasm-streams" @@ -2983,9 +3258,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" dependencies = [ "js-sys", "wasm-bindgen", @@ -3020,12 +3295,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows" -version = "0.48.0" +name = "windows-core" +version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -3034,65 +3309,131 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winreg" @@ -3101,7 +3442,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ "cfg-if", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 534287e..639fc25 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ path = "src/main.rs" [dependencies] async-trait = "0.1.74" -axum = { git = "https://github.com/tokio-rs/axum.git", rev = "3ff45d9" } +axum = { version = "0.7.1" } base64 = "0.21.5" bytes = "1.5.0" chrono = { version = "0.4.26", features = ["serde"] } @@ -25,17 +25,16 @@ enum_dispatch = "0.3.12" fern = { version = "0.6.2", features = ["colored", "chrono"] } futures = "0.3.29" log = "0.4.20" -mimalloc = "0.1.39" mime = "0.3.17" mime_guess = "2.0.4" mobc = "0.8.3" -redis = { version = "0.23.3", features = ["tokio-comp", "connection-manager"] } +redis = { version = "0.24.0", features = ["tokio-comp", "connection-manager"] } rustc-hash = "1.1.0" serde = { version = "1.0.192", features = ["derive"] } serde_json = "1.0.108" strum = { version = "0.25.0", features = ["derive"] } thiserror = "1.0.50" -tokio = { version = "1.31.0", features = ["full"] } +tokio = { version = "1.31.0", features = ["full", "bytes"] } tokio-util = { version = "0.7.10", features = ["io"] } uuid = { version = "1.5.0", features = ["v4"] } rust-s3 = "^0.33" @@ -47,10 +46,26 @@ md-5 = "^0.10.1" digest = "^0.10.1" reqwest = "0.11.22" lapin = "2.3.1" -tower-http = { version = "0.4.4", features = ["cors"] } -http = "^0.2" +tower-http = { version = "0.5.0", features = ["cors", "trace"] } wildmatch = "2.1.1" +tracing = "0.1.40" +sentry = "0.32.0" +sentry-tracing = "0.32.0" +sentry-tower = { version = "0.32.0", features = [ + "http", + "axum", + "axum-matched-path", +] } +tracing-subscriber = { version = "0.3.18", features = [ + "smallvec", + "parking_lot", + "time", +] } +[target.'cfg(not(target_env = "msvc"))'.dependencies] +tikv-jemallocator = { version = "0.5.4", features = [ + "background_threads_runtime_support", +] } [profile.release] opt-level = 3 diff --git a/deploy/Dockerfile b/deploy/Dockerfile index ceaf08b..c765847 100644 --- a/deploy/Dockerfile +++ b/deploy/Dockerfile @@ -4,11 +4,16 @@ WORKDIR /app COPY Cargo.toml Cargo.lock ./ COPY src ./src COPY imgs ./imgs + +ENV JEMALLOC_SYS_WITH_MALLOC_CONF="background_thread:true,metadata_thp:always,tcache:false,dirty_decay_ms:0,muzzy_decay_ms:0,abort_conf:true" RUN cargo build --release --bin rustus -FROM debian:bullseye-20211201-slim AS base +FROM debian:bullseye-20231120-slim AS base COPY --from=builder /app/target/release/rustus /usr/local/bin/ +RUN apt update && apt install -y libssl-dev ca-certificates libjemalloc-dev && apt clean + +VOLUME [ "/data" ] ENTRYPOINT ["/usr/local/bin/rustus"] diff --git a/docs/configuration.md b/docs/configuration.md index 7254b3c..4079a27 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -74,7 +74,8 @@ please provide sentry-dsn to rustus. ``` bash rustus --sentry-dsn "https://user@sentry-instance.com/11" \ - --sentry-sample-rate 1.0 + --sentry-sample-rate 1.0 \ + --sentry-environment "dev" ``` === "ENV" @@ -82,6 +83,7 @@ please provide sentry-dsn to rustus. ``` bash export RUSTUS_SENTRY_DSN="https://user@sentry-instance.com/11" export RUSTUS_SENTRY_SAMPLE_RATE="1.0" + export RUSTUS_SENTRY_ENVIRONMENT="dev" rustus ``` diff --git a/src/config.rs b/src/config.rs index 0c1d79d..52ad974 100644 --- a/src/config.rs +++ b/src/config.rs @@ -276,6 +276,58 @@ pub struct NotificationConfig { pub amqp_hook_opts: AMQPHooksOptions, } +#[derive(Parser, Clone, Debug)] +pub struct SentryConfig { + /// Sentry DSN. + /// + /// Link to sentry project, which is used to send events to. + #[arg(name = "sentry-dsn", long, env = "RUSTUS_SENTRY_DSN")] + pub dsn: Option, + + /// Sentry sample rate. + /// + /// This option is used to set how often events are sent to sentry. + /// The default value is 1.0, which means that all events are sent. + #[arg( + name = "sentry-sample-rate", + long, + default_value = "1.0", + env = "RUSTUS_SENTRY_SAMPLE_RATE" + )] + pub sample_rate: Option, + + /// Sentry traces sample rate. + /// + /// This option is used to set how often traces are sent to sentry. + /// Traces are used to track performance, so this option might not be + /// useful for regular users. + #[arg( + name = "sentry-traces-sample-rate", + long, + env = "RUSTUS_SENTRY_TRACES_SAMPLE_RATE" + )] + pub traces_sample_rate: Option, + + /// Sentry environment. + /// + /// This option is used to set environment for sentry. + #[arg(name = "sentry-environment", long, env = "RUSTUS_SENTRY_ENVIRONMENT")] + pub environment: Option, + + /// DEvelopment option for sentry. + /// + /// This option enables logging of sentry events, + /// which is useful for debugging. But it is not recommended + /// to enable this option in production. + #[arg( + name = "sentry-debug", + long, + default_value = "false", + env = "RUSTUS_SENTRY_DEBUG" + )] + pub debug: bool, +} + #[derive(Parser, Clone, Debug)] #[command(author, version, about, long_about = None)] #[allow(clippy::struct_excessive_bools)] @@ -290,7 +342,7 @@ pub struct Config { /// Log level for the server. #[arg(long, default_value = "INFO", env = "RUSTUS_LOG_LEVEL")] - pub log_level: log::LevelFilter, + pub log_level: tracing::Level, /// Number of worker threads for the server. /// @@ -302,6 +354,15 @@ pub struct Config { #[arg(long, default_value = "/files", env = "RUSTUS_PREFIX")] pub url: String, + /// Option to disable access logging completely. + /// Useful when using sentry, to not spam with logs, + /// because sentry might incorrectly capture some access logs, + /// which is annoying. + /// + /// By default it is disabled. + #[arg(long, default_value = "false", env = "RUSTUS_NO_ACCESS")] + pub no_access: bool, + /// Disable access log for health endpoint. /// By default it is enabled. #[arg(long, env = "RUSTUS_DISABLE_HEALTH_ACCESS_LOG")] @@ -374,6 +435,9 @@ pub struct Config { #[command(flatten)] pub notification_config: NotificationConfig, + + #[command(flatten)] + pub sentry_config: SentryConfig, } impl Config { diff --git a/src/data_storage/impls/file_storage.rs b/src/data_storage/impls/file_storage.rs index 55ff30a..0515dbc 100644 --- a/src/data_storage/impls/file_storage.rs +++ b/src/data_storage/impls/file_storage.rs @@ -1,12 +1,10 @@ -use std::{io::Write, path::PathBuf}; +use std::path::PathBuf; + +use tokio::io::AsyncWriteExt; use axum::response::{IntoResponse, Response}; use bytes::Bytes; -use log::error; -use std::{ - fs::{remove_file, DirBuilder, OpenOptions}, - io::{copy, BufReader, BufWriter}, -}; +use std::fs::DirBuilder; use crate::{ data_storage::base::Storage, @@ -15,7 +13,7 @@ use crate::{ utils::{dir_struct::substr_now, headers::HeaderMapExt}, }; -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct FileStorage { data_dir: PathBuf, dir_struct: String, @@ -82,45 +80,42 @@ impl Storage for FileStorage { Ok(resp) } - async fn add_bytes(&self, file_info: &FileInfo, bytes: Bytes) -> RustusResult<()> { + async fn add_bytes(&self, file_info: &FileInfo, mut bytes: Bytes) -> RustusResult<()> { // In normal situation this `if` statement is not // gonna be called, but what if it is ... - if file_info.path.is_none() { + let Some(path) = &file_info.path else { return Err(RustusError::FileNotFound); + }; + let file = tokio::fs::OpenOptions::new() + .write(true) + .append(true) + .create(false) + .read(false) + .truncate(false) + .open(path.as_str()) + .await?; + let mut writer = tokio::io::BufWriter::new(file); + writer.write_all(&bytes).await?; + writer.flush().await?; + if self.force_fsync { + writer.get_ref().sync_data().await?; } - let path = file_info.path.as_ref().unwrap().clone(); - let force_sync = self.force_fsync; - tokio::task::spawn_blocking(move || { - // Opening file in w+a mode. - // It means that we're going to append some - // bytes to the end of a file. - let file = OpenOptions::new() - .write(true) - .append(true) - .create(false) - .read(false) - .truncate(false) - .open(path.as_str())?; - let mut writer = BufWriter::new(file); - writer.write_all(bytes.as_ref())?; - writer.flush()?; - if force_sync { - writer.get_ref().sync_data()?; - } - Ok(()) - }) - .await? + writer.into_inner().shutdown().await?; + bytes.clear(); + Ok(()) } async fn create_file(&self, file_info: &FileInfo) -> RustusResult { // New path to file. let file_path = self.data_file_path(file_info.id.as_str())?; - OpenOptions::new() + let mut opened = tokio::fs::OpenOptions::new() .create(true) .write(true) .truncate(true) .create_new(true) - .open(file_path.as_path())?; + .open(file_path.as_path()) + .await?; + opened.shutdown().await?; Ok(file_path.display().to_string()) } @@ -129,54 +124,48 @@ impl Storage for FileStorage { file_info: &FileInfo, parts_info: Vec, ) -> RustusResult<()> { - let force_fsync = self.force_fsync; - if file_info.path.is_none() { + let Some(path) = &file_info.path else { return Err(RustusError::FileNotFound); - } - let path = file_info.path.as_ref().unwrap().clone(); - tokio::task::spawn_blocking(move || { - let file = OpenOptions::new() - .write(true) - .append(true) - .create(true) - .open(path)?; - let mut writer = BufWriter::new(file); - for part in parts_info { - if part.path.is_none() { - return Err(RustusError::FileNotFound); - } - let part_file = OpenOptions::new() - .read(true) - .open(part.path.as_ref().unwrap())?; - let mut reader = BufReader::new(part_file); - copy(&mut reader, &mut writer)?; - } - writer.flush()?; - if force_fsync { - writer.get_ref().sync_data()?; + }; + let file = tokio::fs::OpenOptions::new() + .write(true) + .append(true) + .create(true) + .open(path) + .await?; + let mut writer = tokio::io::BufWriter::new(file); + for part in parts_info { + if part.path.is_none() { + return Err(RustusError::FileNotFound); } - Ok(()) - }) - .await? + let part_file = tokio::fs::OpenOptions::new() + .read(true) + .open(part.path.as_ref().unwrap()) + .await?; + let mut reader = tokio::io::BufReader::new(part_file); + tokio::io::copy_buf(&mut reader, &mut writer).await?; + reader.shutdown().await?; + } + writer.flush().await?; + if self.force_fsync { + writer.get_ref().sync_data().await?; + } + writer.into_inner().shutdown().await?; + Ok(()) } async fn remove_file(&self, file_info: &FileInfo) -> RustusResult<()> { - let info = file_info.clone(); - if info.path.is_none() { + let Some(path) = &file_info.path else { + return Err(RustusError::FileNotFound); + }; + let data_path = PathBuf::from(path); + if !data_path.exists() { return Err(RustusError::FileNotFound); } - tokio::task::spawn_blocking(move || { - // Let's remove the file itself. - let data_path = PathBuf::from(info.path.as_ref().unwrap().clone()); - if !data_path.exists() { - return Err(RustusError::FileNotFound); - } - remove_file(data_path).map_err(|err| { - error!("{:?}", err); - RustusError::UnableToRemove(info.id.clone()) - })?; - Ok(()) - }) - .await? + tokio::fs::remove_file(data_path).await.map_err(|err| { + tracing::error!("{:?}", err); + RustusError::UnableToRemove(String::from(path.as_str())) + })?; + Ok(()) } } diff --git a/src/data_storage/impls/s3_hybrid.rs b/src/data_storage/impls/s3_hybrid.rs index d6e7821..fed2673 100644 --- a/src/data_storage/impls/s3_hybrid.rs +++ b/src/data_storage/impls/s3_hybrid.rs @@ -26,7 +26,7 @@ use super::file_storage::FileStorage; /// complete, it uploads file to S3. /// /// It's not intended to use this storage for large files. -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct S3HybridStorage { bucket: Bucket, local_storage: FileStorage, @@ -76,9 +76,9 @@ impl S3HybridStorage { let headers_map = serde_json::from_str::>(raw_s3_headers) .mlog_err("Cannot parse s3 headers. Please provide valid JSON object.") .unwrap(); - log::debug!("Found extra s3 headers."); + tracing::debug!("Found extra s3 headers."); for (key, value) in &headers_map { - log::debug!("Adding header `{key}` with value `{value}`."); + tracing::debug!("Adding header `{key}` with value `{value}`."); bucket.add_header(key, value); } } @@ -103,7 +103,7 @@ impl S3HybridStorage { return Err(RustusError::UnableToWrite("Cannot get upload path.".into())); } let s3_path = self.get_s3_key(file_info); - log::debug!( + tracing::debug!( "Starting uploading {} to S3 with key `{}`", file_info.id, s3_path, @@ -133,7 +133,7 @@ impl Storage for S3HybridStorage { async fn get_contents(&self, file_info: &FileInfo) -> RustusResult { if file_info.length != Some(file_info.offset) { - log::debug!("File isn't uploaded. Returning from local storage."); + tracing::debug!("File isn't uploaded. Returning from local storage."); return self.local_storage.get_contents(file_info).await; } let key = self.get_s3_key(file_info); diff --git a/src/data_storage/mod.rs b/src/data_storage/mod.rs index 6007bcd..712dac5 100644 --- a/src/data_storage/mod.rs +++ b/src/data_storage/mod.rs @@ -21,7 +21,7 @@ pub enum AvailableStorages { from_str!(AvailableStorages, "storages"); -#[derive(Clone)] +#[derive(Clone, Debug)] pub enum DataStorageImpl { File(FileStorage), S3Hybrid(S3HybridStorage), diff --git a/src/errors.rs b/src/errors.rs index 7fdd2b7..8b2c2e8 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,7 +1,6 @@ use std::io::{Error, ErrorKind}; use axum::response::IntoResponse; -use log::error; use axum::http::StatusCode; @@ -45,8 +44,6 @@ pub enum RustusError { HttpRequestError(#[from] reqwest::Error), #[error("Hook invocation failed. Reason: {0}")] HookError(String), - #[error("Unable to configure logging: {0}")] - LogConfigError(#[from] log::SetLoggerError), #[error("AMQP error: {0}")] AMQPError(#[from] lapin::Error), #[error("AMQP pooling error error: {0}")] @@ -61,7 +58,7 @@ pub enum RustusError { WrongChecksum, #[error("The header value is incorrect")] WrongHeaderValue, - #[error("HTTP hook error. Returned status: {0}, Response text: {1}")] + #[error("HTTP hook error. Returned status: {0}.")] HTTPHookError(u16, String, Option), #[error("Found S3 error: {0}")] S3Error(#[from] s3::error::S3Error), @@ -100,8 +97,10 @@ impl RustusError { impl IntoResponse for RustusError { fn into_response(self) -> axum::response::Response { - log::error!("{self}"); let status_code = self.get_status_code(); + if status_code != StatusCode::NOT_FOUND { + tracing::error!(err=?self, "{self}"); + } match self { RustusError::HTTPHookError(_, proxy_response, content_type) => { axum::response::IntoResponse::into_response(( diff --git a/src/info_storages/base.rs b/src/info_storages/base.rs index 3e480da..c285f61 100644 --- a/src/info_storages/base.rs +++ b/src/info_storages/base.rs @@ -1,9 +1,11 @@ +use std::fmt::Debug; + use crate::{errors::RustusResult, models::file_info::FileInfo}; /// Trait for every info storage. /// /// This trait defines required functions /// for building your own info storage. -pub trait InfoStorage { +pub trait InfoStorage: Clone + Debug { /// Prepare storage for storing files. /// /// In this function you can prepare diff --git a/src/info_storages/impls/file_info_storage.rs b/src/info_storages/impls/file_info_storage.rs index 8d44c61..d7fb55a 100644 --- a/src/info_storages/impls/file_info_storage.rs +++ b/src/info_storages/impls/file_info_storage.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use tokio::fs::DirBuilder; +use tokio::{fs::DirBuilder, io::AsyncWriteExt}; use crate::{ errors::{RustusError, RustusResult}, @@ -9,7 +9,7 @@ use crate::{ utils::result::MonadLogger, }; -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct FileInfoStorage { info_dir: PathBuf, } @@ -46,6 +46,8 @@ impl InfoStorage for FileInfoStorage { let str_data = serde_json::to_string(file_info)?; let mut writer = tokio::io::BufWriter::new(file); tokio::io::copy_buf(&mut str_data.as_bytes(), &mut writer).await?; + writer.flush().await?; + writer.shutdown().await?; Ok(()) } @@ -60,6 +62,7 @@ impl InfoStorage for FileInfoStorage { tokio::io::copy_buf(&mut reader, &mut contents) .await .mlog_dbg("Cannot write bytes")?; + reader.shutdown().await?; Ok(serde_json::from_slice::(contents.as_slice())?) } diff --git a/src/info_storages/impls/redis_info_storage.rs b/src/info_storages/impls/redis_info_storage.rs index 8d351f6..20c5926 100644 --- a/src/info_storages/impls/redis_info_storage.rs +++ b/src/info_storages/impls/redis_info_storage.rs @@ -35,7 +35,7 @@ impl Manager for RedisConnectionManager { } } -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct RedisStorage { pool: Pool, expiration: Option, diff --git a/src/info_storages/mod.rs b/src/info_storages/mod.rs index 8015583..fe20da1 100644 --- a/src/info_storages/mod.rs +++ b/src/info_storages/mod.rs @@ -17,7 +17,7 @@ pub enum AvailableInfoStorages { from_str!(AvailableInfoStorages, "info storage"); -#[derive(Clone)] +#[derive(Clone, Debug)] pub enum InfoStorageImpl { Redis(RedisStorage), File(FileInfoStorage), diff --git a/src/main.rs b/src/main.rs index 5abed8f..90fee77 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,8 @@ #![allow(async_fn_in_trait)] +use std::{borrow::Cow, str::FromStr}; + use errors::RustusResult; -use fern::{ - colors::{Color, ColoredLevelConfig}, - Dispatch, -}; -use log::LevelFilter; pub mod config; pub mod data_storage; @@ -18,34 +15,10 @@ pub mod server; pub mod state; pub mod utils; +#[cfg(not(target_env = "msvc"))] #[global_allocator] -static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; - -#[cfg_attr(coverage, no_coverage)] -fn setup_logging(app_config: &config::Config) -> RustusResult<()> { - let colors = ColoredLevelConfig::new() - // use builder methods - .info(Color::Green) - .warn(Color::Yellow) - .debug(Color::BrightCyan) - .error(Color::BrightRed) - .trace(Color::Blue); +static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; - Dispatch::new() - .level(app_config.log_level) - .level_for("rbatis", LevelFilter::Error) - .chain(std::io::stdout()) - .format(move |out, message, record| { - out.finish(format_args!( - "{}[{}] {}", - chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S%:z]"), - colors.color(record.level()), - message - )); - }) - .apply()?; - Ok(()) -} #[cfg_attr(coverage, no_coverage)] fn greeting(app_conf: &config::Config) { let extensions = app_conf @@ -74,8 +47,34 @@ fn greeting(app_conf: &config::Config) { fn main() -> RustusResult<()> { let args = config::Config::parse(); - setup_logging(&args)?; greeting(&args); + #[allow(clippy::no_effect_underscore_binding)] + let mut _guard = None; + if let Some(sentry_dsn) = &args.sentry_config.dsn { + let default_options = sentry::ClientOptions::default(); + _guard = Some(sentry::init(sentry::ClientOptions { + dsn: sentry::types::Dsn::from_str(sentry_dsn.as_str()).ok(), + // Enable capturing of traces; set this a to lower value in production: + sample_rate: args + .sentry_config + .sample_rate + .unwrap_or(default_options.sample_rate), + traces_sample_rate: args + .sentry_config + .traces_sample_rate + .unwrap_or(default_options.traces_sample_rate), + environment: args + .sentry_config + .environment + .clone() + .map(Cow::from) + .clone(), + release: sentry::release_name!(), + debug: args.sentry_config.debug, + ..default_options + })); + } + let mut builder = if Some(1) == args.workers { tokio::runtime::Builder::new_current_thread() } else { diff --git a/src/notifiers/impls/amqp_notifier.rs b/src/notifiers/impls/amqp_notifier.rs index b2907d4..3156ac3 100644 --- a/src/notifiers/impls/amqp_notifier.rs +++ b/src/notifiers/impls/amqp_notifier.rs @@ -20,7 +20,7 @@ use crate::{ }; #[allow(clippy::struct_excessive_bools)] -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct DeclareOptions { pub declare_exchange: bool, pub durable_exchange: bool, @@ -28,7 +28,7 @@ pub struct DeclareOptions { pub durable_queues: bool, } -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct AMQPNotifier { exchange_name: String, channel_pool: Pool, @@ -150,6 +150,7 @@ impl Notifier for AMQPNotifier { Ok(()) } + #[tracing::instrument(skip(self, message, _header_map))] async fn send_message( &self, message: String, diff --git a/src/notifiers/impls/dir_notifier.rs b/src/notifiers/impls/dir_notifier.rs index 363d914..28cf908 100644 --- a/src/notifiers/impls/dir_notifier.rs +++ b/src/notifiers/impls/dir_notifier.rs @@ -4,11 +4,10 @@ use crate::{ RustusResult, }; use axum::http::HeaderMap; -use log::debug; use std::path::PathBuf; use tokio::process::Command; -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct DirNotifier { pub dir: PathBuf, } @@ -26,6 +25,7 @@ impl Notifier for DirNotifier { Ok(()) } + #[tracing::instrument(skip(self, message, _headers_map))] async fn send_message( &self, message: String, @@ -34,12 +34,12 @@ impl Notifier for DirNotifier { ) -> RustusResult<()> { let hook_path = self.dir.join(hook.to_string()); if !hook_path.exists() { - debug!("Hook {} not found.", hook.to_string()); + tracing::debug!("Hook {} not found.", hook.to_string()); return Err(RustusError::HookError(format!( "Hook file {hook} not found." ))); } - debug!("Running hook: {}", hook_path.as_path().display()); + tracing::debug!("Running hook: {}", hook_path.as_path().display()); let mut command = Command::new(hook_path).arg(message).spawn()?; let stat = command.wait().await?; if !stat.success() { diff --git a/src/notifiers/impls/file_notifier.rs b/src/notifiers/impls/file_notifier.rs index d01a497..6c1e258 100644 --- a/src/notifiers/impls/file_notifier.rs +++ b/src/notifiers/impls/file_notifier.rs @@ -4,10 +4,9 @@ use crate::{ RustusResult, }; use axum::http::HeaderMap; -use log::debug; use tokio::process::Command; -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct FileNotifier { pub command: String, } @@ -25,19 +24,21 @@ impl Notifier for FileNotifier { Ok(()) } + #[tracing::instrument(err, skip(self, message, _headers_map), fields(exit_status = tracing::field::Empty))] async fn send_message( &self, message: String, hook: Hook, _headers_map: &HeaderMap, ) -> RustusResult<()> { - debug!("Running command: {}", self.command.as_str()); + tracing::debug!("Running command: {}", self.command.as_str()); let mut command = Command::new(self.command.as_str()) .arg(hook.to_string()) .arg(message) .spawn()?; let stat = command.wait().await?; if !stat.success() { + tracing::Span::current().record("exit_status", stat.code().unwrap_or(0)); return Err(RustusError::HookError("Returned wrong status code".into())); } Ok(()) diff --git a/src/notifiers/impls/http_notifier.rs b/src/notifiers/impls/http_notifier.rs index f1fd158..52fe18b 100644 --- a/src/notifiers/impls/http_notifier.rs +++ b/src/notifiers/impls/http_notifier.rs @@ -7,7 +7,7 @@ use axum::http::HeaderMap; use reqwest::Client; use std::time::Duration; -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct HttpNotifier { urls: Vec, client: Client, @@ -34,16 +34,17 @@ impl Notifier for HttpNotifier { Ok(()) } + #[tracing::instrument(err, skip(self, message, header_map), fields(response_body = tracing::field::Empty))] async fn send_message( &self, message: String, hook: Hook, header_map: &HeaderMap, ) -> RustusResult<()> { - log::debug!("Starting HTTP Hook."); + tracing::debug!("Starting HTTP Hook."); let idempotency_key = uuid::Uuid::new_v4().to_string(); let requests_vec = self.urls.iter().map(|url| { - log::debug!("Preparing request for {}", url); + tracing::debug!("Preparing request for {}", url); let mut request = self .client .post(url.as_str()) @@ -67,12 +68,7 @@ impl Notifier for HttpNotifier { .and_then(|hval| hval.to_str().ok().map(String::from)); let status = real_resp.status().as_u16(); let text = real_resp.text().await.unwrap_or_default(); - log::warn!( - "Got wrong response for `{hook}`. Status code: `{status}`, body: `{body}`", - hook = hook, - status = status, - body = text, - ); + tracing::Span::current().record("response_body", &text); return Err(RustusError::HTTPHookError(status, text, content_type)); } } diff --git a/src/notifiers/manager.rs b/src/notifiers/manager.rs index c77cfb7..96ddadf 100644 --- a/src/notifiers/manager.rs +++ b/src/notifiers/manager.rs @@ -8,8 +8,9 @@ use crate::{ use super::{base::Notifier, NotifierImpl}; use axum::http::HeaderMap; +use tracing::Instrument; -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct NotificationManager { notifiers: Vec, } @@ -25,21 +26,21 @@ impl NotificationManager { let mut manager = Self { notifiers: Vec::new(), }; - log::debug!("Initializing notification manager."); + tracing::debug!("Initializing notification manager."); if let Some(hooks_file) = &rustus_config.notification_config.hooks_file { - log::debug!("Found hooks file"); + tracing::debug!("Found hooks file"); manager .notifiers .push(NotifierImpl::File(FileNotifier::new(hooks_file.clone()))); } if let Some(hooks_dir) = &rustus_config.notification_config.hooks_dir { - log::debug!("Found hooks directory"); + tracing::debug!("Found hooks directory"); manager .notifiers .push(NotifierImpl::Dir(DirNotifier::new(hooks_dir.clone()))); } if !rustus_config.notification_config.hooks_http_urls.is_empty() { - log::debug!("Found http hook urls."); + tracing::debug!("Found http hook urls."); manager.notifiers.push(NotifierImpl::Http(HttpNotifier::new( rustus_config.notification_config.hooks_http_urls.clone(), rustus_config @@ -55,12 +56,12 @@ impl NotificationManager { .hooks_amqp_url .is_some() { - log::debug!("Found AMQP notifier."); + tracing::debug!("Found AMQP notifier."); manager.notifiers.push(NotifierImpl::Amqp(AMQPNotifier::new( rustus_config.notification_config.amqp_hook_opts.clone(), ))); } - log::debug!("Notification manager initialized."); + tracing::debug!("Notification manager initialized."); manager } @@ -83,7 +84,8 @@ impl NotificationManager { /// # Errors /// /// This method might fail in case if any of the notifiers fails. - pub async fn send_message( + #[tracing::instrument(skip(self, hook, headers_map))] + pub async fn notify_all( &self, message: String, hook: super::hooks::Hook, @@ -92,6 +94,7 @@ impl NotificationManager { for notifier in &self.notifiers { notifier .send_message(message.clone(), hook, headers_map) + .in_current_span() .await?; } Ok(()) diff --git a/src/notifiers/mod.rs b/src/notifiers/mod.rs index 5fee8dd..af7b6c2 100644 --- a/src/notifiers/mod.rs +++ b/src/notifiers/mod.rs @@ -4,10 +4,11 @@ pub mod impls; pub mod manager; pub mod serializer; +use axum::http::HeaderMap; pub use manager::NotificationManager; pub use serializer::Format; -#[derive(Clone)] +#[derive(Clone, Debug)] pub enum NotifierImpl { Http(impls::http_notifier::HttpNotifier), File(impls::file_notifier::FileNotifier), @@ -28,7 +29,7 @@ impl base::Notifier for NotifierImpl { &self, message: String, hook: hooks::Hook, - headers_map: &http::HeaderMap, + headers_map: &HeaderMap, ) -> crate::errors::RustusResult<()> { match self { Self::Http(http) => http.send_message(message, hook, headers_map).await, diff --git a/src/notifiers/serializer.rs b/src/notifiers/serializer.rs index c449a9e..3529cbf 100644 --- a/src/notifiers/serializer.rs +++ b/src/notifiers/serializer.rs @@ -1,6 +1,6 @@ use std::{collections::HashMap, hash::BuildHasherDefault, net::SocketAddr}; -use http::{HeaderMap, Uri}; +use axum::http::{HeaderMap, Method, Uri}; use rustc_hash::FxHasher; use serde_json::{json, Value}; @@ -29,7 +29,7 @@ impl Format { pub fn format( &self, uri: &Uri, - method: &http::Method, + method: &Method, addr: &SocketAddr, headers: &HeaderMap, proxy_enabled: bool, diff --git a/src/server/cors.rs b/src/server/cors.rs index 4d6b0bc..8a3d04e 100644 --- a/src/server/cors.rs +++ b/src/server/cors.rs @@ -1,6 +1,6 @@ use std::{str::FromStr, time::Duration}; -use http::{HeaderName, HeaderValue, Method}; +use axum::http::{HeaderName, HeaderValue, Method}; use tower_http::cors::{AllowOrigin, CorsLayer, MaxAge}; use wildmatch::WildMatch; diff --git a/src/server/mod.rs b/src/server/mod.rs index 95eb6e0..73e4d3f 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -1,64 +1,24 @@ use std::{ net::{Ipv4Addr, SocketAddr, SocketAddrV4}, sync::Arc, + time::Duration, }; use crate::{ config::Config, errors::RustusResult, state::RustusState, utils::headers::HeaderMapExt, }; use axum::{ - extract::{ConnectInfo, DefaultBodyLimit, State}, - http::HeaderValue, + extract::{ConnectInfo, DefaultBodyLimit, MatchedPath, Request, State}, + http::{HeaderValue, StatusCode}, + response::{IntoResponse, Response}, Router, ServiceExt, }; use tower::Layer; +use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; mod cors; mod routes; -async fn logger( - State(config): State>, - req: axum::extract::Request, - next: axum::middleware::Next, -) -> impl axum::response::IntoResponse { - let default_addr = ConnectInfo(SocketAddr::V4(SocketAddrV4::new( - Ipv4Addr::new(0, 0, 0, 0), - 8000, - ))); - let socket = req - .extensions() - .get::>() - .unwrap_or(&default_addr); - let remote = req.headers().get_remote_ip(socket, config.behind_proxy); - let method = req.method().to_string(); - let uri = req - .uri() - .path_and_query() - .map(ToString::to_string) - .unwrap_or_default(); - - let time = std::time::Instant::now(); - let version = req.version(); - let response = next.run(req).await; - #[allow(clippy::cast_precision_loss)] - let elapsed = (time.elapsed().as_micros() as f64) / 1000.0; - let status = response.status().as_u16(); - - // log::log!(log::Level::Info, "ememe"); - if uri != "/health" { - let mut level = log::Level::Info; - if !response.status().is_success() { - level = log::Level::Error; - } - log::log!( - level, - "\"{method} {uri} {version:?}\" \"-\" \"{status}\" \"{remote}\" \"{elapsed}\"" - ); - } - - response -} - async fn method_replacer( mut req: axum::extract::Request, next: axum::middleware::Next, @@ -94,7 +54,11 @@ async fn add_tus_header( } async fn healthcheck() -> impl axum::response::IntoResponse { - axum::http::StatusCode::OK + let mut response = StatusCode::OK.into_response(); + response + .headers_mut() + .insert("X-NO-LOG", HeaderValue::from_static("1")); + response } async fn fallback() -> impl axum::response::IntoResponse { @@ -137,23 +101,86 @@ pub fn get_router(state: Arc) -> Router { /// /// This function returns an error if the server fails to start. pub async fn start(config: Config) -> RustusResult<()> { - let listener = tokio::net::TcpListener::bind((config.host.clone(), config.port)).await?; - log::info!("Starting server at http://{}:{}", config.host, config.port); - let state = Arc::new(RustusState::from_config(&config).await?); + let behind_proxy = config.behind_proxy; + let default_addr = ConnectInfo(SocketAddr::V4(SocketAddrV4::new( + Ipv4Addr::new(0, 0, 0, 0), + 0, + ))); + + let mut sentry_layer = None; + if config.sentry_config.dsn.is_some() { + sentry_layer = Some(sentry_tracing::layer()); + } + tracing_subscriber::registry() + .with(tracing_subscriber::filter::LevelFilter::from_level( + config.log_level, + )) + .with( + tracing_subscriber::fmt::layer() + .with_level(true) + .with_file(false) + .with_line_number(false) + .with_target(false), + ) + .with(sentry_layer) + .init(); + + let tracer = tower_http::trace::TraceLayer::new_for_http() + .make_span_with(move |request: &Request| { + let matched_path = request + .extensions() + .get::() + .map(MatchedPath::as_str); + let socket_addr = request + .extensions() + .get::>() + .unwrap_or(&default_addr); + let ip = request.headers().get_remote_ip(socket_addr, behind_proxy); + tracing::info_span!( + "request", + method = ?request.method(), + matched_path, + version = ?request.version(), + ip = ip, + status = tracing::field::Empty, + ) + }) + .on_response( + move |response: &Response, latency: Duration, span: &tracing::Span| { + span.record("status", response.status().as_u16()); + span.record("duration", latency.as_millis()); + if config.no_access { + return; + } + if response.headers().contains_key("X-NO-LOG") { + return; + } + tracing::info!("access log"); + }, + ); + + let state = Arc::new(RustusState::from_config(&config).await?); let tus_app = get_router(state); - let main_router = axum::Router::new() + let mut main_router = axum::Router::new() .route("/health", axum::routing::get(healthcheck)) .nest(&config.url, tus_app) - .fallback(fallback); + .fallback(fallback) + .layer(tracer); - let service = axum::middleware::from_fn(method_replacer).layer( - axum::middleware::from_fn_with_state(Arc::new(config.clone()), logger).layer(main_router), - ); + if config.sentry_config.dsn.is_some() { + main_router = main_router + .layer(sentry_tower::NewSentryLayer::new_from_top()) + .layer(sentry_tower::SentryHttpLayer::new()); + } + let listener = tokio::net::TcpListener::bind((config.host.clone(), config.port)).await?; + tracing::info!("Starting server at http://{}:{}", config.host, config.port); axum::serve( listener, - service.into_make_service_with_connect_info::(), + axum::middleware::from_fn(method_replacer) + .layer(main_router) + .into_make_service_with_connect_info::(), ) .await?; Ok(()) diff --git a/src/server/routes/create.rs b/src/server/routes/create.rs index 5d9381b..e4800db 100644 --- a/src/server/routes/create.rs +++ b/src/server/routes/create.rs @@ -2,24 +2,20 @@ use std::{net::SocketAddr, sync::Arc}; use axum::{ extract::{ConnectInfo, State}, - http::{HeaderMap, StatusCode}, + http::{HeaderMap, Method, StatusCode, Uri}, response::{IntoResponse, Response}, }; use bytes::Bytes; -use http::{Method, Uri}; +use tracing::Instrument; use crate::{ - data_storage::base::Storage, - errors::RustusResult, - extensions::TusExtensions, - info_storages::base::InfoStorage, - models::file_info::FileInfo, - notifiers::hooks::Hook, - state::RustusState, - utils::{headers::HeaderMapExt, result::MonadLogger}, + data_storage::base::Storage, errors::RustusResult, extensions::TusExtensions, + info_storages::base::InfoStorage, models::file_info::FileInfo, notifiers::hooks::Hook, + state::RustusState, utils::headers::HeaderMapExt, }; #[allow(clippy::too_many_lines)] +#[tracing::instrument(level = "info", skip_all, fields(upload_id = tracing::field::Empty))] pub async fn handler( uri: Uri, method: Method, @@ -68,6 +64,8 @@ pub async fn handler( let meta = headers.get_metadata(); let file_id = uuid::Uuid::new_v4().to_string(); + tracing::Span::current().record("upload_id", &file_id); + let mut file_info = FileInfo::new( file_id.as_str(), upload_len, @@ -142,7 +140,7 @@ pub async fn handler( { state .notificator - .send_message( + .notify_all( state.config.notification_config.hooks_format.format( &uri, &method, @@ -198,19 +196,15 @@ pub async fn handler( let moved_state = state.clone(); // Adding send_message task to tokio reactor. // Thin function would be executed in background. - tokio::task::spawn(async move { - moved_state - .notificator - .send_message(message, post_hook, &headers) - .await - .mlog_warn( - format!( - "Failed to send PostReceive hook for upload {}", - file_info.id - ) - .as_str(), - ) - }); + tokio::task::spawn( + async move { + moved_state + .notificator + .notify_all(message, post_hook, &headers) + .await + } + .in_current_span(), + ); } Ok(( diff --git a/src/server/routes/delete.rs b/src/server/routes/delete.rs index 8a2d8ba..e43598d 100644 --- a/src/server/routes/delete.rs +++ b/src/server/routes/delete.rs @@ -2,10 +2,10 @@ use std::{net::SocketAddr, sync::Arc}; use axum::{ extract::{ConnectInfo, Path, State}, - http::StatusCode, + http::{HeaderMap, Method, StatusCode, Uri}, response::{IntoResponse, Response}, }; -use http::{HeaderMap, Method, Uri}; +use tracing::Instrument; use crate::{ data_storage::base::Storage, @@ -14,7 +14,6 @@ use crate::{ info_storages::base::InfoStorage, notifiers::hooks::Hook, state::RustusState, - utils::result::MonadLogger, }; pub async fn handler( @@ -45,7 +44,7 @@ pub async fn handler( { state .notificator - .send_message( + .notify_all( state.config.notification_config.hooks_format.format( &uri, &method, @@ -77,13 +76,15 @@ pub async fn handler( &file_info, ); let state_cln = state.clone(); - tokio::spawn(async move { - state_cln - .notificator - .send_message(msg, Hook::PostTerminate, &headers) - .await - .mlog_warn("Cannot send PostTerminate hook") - }); + tokio::spawn( + async move { + state_cln + .notificator + .notify_all(msg, Hook::PostTerminate, &headers) + .await + } + .in_current_span(), + ); } Ok(StatusCode::NO_CONTENT.into_response()) diff --git a/src/server/routes/file_info.rs b/src/server/routes/file_info.rs index 747a795..37b732f 100644 --- a/src/server/routes/file_info.rs +++ b/src/server/routes/file_info.rs @@ -2,9 +2,9 @@ use std::sync::Arc; use axum::{ extract::{Path, State}, + http::StatusCode, response::Response, }; -use reqwest::StatusCode; use crate::{ data_storage::base::Storage, errors::RustusResult, info_storages::base::InfoStorage, diff --git a/src/server/routes/get_file.rs b/src/server/routes/get_file.rs index 668b94e..24226c5 100644 --- a/src/server/routes/get_file.rs +++ b/src/server/routes/get_file.rs @@ -2,9 +2,9 @@ use std::sync::Arc; use axum::{ extract::{Path, State}, + http::StatusCode, response::{IntoResponse, Response}, }; -use reqwest::StatusCode; use crate::{ data_storage::base::Storage, diff --git a/src/server/routes/upload.rs b/src/server/routes/upload.rs index 83c81dd..5a4cfff 100644 --- a/src/server/routes/upload.rs +++ b/src/server/routes/upload.rs @@ -2,11 +2,11 @@ use std::{net::SocketAddr, sync::Arc}; use axum::{ extract::{ConnectInfo, Path, State}, - http::{HeaderMap, StatusCode}, + http::{HeaderMap, Method, StatusCode, Uri}, response::IntoResponse, }; use bytes::Bytes; -use http::{Method, Uri}; +use tracing::Instrument; use crate::{ data_storage::base::Storage, @@ -15,9 +15,10 @@ use crate::{ info_storages::base::InfoStorage, notifiers::hooks::Hook, state::RustusState, - utils::{hashes::verify_chunk_checksum, headers::HeaderMapExt, result::MonadLogger}, + utils::{hashes::verify_chunk_checksum, headers::HeaderMapExt}, }; +#[tracing::instrument(level = "info", skip_all, fields(upload_id = tracing::field::Empty))] pub async fn handler( uri: Uri, method: Method, @@ -27,6 +28,7 @@ pub async fn handler( Path(upload_id): Path, body: Bytes, ) -> RustusResult { + tracing::Span::current().record("upload_id", upload_id.as_str()); if !headers.check("Content-Type", |val| { val == "application/offset+octet-stream" }) { @@ -134,20 +136,16 @@ pub async fn handler( ); let headers_clone = headers.clone(); - tokio::spawn(async move { - state_clone - .notificator - .send_message(msg, hook, &headers_clone) - .await - .mlog_warn( - format!( - "Failed to send PostReceive hook for upload {}", - file_info.id - ) - .as_str(), - ) - .ok(); - }); + tokio::spawn( + async move { + state_clone + .notificator + .notify_all(msg, hook, &headers_clone) + .await + .ok(); + } + .in_current_span(), + ); } Ok(( diff --git a/src/state.rs b/src/state.rs index dcc3d16..353d7aa 100644 --- a/src/state.rs +++ b/src/state.rs @@ -6,7 +6,7 @@ use crate::{ notifiers::NotificationManager, }; -#[derive(Clone)] +#[derive(Clone, Debug)] #[allow(clippy::module_name_repetitions)] pub struct RustusState { pub config: Config, diff --git a/src/utils/hashes.rs b/src/utils/hashes.rs index 826ea18..bd87a37 100644 --- a/src/utils/hashes.rs +++ b/src/utils/hashes.rs @@ -47,16 +47,12 @@ pub fn verify_chunk_checksum(header: &HeaderValue, data: &[u8]) -> RustusResult< if let Some(checksum_base) = split.next() { let checksum = base64::engine::general_purpose::STANDARD .decode(checksum_base) - .map_err(|_| { - log::error!("Can't decode checksum value"); - RustusError::WrongHeaderValue - })?; + .map_err(|_| RustusError::WrongHeaderValue)?; return checksum_verify(algo, data, checksum.as_slice()); } } Err(RustusError::WrongHeaderValue) } else { - log::error!("Can't decode checksum header."); Err(RustusError::WrongHeaderValue) } } diff --git a/src/utils/lapin_pool.rs b/src/utils/lapin_pool.rs index 4a03c2e..97a8d10 100644 --- a/src/utils/lapin_pool.rs +++ b/src/utils/lapin_pool.rs @@ -1,10 +1,12 @@ use lapin::{ChannelState, ConnectionProperties, ConnectionState}; +#[derive(Clone)] pub struct ConnnectionPool { url: String, properties: ConnectionProperties, } +#[derive(Clone, Debug)] pub struct ChannelPool { pool: mobc::Pool, } diff --git a/src/utils/result.rs b/src/utils/result.rs index 09a60e8..d50b044 100644 --- a/src/utils/result.rs +++ b/src/utils/result.rs @@ -1,53 +1,44 @@ use std::fmt::Display; -pub trait MonadLogger { +pub trait MonadLogger: Sized { #[must_use] - fn mlog(self, level: log::Level, msg: &str) -> Self; - #[must_use] - fn mlog_err(self, msg: &str) -> Self; - #[must_use] - fn mlog_warn(self, msg: &str) -> Self; - #[must_use] - fn mlog_dbg(self, msg: &str) -> Self; -} + fn _should_log(&self) -> bool; -impl MonadLogger for Result { - fn mlog(self, level: log::Level, msg: &str) -> Self { - if let Err(err) = &self { - log::log!(level, "{msg}: {err}"); + #[must_use] + fn mlog_err(self, msg: &str) -> Self { + if self._should_log() { + tracing::error!(msg); } self } - fn mlog_err(self, msg: &str) -> Self { - self.mlog(log::Level::Error, msg) - } - + #[must_use] fn mlog_warn(self, msg: &str) -> Self { - self.mlog(log::Level::Warn, msg) + if self._should_log() { + tracing::warn!(msg); + } + self } + #[must_use] + #[allow(unused_variables)] fn mlog_dbg(self, msg: &str) -> Self { - self.mlog(log::Level::Debug, msg) - } -} - -impl MonadLogger for Option { - fn mlog(self, level: log::Level, msg: &str) -> Self { - if self.is_none() { - log::log!(level, "{msg}: The value is None"); + #[cfg(debug_assertions)] + if self._should_log() { + tracing::debug!(msg); } self } - fn mlog_err(self, msg: &str) -> Self { - self.mlog(log::Level::Error, msg) - } +} - fn mlog_warn(self, msg: &str) -> Self { - self.mlog(log::Level::Warn, msg) +impl MonadLogger for Result { + fn _should_log(&self) -> bool { + self.is_err() } +} - fn mlog_dbg(self, msg: &str) -> Self { - self.mlog(log::Level::Debug, msg) +impl MonadLogger for Option { + fn _should_log(&self) -> bool { + self.is_none() } } From b899cfa6675e6721430b27f7f82f01425ee2f535 Mon Sep 17 00:00:00 2001 From: Pavel Kirilin Date: Tue, 12 Dec 2023 22:05:53 +0100 Subject: [PATCH 3/9] Changed access log info. Signed-off-by: Pavel Kirilin --- src/server/mod.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/server/mod.rs b/src/server/mod.rs index 73e4d3f..d27ffc4 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -8,7 +8,7 @@ use crate::{ config::Config, errors::RustusResult, state::RustusState, utils::headers::HeaderMapExt, }; use axum::{ - extract::{ConnectInfo, DefaultBodyLimit, MatchedPath, Request, State}, + extract::{ConnectInfo, DefaultBodyLimit, Request, State}, http::{HeaderValue, StatusCode}, response::{IntoResponse, Response}, Router, ServiceExt, @@ -128,10 +128,7 @@ pub async fn start(config: Config) -> RustusResult<()> { let tracer = tower_http::trace::TraceLayer::new_for_http() .make_span_with(move |request: &Request| { - let matched_path = request - .extensions() - .get::() - .map(MatchedPath::as_str); + let path = request.uri().path().to_string(); let socket_addr = request .extensions() .get::>() @@ -140,7 +137,7 @@ pub async fn start(config: Config) -> RustusResult<()> { tracing::info_span!( "request", method = ?request.method(), - matched_path, + path, version = ?request.version(), ip = ip, status = tracing::field::Empty, From c01b3133410e4a19d95c027e6bfe364627a0b7b2 Mon Sep 17 00:00:00 2001 From: Pavel Kirilin Date: Fri, 15 Dec 2023 10:25:04 +0100 Subject: [PATCH 4/9] Changed notification signature to pass all by references. (#148) --- src/notifiers/base.rs | 4 ++-- src/notifiers/impls/amqp_notifier.rs | 6 +++--- src/notifiers/impls/dir_notifier.rs | 4 ++-- src/notifiers/impls/file_notifier.rs | 4 ++-- src/notifiers/impls/http_notifier.rs | 7 ++++--- src/notifiers/manager.rs | 12 ++++++------ src/notifiers/mod.rs | 4 ++-- src/server/routes/create.rs | 25 +++++++++++++++---------- src/server/routes/delete.rs | 25 +++++++++++++++---------- src/server/routes/upload.rs | 2 +- 10 files changed, 52 insertions(+), 41 deletions(-) diff --git a/src/notifiers/base.rs b/src/notifiers/base.rs index fe9c14e..494051d 100644 --- a/src/notifiers/base.rs +++ b/src/notifiers/base.rs @@ -8,8 +8,8 @@ pub trait Notifier { async fn prepare(&mut self) -> RustusResult<()>; async fn send_message( &self, - message: String, - hook: Hook, + message: &str, + hook: &Hook, headers_map: &HeaderMap, ) -> RustusResult<()>; } diff --git a/src/notifiers/impls/amqp_notifier.rs b/src/notifiers/impls/amqp_notifier.rs index 3156ac3..ffe4856 100644 --- a/src/notifiers/impls/amqp_notifier.rs +++ b/src/notifiers/impls/amqp_notifier.rs @@ -153,12 +153,12 @@ impl Notifier for AMQPNotifier { #[tracing::instrument(skip(self, message, _header_map))] async fn send_message( &self, - message: String, - hook: Hook, + message: &str, + hook: &Hook, _header_map: &HeaderMap, ) -> RustusResult<()> { let chan = self.channel_pool.get().await?; - let queue = self.get_queue_name(&hook); + let queue = self.get_queue_name(hook); let routing_key = self.routing_key.as_ref().unwrap_or(&queue); let payload = if self.celery { format!("[[{message}], {{}}, {{}}]").as_bytes().to_vec() diff --git a/src/notifiers/impls/dir_notifier.rs b/src/notifiers/impls/dir_notifier.rs index 28cf908..7d97779 100644 --- a/src/notifiers/impls/dir_notifier.rs +++ b/src/notifiers/impls/dir_notifier.rs @@ -28,8 +28,8 @@ impl Notifier for DirNotifier { #[tracing::instrument(skip(self, message, _headers_map))] async fn send_message( &self, - message: String, - hook: Hook, + message: &str, + hook: &Hook, _headers_map: &HeaderMap, ) -> RustusResult<()> { let hook_path = self.dir.join(hook.to_string()); diff --git a/src/notifiers/impls/file_notifier.rs b/src/notifiers/impls/file_notifier.rs index 6c1e258..fe8dc46 100644 --- a/src/notifiers/impls/file_notifier.rs +++ b/src/notifiers/impls/file_notifier.rs @@ -27,8 +27,8 @@ impl Notifier for FileNotifier { #[tracing::instrument(err, skip(self, message, _headers_map), fields(exit_status = tracing::field::Empty))] async fn send_message( &self, - message: String, - hook: Hook, + message: &str, + hook: &Hook, _headers_map: &HeaderMap, ) -> RustusResult<()> { tracing::debug!("Running command: {}", self.command.as_str()); diff --git a/src/notifiers/impls/http_notifier.rs b/src/notifiers/impls/http_notifier.rs index 52fe18b..ec97835 100644 --- a/src/notifiers/impls/http_notifier.rs +++ b/src/notifiers/impls/http_notifier.rs @@ -37,12 +37,13 @@ impl Notifier for HttpNotifier { #[tracing::instrument(err, skip(self, message, header_map), fields(response_body = tracing::field::Empty))] async fn send_message( &self, - message: String, - hook: Hook, + message: &str, + hook: &Hook, header_map: &HeaderMap, ) -> RustusResult<()> { tracing::debug!("Starting HTTP Hook."); let idempotency_key = uuid::Uuid::new_v4().to_string(); + let body_bytes = bytes::Bytes::copy_from_slice(message.as_bytes()); let requests_vec = self.urls.iter().map(|url| { tracing::debug!("Preparing request for {}", url); let mut request = self @@ -57,7 +58,7 @@ impl Notifier for HttpNotifier { request = request.header(item.as_str(), value.as_bytes()); } } - request.body(message.clone()).send() + request.body(body_bytes.clone()).send() }); for response in requests_vec { let real_resp = response.await?; diff --git a/src/notifiers/manager.rs b/src/notifiers/manager.rs index 96ddadf..3b4e10e 100644 --- a/src/notifiers/manager.rs +++ b/src/notifiers/manager.rs @@ -87,16 +87,16 @@ impl NotificationManager { #[tracing::instrument(skip(self, hook, headers_map))] pub async fn notify_all( &self, - message: String, - hook: super::hooks::Hook, + message: &str, + hook: &super::hooks::Hook, headers_map: &HeaderMap, ) -> crate::errors::RustusResult<()> { - for notifier in &self.notifiers { + let collect = self.notifiers.iter().map(|notifier| { notifier - .send_message(message.clone(), hook, headers_map) + .send_message(message, hook, headers_map) .in_current_span() - .await?; - } + }); + futures::future::try_join_all(collect).await?; Ok(()) } } diff --git a/src/notifiers/mod.rs b/src/notifiers/mod.rs index af7b6c2..6f1bc74 100644 --- a/src/notifiers/mod.rs +++ b/src/notifiers/mod.rs @@ -27,8 +27,8 @@ impl base::Notifier for NotifierImpl { } async fn send_message( &self, - message: String, - hook: hooks::Hook, + message: &str, + hook: &hooks::Hook, headers_map: &HeaderMap, ) -> crate::errors::RustusResult<()> { match self { diff --git a/src/server/routes/create.rs b/src/server/routes/create.rs index e4800db..d752fd2 100644 --- a/src/server/routes/create.rs +++ b/src/server/routes/create.rs @@ -141,15 +141,20 @@ pub async fn handler( state .notificator .notify_all( - state.config.notification_config.hooks_format.format( - &uri, - &method, - &addr, - &headers, - state.config.behind_proxy, - &file_info, - ), - Hook::PreCreate, + state + .config + .notification_config + .hooks_format + .format( + &uri, + &method, + &addr, + &headers, + state.config.behind_proxy, + &file_info, + ) + .as_str(), + &Hook::PreCreate, &headers, ) .await?; @@ -200,7 +205,7 @@ pub async fn handler( async move { moved_state .notificator - .notify_all(message, post_hook, &headers) + .notify_all(&message, &post_hook, &headers) .await } .in_current_span(), diff --git a/src/server/routes/delete.rs b/src/server/routes/delete.rs index e43598d..6e9daef 100644 --- a/src/server/routes/delete.rs +++ b/src/server/routes/delete.rs @@ -45,15 +45,20 @@ pub async fn handler( state .notificator .notify_all( - state.config.notification_config.hooks_format.format( - &uri, - &method, - &addr, - &headers, - state.config.behind_proxy, - &file_info, - ), - Hook::PreTerminate, + state + .config + .notification_config + .hooks_format + .format( + &uri, + &method, + &addr, + &headers, + state.config.behind_proxy, + &file_info, + ) + .as_str(), + &Hook::PreTerminate, &headers, ) .await?; @@ -80,7 +85,7 @@ pub async fn handler( async move { state_cln .notificator - .notify_all(msg, Hook::PostTerminate, &headers) + .notify_all(&msg, &Hook::PostTerminate, &headers) .await } .in_current_span(), diff --git a/src/server/routes/upload.rs b/src/server/routes/upload.rs index 5a4cfff..a9e0e76 100644 --- a/src/server/routes/upload.rs +++ b/src/server/routes/upload.rs @@ -140,7 +140,7 @@ pub async fn handler( async move { state_clone .notificator - .notify_all(msg, hook, &headers_clone) + .notify_all(&msg, &hook, &headers_clone) .await .ok(); } From 1cb592891b9258d3f4936587cd26a7deac1ce832 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Kla=C4=8Dan?= Date: Wed, 8 May 2024 20:59:12 +0200 Subject: [PATCH 5/9] Switch to stable + Fix CORS (#149) --- .github/workflows/release.yml | 2 +- .github/workflows/test.yml | 6 +++--- .pre-commit-config.yaml | 2 +- .rustfmt.toml | 1 - README.md | 7 +++---- deploy/Dockerfile | 4 ++-- rust-toolchain.toml | 2 +- src/config.rs | 6 +++--- src/server/mod.rs | 22 ++++++++++++++++++++-- src/server/routes/info.rs | 34 ---------------------------------- src/server/routes/mod.rs | 1 - 11 files changed, 34 insertions(+), 53 deletions(-) delete mode 100644 src/server/routes/info.rs diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 31aec4e..90d28ca 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,7 +11,7 @@ jobs: runs-on: ${{ matrix.job.os }} strategy: matrix: - rust: [nightly] + rust: [stable] job: - os: macos-latest os-name: macos diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 818a98e..86aef21 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,7 +27,7 @@ jobs: - name: Install stable toolchain uses: actions-rs/toolchain@v1 with: - toolchain: nightly + toolchain: stable override: true - name: Adding component run: rustup component add rustfmt @@ -43,7 +43,7 @@ jobs: - name: Install stable toolchain uses: actions-rs/toolchain@v1 with: - toolchain: nightly + toolchain: stable override: true - run: rustup component add clippy - uses: actions-rs/clippy-check@v1 @@ -62,7 +62,7 @@ jobs: - name: Install stable toolchain uses: actions-rs/toolchain@v1 with: - toolchain: nightly + toolchain: stable override: true - name: Run tests run: cargo test -- --test-threads 1 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5f94262..4e1b3be 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,7 +16,7 @@ repos: - fmt - -- - --config - - use_try_shorthand=true,imports_granularity=Crate + - use_try_shorthand=true - id: clippy types: diff --git a/.rustfmt.toml b/.rustfmt.toml index f5e4b58..6575192 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -1,2 +1 @@ use_try_shorthand=true -imports_granularity="Crate" \ No newline at end of file diff --git a/README.md b/README.md index ad03d65..2d7d68f 100644 --- a/README.md +++ b/README.md @@ -27,11 +27,10 @@ You can install rustus by 3 different ways. ### From source -To build it from source rust must be installed. We rely on nightly features, -so please switch to nightly channel before building. +To build it from source rust must be installed. ```bash -rustup update nightly +rustup update stable git clone https://github.com/s3rius/rustus.git cd rustus cargo install --path . @@ -67,4 +66,4 @@ To persist data you can mount volume to `/data` directory ```bash docker run --rm -p "1081:1081" -d s3rius/rustus --log-level "DEBUG" -``` \ No newline at end of file +``` diff --git a/deploy/Dockerfile b/deploy/Dockerfile index c765847..cccf690 100644 --- a/deploy/Dockerfile +++ b/deploy/Dockerfile @@ -1,4 +1,4 @@ -FROM rustlang/rust:nightly-buster AS builder +FROM rustlang/rust:buster AS builder WORKDIR /app COPY Cargo.toml Cargo.lock ./ @@ -21,4 +21,4 @@ FROM base as rootless RUN useradd --create-home -u 1000 --user-group rustus WORKDIR /home/rustus -USER rustus \ No newline at end of file +USER rustus diff --git a/rust-toolchain.toml b/rust-toolchain.toml index a0e2ab6..02fea3c 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1 +1 @@ -toolchain.channel = "nightly" +toolchain.channel = "stable" diff --git a/src/config.rs b/src/config.rs index 52ad974..e33f050 100644 --- a/src/config.rs +++ b/src/config.rs @@ -56,7 +56,7 @@ pub struct DataStorageConfig { /// Rustus data directory /// /// This directory is used to store files - /// for all *file_storage storages. + /// for all *`file_storage` storages. #[arg(long, env = "RUSTUS_DATA_DIR", default_value = "./data")] pub data_dir: PathBuf, @@ -203,7 +203,7 @@ pub struct AMQPHooksOptions { )] pub hooks_amqp_queues_prefix: String, - /// Maximum number of connections for RabbitMQ. + /// Maximum number of connections for `RabbitMQ`. #[arg( long, env = "RUSTUS_HOOKS_AMQP_CONNECTION_POOL_SIZE", @@ -314,7 +314,7 @@ pub struct SentryConfig { #[arg(name = "sentry-environment", long, env = "RUSTUS_SENTRY_ENVIRONMENT")] pub environment: Option, - /// DEvelopment option for sentry. + /// Development option for sentry. /// /// This option enables logging of sentry events, /// which is useful for debugging. But it is not recommended diff --git a/src/server/mod.rs b/src/server/mod.rs index d27ffc4..1a4c7c8 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -5,7 +5,8 @@ use std::{ }; use crate::{ - config::Config, errors::RustusResult, state::RustusState, utils::headers::HeaderMapExt, + config::Config, errors::RustusResult, extensions::TusExtensions, state::RustusState, + utils::headers::HeaderMapExt, }; use axum::{ extract::{ConnectInfo, DefaultBodyLimit, Request, State}, @@ -50,6 +51,24 @@ async fn add_tus_header( resp.headers_mut().insert("Tus-Max-Size", max_size); } + let extensions = state + .tus_extensions + .iter() + .map(ToString::to_string) + .collect::>() + .join(","); + + if let Ok(val) = extensions.parse() { + resp.headers_mut().insert("Tus-Extension", val); + }; + + if state.tus_extensions.contains(&TusExtensions::Checksum) { + resp.headers_mut().insert( + "Tus-checksum-algorithm", + HeaderValue::from_static("md5,sha1,sha256,sha512"), + ); + } + resp } @@ -83,7 +102,6 @@ pub fn get_router(state: Arc) -> Router { config.cors.clone(), &config.notification_config.hooks_http_proxy_headers, )) - .route("/", axum::routing::options(routes::info::handler)) .with_state(state) .route_layer(axum::middleware::from_fn_with_state( config.clone(), diff --git a/src/server/routes/info.rs b/src/server/routes/info.rs deleted file mode 100644 index 2b4217e..0000000 --- a/src/server/routes/info.rs +++ /dev/null @@ -1,34 +0,0 @@ -use std::sync::Arc; - -use axum::{ - extract::State, - http::{HeaderMap, StatusCode}, - response::IntoResponse, -}; - -use crate::{errors::RustusResult, extensions::TusExtensions, state::RustusState}; - -pub async fn handler( - State(ref state): State>, -) -> RustusResult { - let mut headers = HeaderMap::new(); - let extensions = state - .config - .tus_extensions - .iter() - .map(ToString::to_string) - .collect::>() - .join(","); - - headers.insert("tus-extension", extensions.parse()?); - - if state - .config - .tus_extensions - .contains(&TusExtensions::Checksum) - { - headers.insert("tus-checksum-algorithm", "md5,sha1,sha256,sha512".parse()?); - } - - Ok((StatusCode::NO_CONTENT, headers).into_response()) -} diff --git a/src/server/routes/mod.rs b/src/server/routes/mod.rs index 45e6e28..b88aa9f 100644 --- a/src/server/routes/mod.rs +++ b/src/server/routes/mod.rs @@ -2,5 +2,4 @@ pub mod create; pub mod delete; pub mod file_info; pub mod get_file; -pub mod info; pub mod upload; From 977ed220a3bcece63760eefc0f64546643032d1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Kla=C4=8Dan?= Date: Fri, 10 May 2024 11:41:16 +0200 Subject: [PATCH 6/9] Update all deps (#150) --- Cargo.lock | 1682 ++++++++++++----- Cargo.toml | 8 +- src/errors.rs | 1 - src/info_storages/impls/redis_info_storage.rs | 13 +- src/main.rs | 1 - src/notifiers/impls/dir_notifier.rs | 1 - src/notifiers/impls/file_notifier.rs | 1 - src/notifiers/impls/http_notifier.rs | 1 - 8 files changed, 1169 insertions(+), 539 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 081cbbd..710f0f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,31 +17,54 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + [[package]] name = "ahash" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ "getrandom", "once_cell", "version_check", ] +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "amq-protocol" -version = "7.1.2" +version = "7.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d40d8b2465c7959dd40cee32ba6ac334b5de57e9fca0cc756759894a4152a5d" +checksum = "f051d4d77904272e9be7e292607378dc9900d15b8d314bfd3ed4b82fdd84f125" dependencies = [ "amq-protocol-tcp", "amq-protocol-types", @@ -53,9 +76,9 @@ dependencies = [ [[package]] name = "amq-protocol-tcp" -version = "7.1.2" +version = "7.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cb2100adae7da61953a2c3a01935d86caae13329fadce3333f524d6d6ce12e2" +checksum = "4e3d51dd36e67d757c9ba80a7b2a2a2a69254c1dbe4d8c631824ec7f5b69f60e" dependencies = [ "amq-protocol-uri", "tcp-stream", @@ -64,9 +87,9 @@ dependencies = [ [[package]] name = "amq-protocol-types" -version = "7.1.2" +version = "7.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "156ff13c8a3ced600b4e54ed826a2ae6242b6069d00dd98466827cef07d3daff" +checksum = "0acdd47054ced8b9bc89ee0dbb42ccc8028de48d8658b24de4c255a226c9bfec" dependencies = [ "cookie-factory", "nom", @@ -76,9 +99,9 @@ dependencies = [ [[package]] name = "amq-protocol-uri" -version = "7.1.2" +version = "7.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "751bbd7d440576066233e740576f1b31fdc6ab86cfabfbd48c548de77eca73e4" +checksum = "f17881b7575dab3e71403f28a3e50b71f0d1bd026829abca3c48664522ce0df0" dependencies = [ "amq-protocol-types", "percent-encoding", @@ -102,47 +125,48 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.4" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.4" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" [[package]] name = "anstyle-parse" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3a318f1f38d2418400f8209655bfd825785afd25aa30bb7ba6cc792e4596748" +checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.2" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" dependencies = [ "anstyle", "windows-sys 0.52.0", @@ -150,49 +174,87 @@ dependencies = [ [[package]] name = "arc-swap" -version = "1.6.0" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + +[[package]] +name = "asn1-rs" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ad1373757efa0f70ec53939aabc7152e1591cb485208052993070ac8d2429d" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7378575ff571966e99a744addeff0bff98b8ada0dedf1956d59e634db95eaac1" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "async-channel" -version = "2.1.1" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ca33f4bc4ed1babef42cad36cc1f51fa88be00420404e5b1e80ab1b18f7678c" +checksum = "136d4d23bcc79e27423727b36823d86233aad06dfea531837b038394d11e9928" dependencies = [ "concurrent-queue", - "event-listener 4.0.0", - "event-listener-strategy", + "event-listener 5.3.0", + "event-listener-strategy 0.5.2", "futures-core", "pin-project-lite", ] [[package]] name = "async-executor" -version = "1.8.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ae5ebefcc48e7452b4987947920dac9450be1110cadf34d1b8c116bdbaf97c" +checksum = "b10202063978b3351199d68f8b22c4e47e4b1b822f8d43fd862d5ea8c006b29a" dependencies = [ - "async-lock 3.2.0", "async-task", "concurrent-queue", - "fastrand 2.0.1", - "futures-lite 2.1.0", + "fastrand 2.1.0", + "futures-lite 2.3.0", "slab", ] [[package]] name = "async-global-executor" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4353121d5644cdf2beb5726ab752e79a8db1ebb52031770ec47db31d245526" +checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ "async-channel", "async-executor", - "async-io 2.2.1", - "async-lock 3.2.0", + "async-io 2.3.2", + "async-lock 3.3.0", "blocking", - "futures-lite 2.1.0", + "futures-lite 2.3.0", "once_cell", ] @@ -229,18 +291,18 @@ dependencies = [ [[package]] name = "async-io" -version = "2.2.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6d3b15875ba253d1110c740755e246537483f152fa334f91abd7fe84c88b3ff" +checksum = "dcccb0f599cfa2f8ace422d3555572f47424da5648a4382a9dd0310ff8210884" dependencies = [ - "async-lock 3.2.0", + "async-lock 3.3.0", "cfg-if", "concurrent-queue", "futures-io", - "futures-lite 2.1.0", + "futures-lite 2.3.0", "parking", - "polling 3.3.1", - "rustix 0.38.26", + "polling 3.7.0", + "rustix 0.38.34", "slab", "tracing", "windows-sys 0.52.0", @@ -257,12 +319,12 @@ dependencies = [ [[package]] name = "async-lock" -version = "3.2.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7125e42787d53db9dd54261812ef17e937c95a51e4d291373b670342fa44310c" +checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" dependencies = [ - "event-listener 4.0.0", - "event-listener-strategy", + "event-listener 4.0.3", + "event-listener-strategy 0.4.0", "pin-project-lite", ] @@ -280,19 +342,19 @@ dependencies = [ [[package]] name = "async-task" -version = "4.5.0" +version = "4.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4eb2cdb97421e01129ccb49169d8279ed21e829929144f4a22a6e54ac549ca1" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.74" +version = "0.1.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn", ] [[package]] @@ -307,7 +369,7 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fcf00bc6d5abb29b5f97e3c61a90b6d3caa12f3faf897d4a3e3607c050a35a7" dependencies = [ - "http 0.2.11", + "http 0.2.12", "log", "native-tls", "serde", @@ -317,9 +379,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "aws-creds" @@ -338,6 +400,33 @@ dependencies = [ "url", ] +[[package]] +name = "aws-lc-rs" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8487b59d62764df8231cb371c459314df895b41756df457a1fb1243d65c89195" +dependencies = [ + "aws-lc-sys", + "mirai-annotations", + "paste", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c15eb61145320320eb919d9bab524617a7aa4216c78d342fae3a758bc33073e4" +dependencies = [ + "bindgen", + "cc", + "cmake", + "dunce", + "fs_extra", + "libc", + "paste", +] + [[package]] name = "aws-region" version = "0.25.4" @@ -349,18 +438,18 @@ dependencies = [ [[package]] name = "axum" -version = "0.7.2" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "202651474fe73c62d9e0a56c6133f7a0ff1dc1c8cf7a5b03381af2a26553ac9d" +checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" dependencies = [ "async-trait", "axum-core", "bytes", "futures-util", - "http 1.0.0", + "http 1.1.0", "http-body 1.0.0", "http-body-util", - "hyper 1.0.1", + "hyper 1.3.1", "hyper-util", "itoa", "matchit", @@ -373,38 +462,40 @@ dependencies = [ "serde_json", "serde_path_to_error", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 1.0.1", "tokio", "tower", "tower-layer", "tower-service", + "tracing", ] [[package]] name = "axum-core" -version = "0.4.1" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77cb22c689c44d4c07b0ab44ebc25d69d8ae601a2f28fb8d672d344178fa17aa" +checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" dependencies = [ "async-trait", "bytes", "futures-util", - "http 1.0.0", + "http 1.1.0", "http-body 1.0.0", "http-body-util", "mime", "pin-project-lite", "rustversion", - "sync_wrapper", + "sync_wrapper 0.1.2", "tower-layer", "tower-service", + "tracing", ] [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ "addr2line", "cc", @@ -423,9 +514,44 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.5" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bindgen" +version = "0.69.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" +dependencies = [ + "bitflags 2.5.0", + "cexpr", + "clang-sys", + "itertools", + "lazy_static", + "lazycell", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", + "which", +] [[package]] name = "bitflags" @@ -435,9 +561,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "block-buffer" @@ -459,31 +585,29 @@ dependencies = [ [[package]] name = "blocking" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118" +checksum = "495f7104e962b7356f0aeb34247aca1fe7d2e783b346582db7f2904cb5717e88" dependencies = [ "async-channel", - "async-lock 3.2.0", + "async-lock 3.3.0", "async-task", - "fastrand 2.0.1", "futures-io", - "futures-lite 2.1.0", + "futures-lite 2.3.0", "piper", - "tracing", ] [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytes" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cbc" @@ -496,11 +620,22 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.83" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" dependencies = [ + "jobserver", "libc", + "once_cell", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", ] [[package]] @@ -511,9 +646,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.31" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", @@ -521,7 +656,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.48.5", + "windows-targets 0.52.5", ] [[package]] @@ -534,11 +669,22 @@ dependencies = [ "inout", ] +[[package]] +name = "clang-sys" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "clap" -version = "4.4.11" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ "clap_builder", "clap_derive", @@ -546,9 +692,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.11" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" dependencies = [ "anstream", "anstyle", @@ -558,27 +704,48 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.4.7" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" dependencies = [ - "heck", + "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.39", + "syn", ] [[package]] name = "clap_lex" -version = "0.6.0" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + +[[package]] +name = "cmake" +version = "0.1.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" +dependencies = [ + "cc", +] + +[[package]] +name = "cms" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +checksum = "7b77c319abfd5219629c45c34c89ba945ed3c5e49fcde9d16b6c3885f118a730" +dependencies = [ + "const-oid", + "der", + "spki", + "x509-cert", +] [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" [[package]] name = "colored" @@ -593,9 +760,9 @@ dependencies = [ [[package]] name = "combine" -version = "4.6.6" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" dependencies = [ "bytes", "futures-core", @@ -607,18 +774,24 @@ dependencies = [ [[package]] name = "concurrent-queue" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ "crossbeam-utils", ] +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "cookie-factory" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396de984970346b0d9e93d1415082923c679e5ae5c3ee3dcbd104f5610af126b" +checksum = "9885fa71e26b8ab7855e2ec7cae6e9b380edff76cd052e07c683a0319d51b3a2" [[package]] name = "core-foundation" @@ -638,21 +811,18 @@ checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "cpufeatures" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "crypto-common" @@ -664,6 +834,12 @@ dependencies = [ "typenum", ] +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + [[package]] name = "debugid" version = "0.8.0" @@ -674,11 +850,49 @@ dependencies = [ "uuid", ] +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "der_derive", + "flagset", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "der-parser" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "der_derive" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fe87ce4529967e0ba1dcf8450bab64d97dfd5010a6256187ffe2e43e6f0e049" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "deranged" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eb30d70a07a3b04884d2677f06bec33509dc67ca60d92949e5535352d3191dc" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", "serde", @@ -724,6 +938,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "displaydoc" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "dlv-list" version = "0.3.0" @@ -736,25 +961,37 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +[[package]] +name = "dunce" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" + +[[package]] +name = "either" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" + [[package]] name = "encoding_rs" -version = "0.8.33" +version = "0.8.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" dependencies = [ "cfg-if", ] [[package]] name = "enum_dispatch" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f33313078bb8d4d05a2733a94ac4c2d8a0df9a2b84424ebf4f33bfc224a890e" +checksum = "aa18ce2bc66555b3218614519ac839ddb759a7d6720732f979ef8d13be147ecd" dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.39", + "syn", ] [[package]] @@ -781,9 +1018,20 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "event-listener" -version = "4.0.0" +version = "4.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "770d968249b5d99410d61f5bf89057f3199a077a04d087092f58e7d10692baae" +checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d9944b8ca13534cdfb2800775f8dd4902ff3fc75a50101466decadfdf322a24" dependencies = [ "concurrent-queue", "parking", @@ -796,7 +1044,17 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" dependencies = [ - "event-listener 4.0.0", + "event-listener 4.0.3", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +dependencies = [ + "event-listener 5.3.0", "pin-project-lite", ] @@ -820,9 +1078,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] name = "fern" @@ -848,16 +1106,10 @@ dependencies = [ ] [[package]] -name = "flume" -version = "0.10.14" +name = "flagset" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" -dependencies = [ - "futures-core", - "futures-sink", - "pin-project", - "spin", -] +checksum = "cdeb3aa5e95cf9aabc17f060cfa0ced7b83f042390760ca53bf09df9968acaa1" [[package]] name = "flume" @@ -865,6 +1117,8 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" dependencies = [ + "futures-core", + "futures-sink", "spin", ] @@ -898,11 +1152,17 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "futures" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", @@ -915,9 +1175,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", @@ -925,15 +1185,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", @@ -942,9 +1202,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-lite" @@ -963,11 +1223,11 @@ dependencies = [ [[package]] name = "futures-lite" -version = "2.1.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aeee267a1883f7ebef3700f262d2d54de95dfaf38189015a74fdc4e0c7ad8143" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" dependencies = [ - "fastrand 2.0.1", + "fastrand 2.1.0", "futures-core", "futures-io", "parking", @@ -976,38 +1236,38 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn", ] [[package]] name = "futures-sink" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-timer" -version = "3.0.2" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" [[package]] name = "futures-util" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-channel", "futures-core", @@ -1033,9 +1293,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.11" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -1048,18 +1308,24 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "h2" -version = "0.3.22" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" dependencies = [ "bytes", "fnv", "futures-core", "futures-sink", "futures-util", - "http 0.2.11", + "http 0.2.12", "indexmap", "slab", "tokio", @@ -1069,16 +1335,16 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.0" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d308f63daf4181410c242d34c11f928dcb3aa105852019e043c9d1f4e4368a" +checksum = "816ec7294445779408f36fe57bc5b7fc1cf59664059096c65f905c1c61f58069" dependencies = [ "bytes", "fnv", "futures-core", "futures-sink", "futures-util", - "http 1.0.0", + "http 1.1.0", "indexmap", "slab", "tokio", @@ -1092,14 +1358,14 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash", + "ahash 0.7.8", ] [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "heck" @@ -1107,11 +1373,17 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" -version = "0.3.3" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hex" @@ -1128,22 +1400,31 @@ dependencies = [ "digest", ] +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "hostname" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +checksum = "f9c7c7c8ac16c798734b8a24560c1362120597c40d5e1459f09498f8f6c8f2ba" dependencies = [ + "cfg-if", "libc", - "match_cfg", - "winapi", + "windows", ] [[package]] name = "http" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", @@ -1152,9 +1433,9 @@ dependencies = [ [[package]] name = "http" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" dependencies = [ "bytes", "fnv", @@ -1163,12 +1444,12 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http 0.2.11", + "http 0.2.12", "pin-project-lite", ] @@ -1179,18 +1460,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" dependencies = [ "bytes", - "http 1.0.0", + "http 1.1.0", ] [[package]] name = "http-body-util" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cb79eb393015dadd30fc252023adb0b2400a0caee0fa2a077e6e21a551e840" +checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" dependencies = [ "bytes", - "futures-util", - "http 1.0.0", + "futures-core", + "http 1.1.0", "http-body 1.0.0", "pin-project-lite", ] @@ -1209,22 +1490,22 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.27" +version = "0.14.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" dependencies = [ "bytes", "futures-channel", "futures-core", "futures-util", - "h2 0.3.22", - "http 0.2.11", - "http-body 0.4.5", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", "httparse", "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.10", + "socket2 0.5.7", "tokio", "tower-service", "tracing", @@ -1233,21 +1514,23 @@ dependencies = [ [[package]] name = "hyper" -version = "1.0.1" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403f9214f3e703236b221f1a9cd88ec8b4adfa5296de01ab96216361f4692f56" +checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.0", - "http 1.0.0", + "h2 0.4.4", + "http 1.1.0", "http-body 1.0.0", "httparse", "httpdate", "itoa", "pin-project-lite", + "smallvec", "tokio", + "want", ] [[package]] @@ -1257,26 +1540,42 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper 0.14.27", + "hyper 0.14.28", "native-tls", "tokio", "tokio-native-tls", ] +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper 1.3.1", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + [[package]] name = "hyper-util" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca339002caeb0d159cc6e023dff48e199f081e42fa039895c7c6f38b37f2e9d" +checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.0.0", + "http 1.1.0", "http-body 1.0.0", - "hyper 1.0.1", + "hyper 1.3.1", "pin-project-lite", - "socket2 0.5.5", + "socket2 0.5.7", "tokio", "tower", "tower-service", @@ -1285,9 +1584,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.58" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1318,12 +1617,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.1.0" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown 0.14.5", ] [[package]] @@ -1364,42 +1663,66 @@ checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "is-terminal" -version = "0.4.9" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" dependencies = [ "hermit-abi", - "rustix 0.38.26", - "windows-sys 0.48.0", + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", ] [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "jobserver" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +dependencies = [ + "libc", +] [[package]] name = "js-sys" -version = "0.3.66" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] [[package]] name = "lapin" -version = "2.3.1" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f3067a1fcfbc3fc46455809c023e69b8f6602463201010f4ae5a3b572adb9dc" +checksum = "fae02c316a8a5922ce7518afa6b6c00e9a099f8e59587567e3331efdd11b8ceb" dependencies = [ "amq-protocol", "async-global-executor-trait", "async-reactor-trait", "async-trait", "executor-trait", - "flume 0.10.14", + "flume", "futures-core", "futures-io", "parking_lot", @@ -1416,21 +1739,36 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + [[package]] name = "libc" -version = "0.2.150" +version = "0.2.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" + +[[package]] +name = "libloading" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" +dependencies = [ + "cfg-if", + "windows-targets 0.52.5", +] [[package]] name = "libredox" -version = "0.0.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.5.0", "libc", - "redox_syscall", ] [[package]] @@ -1441,15 +1779,15 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -1457,15 +1795,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" - -[[package]] -name = "match_cfg" -version = "0.1.0" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "matchit" @@ -1475,13 +1807,13 @@ checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" [[package]] name = "maybe-async" -version = "0.2.7" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f1b8c13cb1f814b634a96b2c725449fe7ed464a7b8781de8688be5ffbd3f305" +checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn", ] [[package]] @@ -1502,29 +1834,18 @@ checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" [[package]] name = "memchr" -version = "2.6.4" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "metrics" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e52eb6380b6d2a10eb3434aec0885374490f5b82c8aaf5cd487a183c98be834" -dependencies = [ - "ahash", - "metrics-macros", -] - -[[package]] -name = "metrics-macros" -version = "0.5.1" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49e30813093f757be5cf21e50389a24dc7dbb22c49f23b7e8f51d69b508a5ffa" +checksum = "2be3cbd384d4e955b231c895ce10685e3d8260c5ccffae898c96c723b0772835" dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "ahash 0.8.11", + "portable-atomic", ] [[package]] @@ -1560,29 +1881,35 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "wasi", "windows-sys 0.48.0", ] +[[package]] +name = "mirai-annotations" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9be0862c1b3f26a88803c4a49de6889c10e608b3ee9344e6ef5b45fb37ad3d1" + [[package]] name = "mobc" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90eb49dc5d193287ff80e72a86f34cfb27aae562299d22fea215e06ea1059dd3" +checksum = "d8d3681f0b299413df040f53c6950de82e48a8e1a9f79d442ed1ad3694d660b9" dependencies = [ "async-trait", "futures-channel", @@ -1635,11 +1962,36 @@ dependencies = [ "winapi", ] +[[package]] +name = "num-bigint" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] @@ -1655,12 +2007,21 @@ dependencies = [ ] [[package]] -name = "object" -version = "0.32.1" +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + +[[package]] +name = "oid-registry" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +checksum = "1c958dd45046245b9c3c2547369bb634eb461670b2e7e0de552905801a648d1d" dependencies = [ - "memchr", + "asn1-rs", ] [[package]] @@ -1671,11 +2032,11 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "openssl" -version = "0.10.61" +version = "0.10.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b8419dc8cc6d866deb801274bba2e6f8f6108c1bb7fcc10ee5ab864931dbb45" +checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.5.0", "cfg-if", "foreign-types", "libc", @@ -1692,7 +2053,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn", ] [[package]] @@ -1703,9 +2064,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.97" +version = "0.9.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3eaad34cdd97d81de97964fc7f29e2d104f483840d906ef56daa1912338460b" +checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" dependencies = [ "cc", "libc", @@ -1725,13 +2086,13 @@ dependencies = [ [[package]] name = "os_info" -version = "3.7.0" +version = "3.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "006e42d5b888366f1880eda20371fedde764ed2213dc8496f49622fa0c99cd5e" +checksum = "ae99c7fa6dd38c7cafe1ec085e804f8f555a2f8659b0dbe03f1f9963a9b51092" dependencies = [ "log", "serde", - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -1741,20 +2102,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] -name = "p12" -version = "0.6.3" +name = "p12-keystore" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4873306de53fe82e7e484df31e1e947d61514b6ea2ed6cd7b45d63006fd9224" +checksum = "fbd7792ed56836118732faffa19b8c2bb20d5f3ff8b403002cd817d6c4ffc96c" dependencies = [ "cbc", - "cipher", + "cms", + "der", "des", - "getrandom", + "hex", "hmac", - "lazy_static", + "pkcs12", + "pkcs5", + "rand", "rc2", "sha1", - "yasna", + "sha2", + "thiserror", + "x509-parser", ] [[package]] @@ -1765,9 +2131,9 @@ checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" dependencies = [ "lock_api", "parking_lot_core", @@ -1775,15 +2141,40 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.48.5", + "windows-targets 0.52.5", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest", + "hmac", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", ] [[package]] @@ -1794,29 +2185,29 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project" -version = "1.1.3" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.3" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn", ] [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -1831,7 +2222,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6cfae3ead413ca051a681152bd266438d3bfa301c9bdf836939a14c721bb2a21" dependencies = [ "doc-comment", - "flume 0.11.0", + "flume", "parking_lot", "tracing", ] @@ -1843,15 +2234,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" dependencies = [ "atomic-waker", - "fastrand 2.0.1", + "fastrand 2.1.0", "futures-io", ] +[[package]] +name = "pkcs12" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "695b3df3d3cc1015f12d70235e35b6b79befc5fa7a9b95b951eab1dd07c9efc2" +dependencies = [ + "cms", + "const-oid", + "der", + "digest", + "spki", + "x509-cert", + "zeroize", +] + +[[package]] +name = "pkcs5" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e847e2c91a18bfa887dd028ec33f2fe6f25db77db3619024764914affe8b69a6" +dependencies = [ + "aes", + "cbc", + "der", + "pbkdf2", + "scrypt", + "sha2", + "spki", +] + [[package]] name = "pkg-config" -version = "0.3.27" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "polling" @@ -1871,18 +2292,25 @@ dependencies = [ [[package]] name = "polling" -version = "3.3.1" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf63fa624ab313c11656b4cda960bfc46c410187ad493c41f6ba2d8c1e991c9e" +checksum = "645493cf344456ef24219d02a768cf1fb92ddf8c92161679ae3d91b91a637be3" dependencies = [ "cfg-if", "concurrent-queue", + "hermit-abi", "pin-project-lite", - "rustix 0.38.26", + "rustix 0.38.34", "tracing", "windows-sys 0.52.0", ] +[[package]] +name = "portable-atomic" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" + [[package]] name = "powerfmt" version = "0.2.0" @@ -1895,11 +2323,21 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "prettyplease" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" +dependencies = [ + "proc-macro2", + "syn", +] + [[package]] name = "proc-macro2" -version = "1.0.70" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" dependencies = [ "unicode-ident", ] @@ -1916,9 +2354,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.33" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -1975,9 +2413,9 @@ dependencies = [ [[package]] name = "redis" -version = "0.24.0" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c580d9cbbe1d1b479e8d67cf9daf6a62c957e6846048408b80b43ac3f6af84cd" +checksum = "6472825949c09872e8f2c50bde59fcefc17748b6be5c90fd67cd8b4daca73bfd" dependencies = [ "arc-swap", "async-trait", @@ -1990,7 +2428,7 @@ dependencies = [ "pin-project-lite", "ryu", "sha1_smol", - "socket2 0.4.10", + "socket2 0.5.7", "tokio", "tokio-retry", "tokio-util", @@ -1999,18 +2437,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", ] [[package]] name = "redox_users" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" dependencies = [ "getrandom", "libredox", @@ -2019,9 +2457,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.2" +version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", @@ -2031,9 +2469,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.3" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", @@ -2042,26 +2480,26 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "reqwest" -version = "0.11.22" +version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ - "base64 0.21.5", + "base64 0.21.7", "bytes", "encoding_rs", "futures-core", "futures-util", - "h2 0.3.22", - "http 0.2.11", - "http-body 0.4.5", - "hyper 0.14.27", - "hyper-tls", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.28", + "hyper-tls 0.5.0", "ipnet", "js-sys", "log", @@ -2070,9 +2508,11 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", + "sync_wrapper 0.1.2", "system-configuration", "tokio", "tokio-native-tls", @@ -2083,21 +2523,65 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "winreg", + "winreg 0.50.0", +] + +[[package]] +name = "reqwest" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" +dependencies = [ + "base64 0.22.1", + "bytes", + "encoding_rs", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.4.4", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", + "hyper 1.3.1", + "hyper-tls 0.6.0", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile 2.1.2", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 0.1.2", + "system-configuration", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg 0.52.0", ] [[package]] name = "ring" -version = "0.17.7" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", + "cfg-if", "getrandom", "libc", "spin", "untrusted", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -2125,14 +2609,14 @@ dependencies = [ "futures", "hex", "hmac", - "http 0.2.11", + "http 0.2.12", "log", "maybe-async", "md5", "minidom", "percent-encoding", "quick-xml", - "reqwest", + "reqwest 0.11.27", "serde", "serde_derive", "sha2", @@ -2145,9 +2629,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" @@ -2164,6 +2648,15 @@ dependencies = [ "semver", ] +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + [[package]] name = "rustix" version = "0.37.27" @@ -2180,49 +2673,54 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.26" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.5.0", "errno", "libc", - "linux-raw-sys 0.4.12", + "linux-raw-sys 0.4.13", "windows-sys 0.52.0", ] [[package]] name = "rustls" -version = "0.21.9" +version = "0.23.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "629648aced5775d558af50b2b4c7b02983a04b312126d45eeead26e7caa498b9" +checksum = "afabcee0551bd1aa3e18e5adbf2c0544722014b899adb31bd186ec638d3da97e" dependencies = [ + "aws-lc-rs", "log", - "ring", + "once_cell", + "rustls-pki-types", "rustls-webpki", - "sct", + "subtle", + "zeroize", ] [[package]] name = "rustls-connector" -version = "0.18.5" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25da151615461c7347114b1ad1a7458b4cdebc69cb220cd140cd5cb324b1dd37" +checksum = "727a826801254b6cfcd2508a0508c01b7c1bca21d3673e84d86da084781b83d5" dependencies = [ "log", "rustls", "rustls-native-certs", + "rustls-pki-types", "rustls-webpki", ] [[package]] name = "rustls-native-certs" -version = "0.6.3" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792" dependencies = [ "openssl-probe", - "rustls-pemfile", + "rustls-pemfile 2.1.2", + "rustls-pki-types", "schannel", "security-framework", ] @@ -2233,16 +2731,34 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64 0.21.5", + "base64 0.21.7", +] + +[[package]] +name = "rustls-pemfile" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +dependencies = [ + "base64 0.22.1", + "rustls-pki-types", ] +[[package]] +name = "rustls-pki-types" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" + [[package]] name = "rustls-webpki" -version = "0.101.7" +version = "0.102.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +checksum = "f3bce581c0dd41bce533ce695a1437fa16a7ab5ac3ccfa99fe1a620a7885eabf" dependencies = [ + "aws-lc-rs", "ring", + "rustls-pki-types", "untrusted", ] @@ -2252,7 +2768,7 @@ version = "0.7.6" dependencies = [ "async-trait", "axum", - "base64 0.21.5", + "base64 0.22.1", "bytes", "chrono", "clap", @@ -2267,7 +2783,7 @@ dependencies = [ "mime_guess", "mobc", "redis", - "reqwest", + "reqwest 0.12.4", "rust-s3", "rustc-hash", "sentry", @@ -2292,9 +2808,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.14" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +checksum = "092474d1a01ea8278f69e6a358998405fae5b8b963ddaeb2b0b04a128bf1dfb0" [[package]] name = "rxml" @@ -2315,17 +2831,26 @@ checksum = "22a197350ece202f19a166d1ad6d9d6de145e1d2a8ef47db299abe164dbd7530" [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "salsa20" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] [[package]] name = "schannel" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -2335,22 +2860,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] -name = "sct" -version = "0.7.1" +name = "scrypt" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" dependencies = [ - "ring", - "untrusted", + "pbkdf2", + "salsa20", + "sha2", ] [[package]] name = "security-framework" -version = "2.9.2" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", "core-foundation", "core-foundation-sys", "libc", @@ -2359,9 +2885,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.9.1" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" dependencies = [ "core-foundation-sys", "libc", @@ -2369,19 +2895,19 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.20" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "sentry" -version = "0.32.0" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b596ee5f4e76638de6063ca96fd3d923675416461fc7f1b77406dc2f32d1979" +checksum = "00421ed8fa0c995f07cde48ba6c89e80f2b312f74ff637326f392fbfd23abe02" dependencies = [ "httpdate", "native-tls", - "reqwest", + "reqwest 0.12.4", "sentry-backtrace", "sentry-contexts", "sentry-core", @@ -2394,9 +2920,9 @@ dependencies = [ [[package]] name = "sentry-backtrace" -version = "0.32.0" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6510a97162c288989a6310766bcadfc83ec98ad73121674463b055c42189e85" +checksum = "a79194074f34b0cbe5dd33896e5928bbc6ab63a889bd9df2264af5acb186921e" dependencies = [ "backtrace", "once_cell", @@ -2406,9 +2932,9 @@ dependencies = [ [[package]] name = "sentry-contexts" -version = "0.32.0" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e2552a4a578aade01bd44691e6805c32bac34fc918f1675739fbbf2add8460" +checksum = "eba8870c5dba2bfd9db25c75574a11429f6b95957b0a78ac02e2970dd7a5249a" dependencies = [ "hostname", "libc", @@ -2420,9 +2946,9 @@ dependencies = [ [[package]] name = "sentry-core" -version = "0.32.0" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebb7a6ad833035f6b36db3e61e450643eec8a3c5f2839b8e41c74a73e57c6bae" +checksum = "46a75011ea1c0d5c46e9e57df03ce81f5c7f0a9e199086334a1f9c0a541e0826" dependencies = [ "once_cell", "rand", @@ -2433,9 +2959,9 @@ dependencies = [ [[package]] name = "sentry-debug-images" -version = "0.32.0" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bcd02214397892a3ec25372cc68c210d858f39314535f5d640bdf41294fd441" +checksum = "7ec2a486336559414ab66548da610da5e9626863c3c4ffca07d88f7dc71c8de8" dependencies = [ "findshlibs", "once_cell", @@ -2444,9 +2970,9 @@ dependencies = [ [[package]] name = "sentry-panic" -version = "0.32.0" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0866e2ba7615fe37e0e485f2373bf9dabbb255f82637b5fe47902095790bbbc9" +checksum = "2eaa3ecfa3c8750c78dcfd4637cfa2598b95b52897ed184b4dc77fcf7d95060d" dependencies = [ "sentry-backtrace", "sentry-core", @@ -2454,12 +2980,12 @@ dependencies = [ [[package]] name = "sentry-tower" -version = "0.32.0" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e275f07e9e7d9cf3b85130ab6893a9790c3ab2d8fedca29215aeafad0539c4f4" +checksum = "df141464944fdf8e2a6f2184eb1d973a20456466f788346b6e3a51791cdaa370" dependencies = [ "axum", - "http 1.0.0", + "http 1.1.0", "pin-project", "sentry-core", "tower-layer", @@ -2469,9 +2995,9 @@ dependencies = [ [[package]] name = "sentry-tracing" -version = "0.32.0" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53ef38653386354058f30b3c6d0bf764c59ee6270cd769ac4620a2d2fd60c8fe" +checksum = "f715932bf369a61b7256687c6f0554141b7ce097287e30e3f7ed6e9de82498fe" dependencies = [ "sentry-backtrace", "sentry-core", @@ -2481,9 +3007,9 @@ dependencies = [ [[package]] name = "sentry-types" -version = "0.32.0" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26342e85c6b3332273b820d5be6b93027fe991ded23a2aa6fb88a5a28c845c40" +checksum = "4519c900ce734f7a0eb7aba0869dfb225a7af8820634a7dd51449e3b093cfb7c" dependencies = [ "debugid", "hex", @@ -2498,29 +3024,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.193" +version = "1.0.201" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.201" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn", ] [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ "itoa", "ryu", @@ -2529,9 +3055,9 @@ dependencies = [ [[package]] name = "serde_path_to_error" -version = "0.1.14" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4beec8bce849d58d06238cb50db2e1c417cfeafa4c63f692b15c82b7c80f8335" +checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" dependencies = [ "itoa", "serde", @@ -2586,11 +3112,17 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ "libc", ] @@ -2606,9 +3138,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.2" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "smartstring" @@ -2633,12 +3165,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.5" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -2650,6 +3182,16 @@ dependencies = [ "lock_api", ] +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "static_assertions" version = "1.1.0" @@ -2658,30 +3200,30 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" -version = "0.25.0" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" -version = "0.25.3" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro2", "quote", "rustversion", - "syn 2.0.39", + "syn", ] [[package]] @@ -2692,9 +3234,9 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" -version = "1.0.109" +version = "2.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +checksum = "c993ed8ccba56ae856363b1845da7266a7cb78e1d146c8a32d54b45a8b831fc9" dependencies = [ "proc-macro2", "quote", @@ -2702,21 +3244,27 @@ dependencies = [ ] [[package]] -name = "syn" -version = "2.0.39" +name = "sync_wrapper" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] name = "sync_wrapper" -version = "0.1.2" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "system-configuration" @@ -2741,54 +3289,53 @@ dependencies = [ [[package]] name = "tcp-stream" -version = "0.26.1" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4da30af7998f51ee1aa48ab24276fe303a697b004e31ff542b192c088d5630a5" +checksum = "495b0abdce3dc1f8fd27240651c9e68890c14e9d9c61527b1ce44d8a5a7bd3d5" dependencies = [ "cfg-if", - "p12", + "p12-keystore", "rustls-connector", - "rustls-pemfile", + "rustls-pemfile 2.1.2", ] [[package]] name = "tempfile" -version = "3.8.1" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", - "fastrand 2.0.1", - "redox_syscall", - "rustix 0.38.26", - "windows-sys 0.48.0", + "fastrand 2.1.0", + "rustix 0.38.34", + "windows-sys 0.52.0", ] [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn", ] [[package]] name = "thread_local" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ "cfg-if", "once_cell", @@ -2816,12 +3363,13 @@ dependencies = [ [[package]] name = "time" -version = "0.3.30" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa", + "num-conv", "powerfmt", "serde", "time-core", @@ -2836,10 +3384,11 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.15" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ + "num-conv", "time-core", ] @@ -2860,9 +3409,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.34.0" +version = "1.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" dependencies = [ "backtrace", "bytes", @@ -2872,7 +3421,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.5", + "socket2 0.5.7", "tokio-macros", "windows-sys 0.48.0", ] @@ -2885,7 +3434,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn", ] [[package]] @@ -2911,9 +3460,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" dependencies = [ "futures-core", "pin-project-lite", @@ -2922,16 +3471,15 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.10" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" dependencies = [ "bytes", "futures-core", "futures-sink", "pin-project-lite", "tokio", - "tracing", ] [[package]] @@ -2952,14 +3500,13 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09e12e6351354851911bdf8c2b8f2ab15050c567d70a8b9a37ae7b8301a4080d" +checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.5.0", "bytes", - "futures-util", - "http 1.0.0", + "http 1.1.0", "http-body 1.0.0", "http-body-util", "pin-project-lite", @@ -3000,7 +3547,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn", ] [[package]] @@ -3072,9 +3619,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" @@ -3084,9 +3631,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] @@ -3099,11 +3646,11 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "2.9.1" +version = "2.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cdd25c339e200129fe4de81451814e5228c9b771d57378817d6117cc2b3f97" +checksum = "d11a831e3c0b56e438a28308e7c810799e3c118417f342d30ecec080105395cd" dependencies = [ - "base64 0.21.5", + "base64 0.22.1", "log", "native-tls", "once_cell", @@ -3130,9 +3677,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.6.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" dependencies = [ "getrandom", "serde", @@ -3179,9 +3726,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.89" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -3189,24 +3736,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.89" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.39", + "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.39" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ "cfg-if", "js-sys", @@ -3216,9 +3763,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.89" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3226,28 +3773,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.89" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.89" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "wasm-streams" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4609d447824375f43e1ffbc051b50ad8f4b3ae8219680c94452ea05eb240ac7" +checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" dependencies = [ "futures-util", "js-sys", @@ -3258,19 +3805,31 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.66" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", ] +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix 0.38.34", +] + [[package]] name = "wildmatch" -version = "2.1.1" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee583bdc5ff1cf9db20e9db5bb3ff4c3089a8f6b8b31aff265c9aba85812db86" +checksum = "939e59c1bc731542357fdaad98b209ef78c8743d652bb61439d16b16a79eb025" [[package]] name = "winapi" @@ -3294,13 +3853,23 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +dependencies = [ + "windows-core", + "windows-targets 0.52.5", +] + [[package]] name = "windows-core" -version = "0.51.1" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.48.5", + "windows-targets 0.52.5", ] [[package]] @@ -3318,7 +3887,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.5", ] [[package]] @@ -3338,17 +3907,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] [[package]] @@ -3359,9 +3929,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" @@ -3371,9 +3941,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" @@ -3383,9 +3953,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" @@ -3395,9 +3971,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" @@ -3407,9 +3983,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" @@ -3419,9 +3995,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" @@ -3431,9 +4007,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winreg" @@ -3446,7 +4022,65 @@ dependencies = [ ] [[package]] -name = "yasna" -version = "0.5.2" +name = "winreg" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "x509-cert" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1301e935010a701ae5f8655edc0ad17c44bad3ac5ce8c39185f75453b720ae94" +dependencies = [ + "const-oid", + "der", + "spki", +] + +[[package]] +name = "x509-parser" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" +dependencies = [ + "asn1-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "rusticata-macros", + "thiserror", + "time", +] + +[[package]] +name = "zerocopy" +version = "0.7.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zeroize" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/Cargo.toml b/Cargo.toml index 639fc25..21f5e73 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ path = "src/main.rs" [dependencies] async-trait = "0.1.74" axum = { version = "0.7.1" } -base64 = "0.21.5" +base64 = "0.22.1" bytes = "1.5.0" chrono = { version = "0.4.26", features = ["serde"] } clap = { version = "4.3.21", features = ["env", "derive"] } @@ -28,11 +28,11 @@ log = "0.4.20" mime = "0.3.17" mime_guess = "2.0.4" mobc = "0.8.3" -redis = { version = "0.24.0", features = ["tokio-comp", "connection-manager"] } +redis = { version = "0.25.3", features = ["tokio-comp", "connection-manager"] } rustc-hash = "1.1.0" serde = { version = "1.0.192", features = ["derive"] } serde_json = "1.0.108" -strum = { version = "0.25.0", features = ["derive"] } +strum = { version = "0.26.2", features = ["derive"] } thiserror = "1.0.50" tokio = { version = "1.31.0", features = ["full", "bytes"] } tokio-util = { version = "0.7.10", features = ["io"] } @@ -44,7 +44,7 @@ sha1 = { version = "^0.10.1", features = ["compress"] } sha2 = { version = "^0.10.1", features = ["compress"] } md-5 = "^0.10.1" digest = "^0.10.1" -reqwest = "0.11.22" +reqwest = "0.12.4" lapin = "2.3.1" tower-http = { version = "0.5.0", features = ["cors", "trace"] } wildmatch = "2.1.1" diff --git a/src/errors.rs b/src/errors.rs index 8b2c2e8..f7fb8b3 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -69,7 +69,6 @@ pub enum RustusError { } /// This conversion allows us to use `RustusError` in the `main` function. -#[cfg_attr(coverage, no_coverage)] impl From for Error { fn from(err: RustusError) -> Self { Error::new(ErrorKind::Other, err) diff --git a/src/info_storages/impls/redis_info_storage.rs b/src/info_storages/impls/redis_info_storage.rs index 20c5926..81ab10d 100644 --- a/src/info_storages/impls/redis_info_storage.rs +++ b/src/info_storages/impls/redis_info_storage.rs @@ -1,5 +1,5 @@ use mobc::{Manager, Pool}; -use redis::aio::Connection; +use redis::aio::MultiplexedConnection; use crate::{ errors::{RustusError, RustusResult}, @@ -19,11 +19,11 @@ impl RedisConnectionManager { #[async_trait::async_trait] impl Manager for RedisConnectionManager { - type Connection = redis::aio::Connection; + type Connection = redis::aio::MultiplexedConnection; type Error = redis::RedisError; async fn connect(&self) -> Result { - Ok(self.client.get_async_connection().await?) + Ok(self.client.get_multiplexed_async_connection().await?) } async fn check(&self, mut conn: Self::Connection) -> Result { @@ -69,7 +69,8 @@ impl InfoStorage for RedisStorage { if let Some(expiration) = self.expiration.as_ref() { cmd = cmd.arg("EX").arg(expiration); } - cmd.query_async::(&mut conn).await?; + cmd.query_async::(&mut conn) + .await?; Ok(()) } @@ -77,7 +78,7 @@ impl InfoStorage for RedisStorage { let mut conn = self.pool.get().await?; let res = redis::cmd("GET") .arg(file_id) - .query_async::>(&mut conn) + .query_async::>(&mut conn) .await?; if let Some(res) = res { @@ -91,7 +92,7 @@ impl InfoStorage for RedisStorage { let mut conn = self.pool.get().await?; let resp = redis::cmd("DEL") .arg(file_id) - .query_async::>(&mut conn) + .query_async::>(&mut conn) .await?; match resp { None | Some(0) => Err(RustusError::FileNotFound), diff --git a/src/main.rs b/src/main.rs index 90fee77..f91300b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,7 +19,6 @@ pub mod utils; #[global_allocator] static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; -#[cfg_attr(coverage, no_coverage)] fn greeting(app_conf: &config::Config) { let extensions = app_conf .tus_extensions diff --git a/src/notifiers/impls/dir_notifier.rs b/src/notifiers/impls/dir_notifier.rs index 7d97779..5285112 100644 --- a/src/notifiers/impls/dir_notifier.rs +++ b/src/notifiers/impls/dir_notifier.rs @@ -20,7 +20,6 @@ impl DirNotifier { } impl Notifier for DirNotifier { - #[cfg_attr(coverage, no_coverage)] async fn prepare(&mut self) -> RustusResult<()> { Ok(()) } diff --git a/src/notifiers/impls/file_notifier.rs b/src/notifiers/impls/file_notifier.rs index fe8dc46..f75425c 100644 --- a/src/notifiers/impls/file_notifier.rs +++ b/src/notifiers/impls/file_notifier.rs @@ -19,7 +19,6 @@ impl FileNotifier { } impl Notifier for FileNotifier { - #[cfg_attr(coverage, no_coverage)] async fn prepare(&mut self) -> RustusResult<()> { Ok(()) } diff --git a/src/notifiers/impls/http_notifier.rs b/src/notifiers/impls/http_notifier.rs index ec97835..c244a2d 100644 --- a/src/notifiers/impls/http_notifier.rs +++ b/src/notifiers/impls/http_notifier.rs @@ -29,7 +29,6 @@ impl HttpNotifier { } impl Notifier for HttpNotifier { - #[cfg_attr(coverage, no_coverage)] async fn prepare(&mut self) -> RustusResult<()> { Ok(()) } From 23828d82765223d4dcd47705af69007b1ae3ba4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Kla=C4=8Dan?= Date: Fri, 17 May 2024 18:22:04 +0200 Subject: [PATCH 7/9] Docker - Update base images (#152) --- deploy/Dockerfile | 4 ++-- deploy/alpine.Dockerfile | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/deploy/Dockerfile b/deploy/Dockerfile index cccf690..4997dc6 100644 --- a/deploy/Dockerfile +++ b/deploy/Dockerfile @@ -1,4 +1,4 @@ -FROM rustlang/rust:buster AS builder +FROM rust:buster AS builder WORKDIR /app COPY Cargo.toml Cargo.lock ./ @@ -8,7 +8,7 @@ COPY imgs ./imgs ENV JEMALLOC_SYS_WITH_MALLOC_CONF="background_thread:true,metadata_thp:always,tcache:false,dirty_decay_ms:0,muzzy_decay_ms:0,abort_conf:true" RUN cargo build --release --bin rustus -FROM debian:bullseye-20231120-slim AS base +FROM debian:bookworm-20240513-slim AS base COPY --from=builder /app/target/release/rustus /usr/local/bin/ RUN apt update && apt install -y libssl-dev ca-certificates libjemalloc-dev && apt clean diff --git a/deploy/alpine.Dockerfile b/deploy/alpine.Dockerfile index f2309ca..9279a32 100644 --- a/deploy/alpine.Dockerfile +++ b/deploy/alpine.Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.15.0 as base +FROM alpine:3.19.1 as base ARG app_version @@ -14,4 +14,4 @@ FROM base as rootless RUN adduser -u 1000 --disabled-password rustus WORKDIR /home/rustus -USER rustus \ No newline at end of file +USER rustus From 3131cf589a305377fe3fdc53baf8ed0f168468b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Kla=C4=8Dan?= Date: Tue, 21 May 2024 11:12:19 +0200 Subject: [PATCH 8/9] Fix docker image (#153) --- deploy/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/Dockerfile b/deploy/Dockerfile index 4997dc6..4dc3262 100644 --- a/deploy/Dockerfile +++ b/deploy/Dockerfile @@ -1,4 +1,4 @@ -FROM rust:buster AS builder +FROM rust:bookworm AS builder WORKDIR /app COPY Cargo.toml Cargo.lock ./ From ab047aeeabf6fed28dbba1d0daf493cbb9b141f2 Mon Sep 17 00:00:00 2001 From: Rene Klacan Date: Wed, 22 May 2024 22:37:35 +0200 Subject: [PATCH 9/9] Helm Chart - Tweaks & Fixes - Switch from deployment to stateful set (this fixes more than 1 replica) - Support secrets --- deploy/helm/templates/pvc.yml | 30 ----------- .../{deployment.yaml => statefulset.yaml} | 52 ++++++++++++++----- deploy/helm/values.yaml | 4 +- 3 files changed, 41 insertions(+), 45 deletions(-) delete mode 100644 deploy/helm/templates/pvc.yml rename deploy/helm/templates/{deployment.yaml => statefulset.yaml} (63%) diff --git a/deploy/helm/templates/pvc.yml b/deploy/helm/templates/pvc.yml deleted file mode 100644 index 5836d74..0000000 --- a/deploy/helm/templates/pvc.yml +++ /dev/null @@ -1,30 +0,0 @@ -{{- if and (.Values.persistence.enabled) (not .Values.persistence.existingClaim) }} -kind: PersistentVolumeClaim -apiVersion: v1 -metadata: - name: {{ printf "rustus-data-%s" (include "rustus.fullname" .) }} - labels: - {{- include "rustus.selectorLabels" . | nindent 4 }} - {{- if .Values.persistence.annotations }} - annotations: {{- toYaml .Values.persistence.annotations | nindent 4 }} - {{- end }} -spec: - storageClassName: {{ .Values.persistence.storageClass }} - accessModes: - {{- range .Values.persistence.accessModes }} - - {{ . | quote }} - {{- end }} - {{- with .Values.persistence.dataSource }} - dataSource: - {{ . | toYaml | nindent 4 }} - {{- end }} - {{- with .Values.persistence.selector }} - selector: - {{- . | toYaml | nindent 4 }} - {{- end }} - mountOptions: - {{- .Values.persistence.mountOptions | toYaml | nindent 4 }} - resources: - requests: - storage: {{ .Values.persistence.size | quote }} -{{- end }} \ No newline at end of file diff --git a/deploy/helm/templates/deployment.yaml b/deploy/helm/templates/statefulset.yaml similarity index 63% rename from deploy/helm/templates/deployment.yaml rename to deploy/helm/templates/statefulset.yaml index 320d368..8b6b859 100644 --- a/deploy/helm/templates/deployment.yaml +++ b/deploy/helm/templates/statefulset.yaml @@ -1,10 +1,11 @@ apiVersion: apps/v1 -kind: Deployment +kind: StatefulSet metadata: name: {{ include "rustus.fullname" . }} labels: {{- include "rustus.labels" . | nindent 4 }} spec: + serviceName: {{ include "rustus.fullname" . }} {{- if not .Values.autoscaling.enabled }} replicas: {{ .Values.replicaCount }} {{- end }} @@ -45,13 +46,15 @@ spec: httpGet: path: /health port: http - {{- with .Values.env }} env: - {{- range $key, $val := . }} + {{- range $key, $val := .Values.env }} - name: {{ $key | quote }} value: {{ $val | quote }} {{- end }} - {{- end }} + {{- range $key, $value := .Values.secrets }} + - name: {{ $key }} + valueFrom: { secretKeyRef: { name: {{ $value.from }}, key: {{ $value.key }} } } + {{- end }} {{- if .Values.persistence.enabled }} volumeMounts: - name: data @@ -59,16 +62,6 @@ spec: {{- end }} resources: {{- toYaml .Values.resources | nindent 12 }} - {{- if .Values.persistence.enabled }} - volumes: - - name: data - persistentVolumeClaim: - {{- if .Values.persistence.existingClaim }} - claimName: {{ .Values.persistence.existingClaim }} - {{- else }} - claimName: {{ printf "rustus-data-%s" (include "rustus.fullname" .) }} - {{- end }} - {{- end }} {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} @@ -81,3 +74,34 @@ spec: tolerations: {{- toYaml . | nindent 8 }} {{- end }} + + {{- if .Values.persistence.enabled }} + volumeClaimTemplates: + - metadata: + name: data + labels: + {{- include "rustus.selectorLabels" . | nindent 10 }} + {{- if .Values.persistence.annotations }} + annotations: + {{- toYaml .Values.persistence.annotations | nindent 10 }} + {{- end }} + spec: + storageClassName: {{ .Values.persistence.storageClass }} + accessModes: + {{- range .Values.persistence.accessModes }} + - {{ . | quote }} + {{- end }} + {{- with .Values.persistence.dataSource }} + dataSource: + {{ . | toYaml | nindent 10 }} + {{- end }} + {{- with .Values.persistence.selector }} + selector: + {{- . | toYaml | nindent 10 }} + {{- end }} + mountOptions: + {{- .Values.persistence.mountOptions | toYaml | nindent 10 }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} + {{- end }} diff --git a/deploy/helm/values.yaml b/deploy/helm/values.yaml index 6438816..5b324c7 100644 --- a/deploy/helm/values.yaml +++ b/deploy/helm/values.yaml @@ -31,6 +31,8 @@ env: # RUSTUS_INFO_STORAGE: db-info-storage # RUSTUS_INFO_DB_DSN: mysql://rustus:rustus@rustus-mysql/rustus +secrets: [] + persistence: enabled: false @@ -191,4 +193,4 @@ service_monitor: scrapeTimeout: "" honorLabels: "" relabellings: {} - metricRelabelings: {} \ No newline at end of file + metricRelabelings: {}