From 1cd607f5b52cb59805bdd98314d2f47b182b9b8a Mon Sep 17 00:00:00 2001 From: DecDuck Date: Sat, 13 Dec 2025 14:04:35 +1100 Subject: [PATCH 01/22] initial commit --- cli/.gitignore | 1 + cli/Cargo.toml | 6 ++++++ cli/README.md | 2 ++ cli/src/main.rs | 3 +++ 4 files changed, 12 insertions(+) create mode 100644 cli/.gitignore create mode 100644 cli/Cargo.toml create mode 100644 cli/README.md create mode 100644 cli/src/main.rs diff --git a/cli/.gitignore b/cli/.gitignore new file mode 100644 index 00000000..ea8c4bf7 --- /dev/null +++ b/cli/.gitignore @@ -0,0 +1 @@ +/target diff --git a/cli/Cargo.toml b/cli/Cargo.toml new file mode 100644 index 00000000..15974bd0 --- /dev/null +++ b/cli/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "downpour" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/cli/README.md b/cli/README.md new file mode 100644 index 00000000..3bb5aaa6 --- /dev/null +++ b/cli/README.md @@ -0,0 +1,2 @@ +# downpour +A cli tool to upload local files to Drop's depot infrastructure. diff --git a/cli/src/main.rs b/cli/src/main.rs new file mode 100644 index 00000000..e7a11a96 --- /dev/null +++ b/cli/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} From aa21a779ffc063b3434c238688b06d17449decf8 Mon Sep 17 00:00:00 2001 From: DecDuck Date: Sat, 13 Dec 2025 21:29:41 +1100 Subject: [PATCH 02/22] feat: basics --- cli/Cargo.lock | 1128 +++++++++++++++++++++++++++++++++++++++++++++++ cli/Cargo.toml | 3 + cli/src/main.rs | 41 +- 3 files changed, 1170 insertions(+), 2 deletions(-) create mode 100644 cli/Cargo.lock diff --git a/cli/Cargo.lock b/cli/Cargo.lock new file mode 100644 index 00000000..bf8e0da3 --- /dev/null +++ b/cli/Cargo.lock @@ -0,0 +1,1128 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + +[[package]] +name = "asn1-rs" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048" +dependencies = [ + "asn1-rs-derive 0.5.1", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror 1.0.69", + "time", +] + +[[package]] +name = "asn1-rs" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56624a96882bb8c26d61312ae18cb45868e5a9992ea73c58e45c3101e56a1e60" +dependencies = [ + "asn1-rs-derive 0.6.0", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror 2.0.17", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" +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 = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + +[[package]] +name = "bytes" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" + +[[package]] +name = "cc" +version = "1.2.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "console" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b430743a6eb14e9764d4260d4c0d8123087d504eeb9c48f2b2a5e810dd369df4" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "unicode-width", + "windows-sys 0.61.2", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "data-encoding" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" + +[[package]] +name = "der-parser" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" +dependencies = [ + "asn1-rs 0.6.2", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "der-parser" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" +dependencies = [ + "asn1-rs 0.7.1", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "deranged" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "downpour" +version = "0.1.0" +dependencies = [ + "droplet-rs", + "indicatif", + "tokio", +] + +[[package]] +name = "droplet-rs" +version = "0.11.1" +source = "git+https://github.com/Drop-OSS/droplet-rs.git#3e782bf29eb4bed7e31cfb7f8dfef4babf34fa9c" +dependencies = [ + "anyhow", + "async-trait", + "dyn-clone", + "futures", + "hex", + "humansize", + "rcgen", + "ring", + "serde", + "serde_json", + "sha2", + "time", + "tokio", + "uuid", + "x509-parser 0.17.0", +] + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + +[[package]] +name = "find-msvc-tools" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "humansize" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" +dependencies = [ + "libm", +] + +[[package]] +name = "indicatif" +version = "0.18.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9375e112e4b463ec1b1c6c011953545c65a30164fbab5b581df32b3abf0dcb88" +dependencies = [ + "console", + "portable-atomic", + "unicode-width", + "unit-prefix", + "web-time", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "js-sys" +version = "0.3.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.178" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" + +[[package]] +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "mio" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +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.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "oid-registry" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9" +dependencies = [ + "asn1-rs 0.6.2", +] + +[[package]] +name = "oid-registry" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" +dependencies = [ + "asn1-rs 0.7.1", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "pem" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" +dependencies = [ + "base64", + "serde_core", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "portable-atomic" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "proc-macro2" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rcgen" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2" +dependencies = [ + "pem", + "ring", + "rustls-pki-types", + "time", + "x509-parser 0.16.0", + "yasna", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + +[[package]] +name = "rustls-pki-types" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "708c0f9d5f54ba0272468c1d306a52c495b31fa155e91bc25371e6df7996908c" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[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.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" + +[[package]] +name = "syn" +version = "2.0.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl 2.0.17", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.3.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" + +[[package]] +name = "time-macros" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tokio" +version = "1.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "signal-hook-registry", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "unit-prefix" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81e544489bf3d8ef66c953931f56617f423cd4b5494be343d9b9d3dda037b9a3" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "uuid" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" +dependencies = [ + "getrandom 0.3.4", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + +[[package]] +name = "x509-parser" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" +dependencies = [ + "asn1-rs 0.6.2", + "data-encoding", + "der-parser 9.0.0", + "lazy_static", + "nom", + "oid-registry 0.7.1", + "ring", + "rusticata-macros", + "thiserror 1.0.69", + "time", +] + +[[package]] +name = "x509-parser" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4569f339c0c402346d4a75a9e39cf8dad310e287eef1ff56d4c68e5067f53460" +dependencies = [ + "asn1-rs 0.7.1", + "data-encoding", + "der-parser 10.0.0", + "lazy_static", + "nom", + "oid-registry 0.8.1", + "ring", + "rusticata-macros", + "thiserror 2.0.17", + "time", +] + +[[package]] +name = "yasna" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +dependencies = [ + "time", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 15974bd0..a799a30c 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -4,3 +4,6 @@ version = "0.1.0" edition = "2024" [dependencies] +droplet-rs = { git = "https://github.com/Drop-OSS/droplet-rs.git", version = "0.11.1" } +indicatif = "0.18.3" +tokio = { version = "1.48.0", features = ["macros"] } diff --git a/cli/src/main.rs b/cli/src/main.rs index e7a11a96..7b399428 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,3 +1,40 @@ -fn main() { - println!("Hello, world!"); +use std::{env, path::PathBuf}; + +use droplet_rs::manifest::generate_manifest_rusty; +use indicatif::{ProgressBar, ProgressStyle}; +use tokio::runtime::Handle; + +#[tokio::main] +async fn main() { + let threads = Handle::current().metrics().num_workers(); + println!("using {} workers", threads); + let args: Vec = env::args().collect(); + let path = &args[1]; + + let path = PathBuf::from(path); + if !path.exists() { + panic!("{} does not exist", path.display()); + } + + println!("using path {}", path.display()); + + let progress_bar = ProgressBar::new(100_00).with_style( + ProgressStyle::template( + ProgressStyle::default_bar(), + "[{elapsed_precise}] [ETA {eta}] {wide_bar} {percent_precise}%", + ) + .unwrap(), + ); + let manifest = generate_manifest_rusty( + &path, + |progress| { + let progress_int = (progress * 100.0f32).round() as u64; + progress_bar.set_position(progress_int); + }, + |log| { + progress_bar.println(log); + }, + ) + .await + .expect("failed to generate manifest"); } From 4e32c389480fadd3b02efb09fd8c22468d40e688 Mon Sep 17 00:00:00 2001 From: DecDuck Date: Tue, 6 Jan 2026 16:11:06 +0700 Subject: [PATCH 03/22] feat: begin designing cli --- cli/Cargo.lock | 1530 ++++++++++++++++++++++++++++++++- cli/Cargo.toml | 9 + cli/src/cli.rs | 33 + cli/src/commands/configure.rs | 79 ++ cli/src/commands/mod.rs | 1 + cli/src/main.rs | 57 +- 6 files changed, 1660 insertions(+), 49 deletions(-) create mode 100644 cli/src/cli.rs create mode 100644 cli/src/commands/configure.rs create mode 100644 cli/src/commands/mod.rs diff --git a/cli/Cargo.lock b/cli/Cargo.lock index bf8e0da3..e57027d9 100644 --- a/cli/Cargo.lock +++ b/cli/Cargo.lock @@ -2,6 +2,56 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + [[package]] name = "anyhow" version = "1.0.100" @@ -86,18 +136,52 @@ dependencies = [ "syn", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "aws-lc-rs" +version = "1.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a88aab2464f1f25453baa7a07c84c5b7684e274054ba06817f382357f77a288" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45afffdee1e7c9126814751f88dddc747f41d91da16c9551a0f1e8a11e788a1" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", +] + [[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" + [[package]] name = "block-buffer" version = "0.10.4" @@ -126,9 +210,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215" dependencies = [ "find-msvc-tools", + "jobserver", + "libc", "shlex", ] +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + [[package]] name = "cfg-if" version = "1.0.4" @@ -136,10 +228,81 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] -name = "console" -version = "0.16.1" +name = "cfg_aliases" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b430743a6eb14e9764d4260d4c0d8123087d504eeb9c48f2b2a5e810dd369df4" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "clap" +version = "4.5.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" + +[[package]] +name = "cmake" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" +dependencies = [ + "cc", +] + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "console" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03e45a4a8926227e4197636ba97a9fc9b00477e9f4bd711395687c5f0734bec4" dependencies = [ "encode_unicode", "libc", @@ -148,6 +311,32 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -210,6 +399,18 @@ dependencies = [ "powerfmt", ] +[[package]] +name = "dialoguer" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25f104b501bf2364e78d0d3974cbc774f738f5865306ed128e1e0d7499c0ad96" +dependencies = [ + "console", + "shell-words", + "tempfile", + "zeroize", +] + [[package]] name = "digest" version = "0.10.7" @@ -235,9 +436,18 @@ dependencies = [ name = "downpour" version = "0.1.0" dependencies = [ + "anyhow", + "clap", + "console", + "dialoguer", "droplet-rs", "indicatif", + "reqwest", + "serde", + "serde_json", "tokio", + "url", + "webbrowser", ] [[package]] @@ -262,6 +472,12 @@ dependencies = [ "x509-parser 0.17.0", ] +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + [[package]] name = "dyn-clone" version = "1.0.20" @@ -274,12 +490,64 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + [[package]] name = "find-msvc-tools" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +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.31" @@ -386,8 +654,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -397,17 +667,89 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi", "wasip2", + "wasm-bindgen", ] +[[package]] +name = "h2" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + [[package]] name = "humansize" version = "2.1.3" @@ -417,6 +759,182 @@ dependencies = [ "libm", ] +[[package]] +name = "hyper" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "system-configuration", + "tokio", + "tower-service", + "tracing", + "windows-registry", +] + +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "indicatif" version = "0.18.3" @@ -430,12 +948,66 @@ dependencies = [ "web-time", ] +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "iri-string" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + [[package]] name = "itoa" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + [[package]] name = "js-sys" version = "0.3.83" @@ -464,12 +1036,42 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "litemap" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "memchr" version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -487,6 +1089,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + [[package]] name = "nom" version = "7.1.3" @@ -531,6 +1139,31 @@ dependencies = [ "autocfg", ] +[[package]] +name = "objc2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" +dependencies = [ + "objc2-encode", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +dependencies = [ + "bitflags", + "objc2", +] + [[package]] name = "oid-registry" version = "0.7.1" @@ -555,6 +1188,18 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "openssl-probe" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f50d9b3dabb09ecd771ad0aa242ca6894994c130308ca3d7684634df8037391" + [[package]] name = "pem" version = "3.0.6" @@ -565,6 +1210,12 @@ dependencies = [ "serde_core", ] +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + [[package]] name = "pin-project-lite" version = "0.2.16" @@ -583,12 +1234,30 @@ version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] + [[package]] name = "powerfmt" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + [[package]] name = "proc-macro2" version = "1.0.103" @@ -598,6 +1267,62 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "quinn" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror 2.0.17", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" +dependencies = [ + "aws-lc-rs", + "bytes", + "getrandom 0.3.4", + "lru-slab", + "rand", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.17", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "quote" version = "1.0.42" @@ -613,6 +1338,35 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.4", +] + [[package]] name = "rcgen" version = "0.13.2" @@ -627,6 +1381,46 @@ dependencies = [ "yasna", ] +[[package]] +name = "reqwest" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04e9018c9d814e5f30cc16a0f03271aeab3571e609612d9fe78c1aa8d11c2f62" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "mime", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "rustls-platform-verifier", + "serde", + "serde_json", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "ring" version = "0.17.14" @@ -641,6 +1435,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + [[package]] name = "rusticata-macros" version = "4.1.0" @@ -650,15 +1450,94 @@ dependencies = [ "nom", ] +[[package]] +name = "rustix" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" +dependencies = [ + "aws-lc-rs", + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pki-types" version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "708c0f9d5f54ba0272468c1d306a52c495b31fa155e91bc25371e6df7996908c" dependencies = [ + "web-time", "zeroize", ] +[[package]] +name = "rustls-platform-verifier" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" +dependencies = [ + "core-foundation 0.10.1", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + +[[package]] +name = "rustls-webpki" +version = "0.103.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "rustversion" version = "1.0.22" @@ -666,10 +1545,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] -name = "ryu" -version = "1.0.20" +name = "same-file" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "security-framework" +version = "3.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" +dependencies = [ + "bitflags", + "core-foundation 0.10.1", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +dependencies = [ + "core-foundation-sys", + "libc", +] [[package]] name = "serde" @@ -703,15 +1617,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.145" +version = "1.0.148" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +checksum = "3084b546a1dd6289475996f182a22aba973866ea8e8b02c51d9f46b1336a22da" dependencies = [ "itoa", "memchr", - "ryu", "serde", "serde_core", + "zmij", ] [[package]] @@ -725,6 +1639,12 @@ dependencies = [ "digest", ] +[[package]] +name = "shell-words" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77" + [[package]] name = "shlex" version = "1.3.0" @@ -746,6 +1666,40 @@ version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" version = "2.0.111" @@ -757,6 +1711,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + [[package]] name = "synstructure" version = "0.13.2" @@ -768,6 +1731,40 @@ dependencies = [ "syn", ] +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags", + "core-foundation 0.9.4", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tempfile" +version = "3.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" +dependencies = [ + "fastrand", + "getrandom 0.3.4", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + [[package]] name = "thiserror" version = "1.0.69" @@ -839,6 +1836,31 @@ dependencies = [ "time-core", ] +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tokio" version = "1.48.0" @@ -850,6 +1872,7 @@ dependencies = [ "mio", "pin-project-lite", "signal-hook-registry", + "socket2", "tokio-macros", "windows-sys 0.61.2", ] @@ -865,6 +1888,99 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +dependencies = [ + "bitflags", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + [[package]] name = "typenum" version = "1.19.0" @@ -895,6 +2011,30 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "uuid" version = "1.19.0" @@ -912,6 +2052,25 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" @@ -940,6 +2099,19 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.106" @@ -972,6 +2144,16 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "web-sys" +version = "0.3.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "web-time" version = "1.1.0" @@ -982,19 +2164,100 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webbrowser" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00f1243ef785213e3a32fa0396093424a3a6ea566f9948497e5a2309261a4c97" +dependencies = [ + "core-foundation 0.10.1", + "jni", + "log", + "ndk-context", + "objc2", + "objc2-foundation", + "url", + "web-sys", +] + +[[package]] +name = "webpki-root-certs" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36a29fc0408b113f68cf32637857ab740edfafdf460c326cd2afaa2d84cc05dc" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" +dependencies = [ + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", ] [[package]] @@ -1006,76 +2269,204 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + [[package]] name = "wit-bindgen" version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + [[package]] name = "x509-parser" version = "0.16.0" @@ -1121,8 +2512,111 @@ dependencies = [ "time", ] +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + [[package]] name = "zeroize" version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zmij" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fc5a66a20078bf1251bde995aa2fdcc4b800c70b5d92dd2c62abc5c60f679f8" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index a799a30c..e933d18a 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -4,6 +4,15 @@ version = "0.1.0" edition = "2024" [dependencies] +anyhow = "1.0.100" +clap = { version = "4.5.54", features = ["derive"] } +console = "0.16.2" +dialoguer = "0.12.0" droplet-rs = { git = "https://github.com/Drop-OSS/droplet-rs.git", version = "0.11.1" } indicatif = "0.18.3" +reqwest = { version = "0.13.1", features = ["json"] } +serde = { version = "1.0.228", features = ["derive"] } +serde_json = "1.0.148" tokio = { version = "1.48.0", features = ["macros"] } +url = "2.5.8" +webbrowser = "1.0.6" diff --git a/cli/src/cli.rs b/cli/src/cli.rs new file mode 100644 index 00000000..3b9086f3 --- /dev/null +++ b/cli/src/cli.rs @@ -0,0 +1,33 @@ +use clap::{Parser, Subcommand}; + +#[derive(Parser)] +#[command(version, about, long_about = None)] +pub struct Cli { + #[command(subcommand)] + pub command: Commands, + + /// Specify data file path + #[arg(short, long)] + pub data: Option, +} + +#[derive(Subcommand)] +pub enum Commands { + /// Configures a new Drop server + Configure { + /// Endpoint of the Drop server + url: String, + /// API token for non-interactive configuration. + #[arg(short, long)] + token: Option + }, + /// Uploads new game version to depot + Upload { + /// Path of new version + path: bool, + /// ID of game to attach to + game_id: String, + /// Version ID to attach to + version_id: String, + }, +} diff --git a/cli/src/commands/configure.rs b/cli/src/commands/configure.rs new file mode 100644 index 00000000..e4fe022e --- /dev/null +++ b/cli/src/commands/configure.rs @@ -0,0 +1,79 @@ +use std::sync::LazyLock; + +use anyhow::{Result, anyhow}; +use dialoguer::{Confirm, Input, theme::ColorfulTheme}; +use reqwest::Client; +use serde::{Deserialize, Serialize}; +use url::Url; + +const TOKEN_CREATE_PAYLOAD: &str = + "eyJuYW1lIjoiZG93bnBvdXIgKGNsaSkiLCJhY2xzIjpbImRlcG90Om5ldyJdfQ=="; + +static CLIENT: LazyLock = LazyLock::new(|| reqwest::Client::new()); +const REQUIRED_ACLS: [&str; 1] = ["depot:new"]; + +pub async fn interactive_configure(url: String) -> Result<()> { + let base_url = Url::parse(&url)?; + let mut token_create_url = base_url.join("/admin/settings/tokens")?; + { + let mut query = token_create_url.query_pairs_mut(); + query.append_pair("payload", TOKEN_CREATE_PAYLOAD); + }; + + let confirm = Confirm::with_theme(&ColorfulTheme::default()) + .with_prompt(format!( + "Open \"{}\" in your default browser?", + token_create_url.as_str() + )) + .interact()?; + + if !confirm { + return Err(anyhow!("User cancelled action")); + } + + webbrowser::open(token_create_url.as_str())?; + + let token: String = Input::with_theme(&ColorfulTheme::default()) + .with_prompt("API token") + .interact_text()?; + + validate_configuration(url, token).await?; + + Ok(()) +} + +pub async fn validate_configuration(url: String, token: String) -> Result<()> { + let base_url = Url::parse(&url)?; + let token_check_url = base_url.join("/api/v1/token")?; + + let acl_check = CLIENT + .get(token_check_url) + .bearer_auth(token) + .send() + .await?; + + if !acl_check.status().is_success() { + return Err(anyhow!( + "ACL check failed with response code: {}", + acl_check.status() + )); + } + + let acls: Vec = acl_check.json().await?; + + for acl in REQUIRED_ACLS { + if !acls.contains(&acl.to_string()) { + return Err(anyhow!("Token missing {} acl", acl)); + } + } + + + + Ok(()) +} + +#[derive(Serialize, Deserialize)] +pub struct ServerConfiguration { + pub endpoint: String, + pub token: String, +} diff --git a/cli/src/commands/mod.rs b/cli/src/commands/mod.rs new file mode 100644 index 00000000..bd5a1e99 --- /dev/null +++ b/cli/src/commands/mod.rs @@ -0,0 +1 @@ +pub mod configure; \ No newline at end of file diff --git a/cli/src/main.rs b/cli/src/main.rs index 7b399428..f00aa39c 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,40 +1,35 @@ -use std::{env, path::PathBuf}; +use std::{env, path::PathBuf, sync::LazyLock}; +use anyhow::Result; +use clap::Parser; use droplet_rs::manifest::generate_manifest_rusty; use indicatif::{ProgressBar, ProgressStyle}; use tokio::runtime::Handle; +use crate::{cli::{Cli, Commands}, commands::configure::interactive_configure}; + +mod cli; +mod commands; + +pub static CLI: LazyLock = LazyLock::new(|| Cli::parse()); + #[tokio::main] -async fn main() { - let threads = Handle::current().metrics().num_workers(); - println!("using {} workers", threads); - let args: Vec = env::args().collect(); - let path = &args[1]; +async fn main() -> Result<()> { - let path = PathBuf::from(path); - if !path.exists() { - panic!("{} does not exist", path.display()); - } - - println!("using path {}", path.display()); - - let progress_bar = ProgressBar::new(100_00).with_style( - ProgressStyle::template( - ProgressStyle::default_bar(), - "[{elapsed_precise}] [ETA {eta}] {wide_bar} {percent_precise}%", - ) - .unwrap(), - ); - let manifest = generate_manifest_rusty( - &path, - |progress| { - let progress_int = (progress * 100.0f32).round() as u64; - progress_bar.set_position(progress_int); + match &CLI.command { + Commands::Configure { url, token } => { + if let Some(token) = token { + todo!() + } else { + interactive_configure(url.to_string()).await?; + } }, - |log| { - progress_bar.println(log); - }, - ) - .await - .expect("failed to generate manifest"); + Commands::Upload { + path, + game_id, + version_id, + } => todo!(), + }; + + Ok(()) } From 320d32388030ce7f82e0a6a36c7db54556800c80 Mon Sep 17 00:00:00 2001 From: quexeky Date: Mon, 19 Jan 2026 13:45:00 +1100 Subject: [PATCH 04/22] feat: Add nix and rust-toolchain.toml --- cli/flake.lock | 96 +++++++++++++++++++++++++++++++++++++++++ cli/flake.nix | 51 ++++++++++++++++++++++ cli/rust-toolchain.toml | 2 + 3 files changed, 149 insertions(+) create mode 100644 cli/flake.lock create mode 100644 cli/flake.nix create mode 100644 cli/rust-toolchain.toml diff --git a/cli/flake.lock b/cli/flake.lock new file mode 100644 index 00000000..94100467 --- /dev/null +++ b/cli/flake.lock @@ -0,0 +1,96 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1768564909, + "narHash": "sha256-Kell/SpJYVkHWMvnhqJz/8DqQg2b6PguxVWOuadbHCc=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e4bae1bd10c9c57b2cf517953ab70060a828ee6f", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1744536153, + "narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "18dd725c29603f582cf1900e0d25f9f1063dbf11", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs", + "rust-overlay": "rust-overlay" + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1768704795, + "narHash": "sha256-Y33TAp2BHEcuspYvcmBXXD0qdvjftv73PwyKTDOjoSY=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "4b7472a78857ac789fb26616040f55cfcbd36c6e", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/cli/flake.nix b/cli/flake.nix new file mode 100644 index 00000000..e196f2cc --- /dev/null +++ b/cli/flake.nix @@ -0,0 +1,51 @@ +{ + description = "Drop-OSS app development environment"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + rust-overlay.url = "github:oxalica/rust-overlay"; + }; + + outputs = + { + self, + nixpkgs, + flake-utils, + rust-overlay, + }: + flake-utils.lib.eachDefaultSystem ( + system: + let + overlays = [ (import rust-overlay) ]; + pkgs = import nixpkgs { + inherit system overlays; + }; + libraries = with pkgs; [ + glib + glibc + openssl + ]; + in + { + devShells.default = pkgs.mkShell { + nativeBuildInputs = with pkgs; [ + pkg-config + git + rust-bin.nightly.latest.default + rust-analyzer + ]; + + + buildInputs = libraries; + + shellHook = '' + echo "Drop-OSS app development environment loaded." + export LD_LIBRARY_PATH="${ + pkgs.lib.makeLibraryPath libraries + }:$LD_LIBRARY_PATH" + ''; + }; + } + ); +} diff --git a/cli/rust-toolchain.toml b/cli/rust-toolchain.toml new file mode 100644 index 00000000..271800cb --- /dev/null +++ b/cli/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" \ No newline at end of file From 6e21e40648f95985de32ce4288abd6b769e03501 Mon Sep 17 00:00:00 2001 From: quexeky Date: Mon, 19 Jan 2026 18:54:41 +1100 Subject: [PATCH 05/22] feat: Logging Also initial progress on the upload interface --- cli/.gitignore | 1 + cli/Cargo.lock | 983 +++++++++++++++++++++++++- cli/Cargo.toml | 6 +- cli/src/cli.rs | 35 +- cli/src/commands/configure.rs | 2 - cli/src/commands/mod.rs | 3 +- cli/src/commands/upload/interface.rs | 34 + cli/src/commands/upload/mod.rs | 4 + cli/src/commands/upload/s3.rs | 28 + cli/src/commands/upload/uploadable.rs | 20 + cli/src/commands/upload/void.rs | 38 + cli/src/main.rs | 90 ++- cli/src/manifest.rs | 26 + 13 files changed, 1198 insertions(+), 72 deletions(-) create mode 100644 cli/src/commands/upload/interface.rs create mode 100644 cli/src/commands/upload/mod.rs create mode 100644 cli/src/commands/upload/s3.rs create mode 100644 cli/src/commands/upload/uploadable.rs create mode 100644 cli/src/commands/upload/void.rs create mode 100644 cli/src/manifest.rs diff --git a/cli/.gitignore b/cli/.gitignore index ea8c4bf7..b13d16da 100644 --- a/cli/.gitignore +++ b/cli/.gitignore @@ -1 +1,2 @@ /target +logs/ \ No newline at end of file diff --git a/cli/Cargo.lock b/cli/Cargo.lock index e57027d9..1973d175 100644 --- a/cli/Cargo.lock +++ b/cli/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anstream" version = "0.6.21" @@ -148,6 +163,18 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "aws-credential-types" +version = "1.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cd362783681b15d136480ad555a099e82ecd8e2d10a841e14dfd0078d67fee3" +dependencies = [ + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-types", + "zeroize", +] + [[package]] name = "aws-lc-rs" version = "1.15.2" @@ -170,12 +197,324 @@ dependencies = [ "fs_extra", ] +[[package]] +name = "aws-runtime" +version = "1.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "959dab27ce613e6c9658eb3621064d0e2027e5f2acb65bc526a43577facea557" +dependencies = [ + "aws-credential-types", + "aws-sigv4", + "aws-smithy-async", + "aws-smithy-eventstream", + "aws-smithy-http", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", + "bytes", + "fastrand", + "http 0.2.12", + "http-body 0.4.6", + "percent-encoding", + "pin-project-lite", + "tracing", + "uuid", +] + +[[package]] +name = "aws-sdk-s3" +version = "1.120.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06673901e961f20fa8d7da907da48f7ad6c1b383e3726c22bd418900f015abe1" +dependencies = [ + "aws-credential-types", + "aws-runtime", + "aws-sigv4", + "aws-smithy-async", + "aws-smithy-checksums", + "aws-smithy-eventstream", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-observability", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-smithy-xml", + "aws-types", + "bytes", + "fastrand", + "hex", + "hmac", + "http 0.2.12", + "http 1.4.0", + "http-body 0.4.6", + "lru", + "percent-encoding", + "regex-lite", + "sha2", + "tracing", + "url", +] + +[[package]] +name = "aws-sigv4" +version = "1.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69e523e1c4e8e7e8ff219d732988e22bfeae8a1cafdbe6d9eca1546fa080be7c" +dependencies = [ + "aws-credential-types", + "aws-smithy-eventstream", + "aws-smithy-http", + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "crypto-bigint 0.5.5", + "form_urlencoded", + "hex", + "hmac", + "http 0.2.12", + "http 1.4.0", + "p256", + "percent-encoding", + "ring", + "sha2", + "subtle", + "time", + "tracing", + "zeroize", +] + +[[package]] +name = "aws-smithy-async" +version = "1.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ee19095c7c4dda59f1697d028ce704c24b2d33c6718790c7f1d5a3015b4107c" +dependencies = [ + "futures-util", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "aws-smithy-checksums" +version = "0.63.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23374b9170cbbcc6f5df8dc5ebb9b6c5c28a3c8f599f0e8b8b10eb6f4a5c6e74" +dependencies = [ + "aws-smithy-http", + "aws-smithy-types", + "bytes", + "crc-fast", + "hex", + "http 0.2.12", + "http-body 0.4.6", + "md-5", + "pin-project-lite", + "sha1", + "sha2", + "tracing", +] + +[[package]] +name = "aws-smithy-eventstream" +version = "0.60.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc12f8b310e38cad85cf3bef45ad236f470717393c613266ce0a89512286b650" +dependencies = [ + "aws-smithy-types", + "bytes", + "crc32fast", +] + +[[package]] +name = "aws-smithy-http" +version = "0.62.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826141069295752372f8203c17f28e30c464d22899a43a0c9fd9c458d469c88b" +dependencies = [ + "aws-smithy-eventstream", + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "bytes-utils", + "futures-core", + "futures-util", + "http 0.2.12", + "http 1.4.0", + "http-body 0.4.6", + "percent-encoding", + "pin-project-lite", + "pin-utils", + "tracing", +] + +[[package]] +name = "aws-smithy-http-client" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59e62db736db19c488966c8d787f52e6270be565727236fd5579eaa301e7bc4a" +dependencies = [ + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-types", + "h2 0.3.27", + "h2 0.4.13", + "http 0.2.12", + "http 1.4.0", + "http-body 0.4.6", + "hyper 0.14.32", + "hyper 1.8.1", + "hyper-rustls 0.24.2", + "hyper-rustls 0.27.7", + "hyper-util", + "pin-project-lite", + "rustls 0.21.12", + "rustls 0.23.36", + "rustls-native-certs", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.26.4", + "tower", + "tracing", +] + +[[package]] +name = "aws-smithy-json" +version = "0.61.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49fa1213db31ac95288d981476f78d05d9cbb0353d22cdf3472cc05bb02f6551" +dependencies = [ + "aws-smithy-types", +] + +[[package]] +name = "aws-smithy-observability" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1fcbefc7ece1d70dcce29e490f269695dfca2d2bacdeaf9e5c3f799e4e6a42" +dependencies = [ + "aws-smithy-runtime-api", +] + +[[package]] +name = "aws-smithy-runtime" +version = "1.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb5b6167fcdf47399024e81ac08e795180c576a20e4d4ce67949f9a88ae37dc1" +dependencies = [ + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-http-client", + "aws-smithy-observability", + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "fastrand", + "http 0.2.12", + "http 1.4.0", + "http-body 0.4.6", + "http-body 1.0.1", + "pin-project-lite", + "pin-utils", + "tokio", + "tracing", +] + +[[package]] +name = "aws-smithy-runtime-api" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efce7aaaf59ad53c5412f14fc19b2d5c6ab2c3ec688d272fd31f76ec12f44fb0" +dependencies = [ + "aws-smithy-async", + "aws-smithy-types", + "bytes", + "http 0.2.12", + "http 1.4.0", + "pin-project-lite", + "tokio", + "tracing", + "zeroize", +] + +[[package]] +name = "aws-smithy-types" +version = "1.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65f172bcb02424eb94425db8aed1b6d583b5104d4d5ddddf22402c661a320048" +dependencies = [ + "base64-simd", + "bytes", + "bytes-utils", + "futures-core", + "http 0.2.12", + "http 1.4.0", + "http-body 0.4.6", + "http-body 1.0.1", + "http-body-util", + "itoa", + "num-integer", + "pin-project-lite", + "pin-utils", + "ryu", + "serde", + "time", + "tokio", + "tokio-util", +] + +[[package]] +name = "aws-smithy-xml" +version = "0.60.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11b2f670422ff42bf7065031e72b45bc52a3508bd089f743ea90731ca2b6ea57" +dependencies = [ + "xmlparser", +] + +[[package]] +name = "aws-types" +version = "1.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d980627d2dd7bfc32a3c025685a033eeab8d365cc840c631ef59d1b8f428164" +dependencies = [ + "aws-credential-types", + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-types", + "rustc_version", + "tracing", +] + +[[package]] +name = "base16ct" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" + [[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64-simd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195" +dependencies = [ + "outref", + "vsimd", +] + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + [[package]] name = "bitflags" version = "2.10.0" @@ -203,6 +542,16 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" +[[package]] +name = "bytes-utils" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dafe3a8757b027e2be6e4e5601ed563c55989fcf1546e933c66c8eb3a058d35" +dependencies = [ + "bytes", + "either", +] + [[package]] name = "cc" version = "1.2.49" @@ -233,6 +582,19 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "chrono" +version = "0.4.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link", +] + [[package]] name = "clap" version = "4.5.54" @@ -288,6 +650,16 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +[[package]] +name = "colored" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" +dependencies = [ + "lazy_static", + "windows-sys 0.52.0", +] + [[package]] name = "combine" version = "4.6.7" @@ -311,6 +683,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "core-foundation" version = "0.9.4" @@ -346,6 +724,64 @@ dependencies = [ "libc", ] +[[package]] +name = "crc" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + +[[package]] +name = "crc-fast" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd92aca2c6001b1bf5ba0ff84ee74ec8501b52bbef0cac80bf25a6c1d87a83d" +dependencies = [ + "crc", + "digest", + "rustversion", + "spin", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-bigint" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "crypto-common" version = "0.1.7" @@ -362,6 +798,16 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" +[[package]] +name = "der" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" +dependencies = [ + "const-oid", + "zeroize", +] + [[package]] name = "der-parser" version = "9.0.0" @@ -419,6 +865,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", + "subtle", ] [[package]] @@ -437,11 +884,15 @@ name = "downpour" version = "0.1.0" dependencies = [ "anyhow", + "aws-sdk-s3", + "chrono", "clap", "console", "dialoguer", "droplet-rs", + "fern", "indicatif", + "log", "reqwest", "serde", "serde_json", @@ -452,13 +903,14 @@ dependencies = [ [[package]] name = "droplet-rs" -version = "0.11.1" -source = "git+https://github.com/Drop-OSS/droplet-rs.git#3e782bf29eb4bed7e31cfb7f8dfef4babf34fa9c" +version = "0.14.1" +source = "git+https://github.com/Drop-OSS/droplet-rs.git#f17a585b563d874ef9a09c27be5169b7e728d148" dependencies = [ "anyhow", "async-trait", "dyn-clone", "futures", + "getrandom 0.3.4", "hex", "humansize", "rcgen", @@ -484,6 +936,44 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" +[[package]] +name = "ecdsa" +version = "0.14.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" +dependencies = [ + "der", + "elliptic-curve", + "rfc6979", + "signature", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "elliptic-curve" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" +dependencies = [ + "base16ct", + "crypto-bigint 0.4.9", + "der", + "digest", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "encode_unicode" version = "1.0.0" @@ -521,6 +1011,26 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "fern" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4316185f709b23713e41e3195f90edef7fb00c3ed4adc79769cf09cc762a3b29" +dependencies = [ + "colored", + "log", +] + +[[package]] +name = "ff" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "find-msvc-tools" version = "0.1.5" @@ -533,6 +1043,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "form_urlencoded" version = "1.2.2" @@ -674,6 +1190,36 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "group" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "h2" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "h2" version = "0.4.13" @@ -685,7 +1231,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http", + "http 1.4.0", "indexmap", "slab", "tokio", @@ -698,6 +1244,11 @@ name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] [[package]] name = "heck" @@ -711,6 +1262,26 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http" version = "1.4.0" @@ -721,6 +1292,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + [[package]] name = "http-body" version = "1.0.1" @@ -728,7 +1310,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http", + "http 1.4.0", ] [[package]] @@ -739,8 +1321,8 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http", - "http-body", + "http 1.4.0", + "http-body 1.0.1", "pin-project-lite", ] @@ -750,6 +1332,12 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + [[package]] name = "humansize" version = "2.1.3" @@ -759,6 +1347,30 @@ dependencies = [ "libm", ] +[[package]] +name = "hyper" +version = "0.14.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.3.27", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.5.10", + "tokio", + "tower-service", + "tracing", + "want", +] + [[package]] name = "hyper" version = "1.8.1" @@ -769,9 +1381,9 @@ dependencies = [ "bytes", "futures-channel", "futures-core", - "h2", - "http", - "http-body", + "h2 0.4.13", + "http 1.4.0", + "http-body 1.0.1", "httparse", "itoa", "pin-project-lite", @@ -781,19 +1393,35 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http 0.2.12", + "hyper 0.14.32", + "log", + "rustls 0.21.12", + "tokio", + "tokio-rustls 0.24.1", +] + [[package]] name = "hyper-rustls" version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "http", - "hyper", + "http 1.4.0", + "hyper 1.8.1", "hyper-util", - "rustls", + "rustls 0.23.36", + "rustls-native-certs", "rustls-pki-types", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.4", "tower-service", ] @@ -808,14 +1436,14 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "http", - "http-body", - "hyper", + "http 1.4.0", + "http-body 1.0.1", + "hyper 1.8.1", "ipnet", "libc", "percent-encoding", "pin-project-lite", - "socket2", + "socket2 0.6.1", "system-configuration", "tokio", "tower-service", @@ -823,6 +1451,30 @@ dependencies = [ "windows-registry", ] +[[package]] +name = "iana-time-zone" +version = "0.1.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "icu_collections" version = "2.1.1" @@ -1054,12 +1706,31 @@ version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +[[package]] +name = "lru" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1dc47f592c06f33f8e3aea9591776ec7c9f9e4124778ff8a3c3b87159f7e593" +dependencies = [ + "hashbrown", +] + [[package]] name = "lru-slab" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + [[package]] name = "memchr" version = "2.7.6" @@ -1200,6 +1871,23 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f50d9b3dabb09ecd771ad0aa242ca6894994c130308ca3d7684634df8037391" +[[package]] +name = "outref" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" + +[[package]] +name = "p256" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594" +dependencies = [ + "ecdsa", + "elliptic-curve", + "sha2", +] + [[package]] name = "pem" version = "3.0.6" @@ -1228,6 +1916,16 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs8" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" +dependencies = [ + "der", + "spki", +] + [[package]] name = "portable-atomic" version = "1.11.1" @@ -1279,8 +1977,8 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls", - "socket2", + "rustls 0.23.36", + "socket2 0.6.1", "thiserror 2.0.17", "tokio", "tracing", @@ -1300,7 +1998,7 @@ dependencies = [ "rand", "ring", "rustc-hash", - "rustls", + "rustls 0.23.36", "rustls-pki-types", "slab", "thiserror 2.0.17", @@ -1318,9 +2016,9 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2", + "socket2 0.6.1", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.60.2", ] [[package]] @@ -1345,7 +2043,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha", - "rand_core", + "rand_core 0.9.3", ] [[package]] @@ -1355,7 +2053,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", ] [[package]] @@ -1381,6 +2088,12 @@ dependencies = [ "yasna", ] +[[package]] +name = "regex-lite" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d942b98df5e658f56f20d592c7f868833fe38115e65c33003d8cd224b0155da" + [[package]] name = "reqwest" version = "0.13.1" @@ -1391,12 +2104,12 @@ dependencies = [ "bytes", "encoding_rs", "futures-core", - "h2", - "http", - "http-body", + "h2 0.4.13", + "http 1.4.0", + "http-body 1.0.1", "http-body-util", - "hyper", - "hyper-rustls", + "hyper 1.8.1", + "hyper-rustls 0.27.7", "hyper-util", "js-sys", "log", @@ -1404,14 +2117,14 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls", + "rustls 0.23.36", "rustls-pki-types", "rustls-platform-verifier", "serde", "serde_json", "sync_wrapper", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.4", "tower", "tower-http", "tower-service", @@ -1421,6 +2134,17 @@ dependencies = [ "web-sys", ] +[[package]] +name = "rfc6979" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" +dependencies = [ + "crypto-bigint 0.4.9", + "hmac", + "zeroize", +] + [[package]] name = "ring" version = "0.17.14" @@ -1441,6 +2165,15 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rusticata-macros" version = "4.1.0" @@ -1463,6 +2196,18 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring", + "rustls-webpki 0.101.7", + "sct", +] + [[package]] name = "rustls" version = "0.23.36" @@ -1472,7 +2217,7 @@ dependencies = [ "aws-lc-rs", "once_cell", "rustls-pki-types", - "rustls-webpki", + "rustls-webpki 0.103.8", "subtle", "zeroize", ] @@ -1510,10 +2255,10 @@ dependencies = [ "jni", "log", "once_cell", - "rustls", + "rustls 0.23.36", "rustls-native-certs", "rustls-platform-verifier-android", - "rustls-webpki", + "rustls-webpki 0.103.8", "security-framework", "security-framework-sys", "webpki-root-certs", @@ -1526,6 +2271,16 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "rustls-webpki" version = "0.103.8" @@ -1544,6 +2299,12 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +[[package]] +name = "ryu" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" + [[package]] name = "same-file" version = "1.0.6" @@ -1562,6 +2323,30 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "sec1" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + [[package]] name = "security-framework" version = "3.5.1" @@ -1585,6 +2370,12 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + [[package]] name = "serde" version = "1.0.228" @@ -1628,6 +2419,17 @@ dependencies = [ "zmij", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha2" version = "0.10.9" @@ -1660,6 +2462,16 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +dependencies = [ + "digest", + "rand_core 0.6.4", +] + [[package]] name = "slab" version = "0.4.11" @@ -1672,6 +2484,16 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "socket2" version = "0.6.1" @@ -1682,6 +2504,22 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "spin" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" + +[[package]] +name = "spki" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "stable_deref_trait" version = "1.2.1" @@ -1872,7 +2710,7 @@ dependencies = [ "mio", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.6.1", "tokio-macros", "windows-sys 0.61.2", ] @@ -1888,13 +2726,23 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.12", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls", + "rustls 0.23.36", "tokio", ] @@ -1935,8 +2783,8 @@ dependencies = [ "bitflags", "bytes", "futures-util", - "http", - "http-body", + "http 1.4.0", + "http-body 1.0.1", "iri-string", "pin-project-lite", "tower", @@ -1963,9 +2811,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tracing-core" version = "0.1.36" @@ -2052,6 +2912,12 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "vsimd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" + [[package]] name = "walkdir" version = "2.5.0" @@ -2198,6 +3064,41 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "windows-link" version = "0.2.1" @@ -2503,6 +3404,12 @@ dependencies = [ "time", ] +[[package]] +name = "xmlparser" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" + [[package]] name = "yasna" version = "0.5.2" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index e933d18a..de7ab3b7 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -5,11 +5,15 @@ edition = "2024" [dependencies] anyhow = "1.0.100" +aws-sdk-s3 = "1.120.0" +chrono = "0.4.43" clap = { version = "4.5.54", features = ["derive"] } console = "0.16.2" dialoguer = "0.12.0" -droplet-rs = { git = "https://github.com/Drop-OSS/droplet-rs.git", version = "0.11.1" } +droplet-rs = { git = "https://github.com/Drop-OSS/droplet-rs.git", version = "0.14" } +fern = { version = "0.7.1", features = ["colored"] } indicatif = "0.18.3" +log = "0.4.29" reqwest = { version = "0.13.1", features = ["json"] } serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0.148" diff --git a/cli/src/cli.rs b/cli/src/cli.rs index 3b9086f3..b420d07d 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -1,4 +1,6 @@ -use clap::{Parser, Subcommand}; +use std::path::PathBuf; + +use clap::{Args, Parser, Subcommand, ValueEnum}; #[derive(Parser)] #[command(version, about, long_about = None)] @@ -19,15 +21,28 @@ pub enum Commands { url: String, /// API token for non-interactive configuration. #[arg(short, long)] - token: Option + token: Option, }, /// Uploads new game version to depot - Upload { - /// Path of new version - path: bool, - /// ID of game to attach to - game_id: String, - /// Version ID to attach to - version_id: String, - }, + Upload(UploadInfo), +} +#[derive(Args)] +pub struct UploadInfo { + /// Sets + pub upload_style: UploadStyle, + /// Path of new version + #[arg(short, long)] + pub path: PathBuf, + /// ID of game to attach to + #[arg(short, long)] + pub game_id: String, + /// Version ID to attach to + #[arg(short, long)] + pub version_id: String, +} + +#[derive(ValueEnum, Copy, Clone, Debug, PartialEq, Eq)] +pub enum UploadStyle { + S3, + Nginx, } diff --git a/cli/src/commands/configure.rs b/cli/src/commands/configure.rs index e4fe022e..c4a2ed1c 100644 --- a/cli/src/commands/configure.rs +++ b/cli/src/commands/configure.rs @@ -67,8 +67,6 @@ pub async fn validate_configuration(url: String, token: String) -> Result<()> { } } - - Ok(()) } diff --git a/cli/src/commands/mod.rs b/cli/src/commands/mod.rs index bd5a1e99..db8ad986 100644 --- a/cli/src/commands/mod.rs +++ b/cli/src/commands/mod.rs @@ -1 +1,2 @@ -pub mod configure; \ No newline at end of file +pub mod configure; +pub mod upload; diff --git a/cli/src/commands/upload/interface.rs b/cli/src/commands/upload/interface.rs new file mode 100644 index 00000000..a88f1f94 --- /dev/null +++ b/cli/src/commands/upload/interface.rs @@ -0,0 +1,34 @@ +use std::path::Path; + +use crate::{ + cli::UploadInfo, + commands::upload::{uploadable::Uploadable, void::VoidUploadable}, + manifest::generate_manifest, +}; +use log::info; + +pub async fn upload(info: &UploadInfo) -> anyhow::Result<()> { + let game_id = &info.game_id; + let path = &info.path; + let version_id = &info.version_id; + + let manifest = generate_manifest(&Path::new(path)).await?; + let mut uploader: Box = match info.upload_style { + crate::cli::UploadStyle::S3 => Box::new(VoidUploadable::new()), + crate::cli::UploadStyle::Nginx => Box::new(VoidUploadable::new()), + }; + info!("Uploading chunks"); + for (id, data) in &manifest.chunks { + info!("Uploading chunk id {id}"); + uploader.upload_chunk(game_id, version_id, id, data)?; + } + info!("Finished uploading chunks"); + + info!("Uploading manifest"); + uploader.upload_manifest(manifest, game_id, version_id)?; + + info!("Uploading speedtest"); + uploader.upload_speedtest(game_id, version_id)?; + + Ok(()) +} diff --git a/cli/src/commands/upload/mod.rs b/cli/src/commands/upload/mod.rs new file mode 100644 index 00000000..e1c44a3a --- /dev/null +++ b/cli/src/commands/upload/mod.rs @@ -0,0 +1,4 @@ +pub mod interface; +pub mod s3; +pub mod uploadable; +pub mod void; \ No newline at end of file diff --git a/cli/src/commands/upload/s3.rs b/cli/src/commands/upload/s3.rs new file mode 100644 index 00000000..c6a990bb --- /dev/null +++ b/cli/src/commands/upload/s3.rs @@ -0,0 +1,28 @@ +use droplet_rs::manifest::{ChunkData, Manifest}; + +use crate::commands::upload::uploadable::Uploadable; + +pub type S3 = aws_sdk_s3::Client; +impl Uploadable for S3 { + fn upload_chunk( + &mut self, + id: &String, + version: &String, + chunk_id: &String, + chunk: &ChunkData, + ) -> anyhow::Result<()> { + todo!() + } + fn upload_speedtest(&mut self, game_id: &String, version_id: &String) -> anyhow::Result<()> { + todo!() + } + + fn upload_manifest( + &mut self, + manifest: Manifest, + game_id: &String, + version_id: &String, + ) -> anyhow::Result<()> { + todo!() + } +} diff --git a/cli/src/commands/upload/uploadable.rs b/cli/src/commands/upload/uploadable.rs new file mode 100644 index 00000000..9b2548e0 --- /dev/null +++ b/cli/src/commands/upload/uploadable.rs @@ -0,0 +1,20 @@ +use droplet_rs::manifest::{ChunkData, Manifest}; + +pub trait Uploadable { + fn upload_chunk( + &mut self, + id: &String, + version: &String, + chunk_id: &String, + chunk: &ChunkData, + ) -> anyhow::Result<()>; + fn upload_speedtest(&mut self, game_id: &String, version_id: &String) -> anyhow::Result<()>; + fn upload_manifest(&mut self, manifest: Manifest, game_id: &String, version_id: &String) -> anyhow::Result<()>; +} +pub enum UploadableConfig { + S3 { + api_secret: String, + api_key_identifier: String, + region: String, + }, +} diff --git a/cli/src/commands/upload/void.rs b/cli/src/commands/upload/void.rs new file mode 100644 index 00000000..1a28358e --- /dev/null +++ b/cli/src/commands/upload/void.rs @@ -0,0 +1,38 @@ +use droplet_rs::manifest::{ChunkData, Manifest}; +use log::warn; + +use crate::commands::upload::uploadable::Uploadable; + +pub struct VoidUploadable; +impl Uploadable for VoidUploadable { + fn upload_chunk( + &mut self, + _id: &String, + _version: &String, + _chunk_id: &String, + _chunk: &ChunkData, + ) -> anyhow::Result<()> { + warn!("Uploading chunk to VoidUploader"); + Ok(()) + } + + fn upload_speedtest(&mut self, _game_id: &String, _version_id: &String) -> anyhow::Result<()> { + warn!("Uploading speedtest to VoidUploader"); + Ok(()) + } + + fn upload_manifest( + &mut self, + _manifest: Manifest, + _game_id: &String, + _version_id: &String, + ) -> anyhow::Result<()> { + warn!("Uploading manifest to VoidUploader"); + Ok(()) + } +} +impl VoidUploadable { + pub fn new() -> Self { + Self + } +} diff --git a/cli/src/main.rs b/cli/src/main.rs index f00aa39c..5c62aa46 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,35 +1,85 @@ -use std::{env, path::PathBuf, sync::LazyLock}; - -use anyhow::Result; +use crate::{ + cli::{Cli, Commands}, + commands::{configure::interactive_configure, upload}, +}; use clap::Parser; -use droplet_rs::manifest::generate_manifest_rusty; -use indicatif::{ProgressBar, ProgressStyle}; -use tokio::runtime::Handle; - -use crate::{cli::{Cli, Commands}, commands::configure::interactive_configure}; +use fern::colors::{Color, ColoredLevelConfig}; +use log::LevelFilter; +use std::env; +use std::fs; +use std::io; mod cli; mod commands; - -pub static CLI: LazyLock = LazyLock::new(|| Cli::parse()); +mod manifest; #[tokio::main] -async fn main() -> Result<()> { - - match &CLI.command { +async fn main() -> anyhow::Result<()> { + configure_logging()?; + let cli = Cli::parse(); + match &cli.command { Commands::Configure { url, token } => { if let Some(token) = token { - todo!() } else { interactive_configure(url.to_string()).await?; } - }, - Commands::Upload { - path, - game_id, - version_id, - } => todo!(), + } + Commands::Upload(info) => { + upload::interface::upload(info).await?; + } }; Ok(()) } + +pub fn configure_logging() -> anyhow::Result<()> { + let log_level = env::var("RUST_LOG") + .or_else(|_| env::var("LOG_LEVEL")) + .unwrap_or_else(|_| "info".to_string()) + .parse::()?; + + let log_dir = env::var("LOG_FILE_DIR").unwrap_or_else(|_| "logs".to_string()); + + fs::create_dir_all(&log_dir)?; + + let colors = ColoredLevelConfig::new() + .error(Color::Red) + .warn(Color::Yellow) + .info(Color::Green) + .debug(Color::Blue) + .trace(Color::Magenta); + + fern::Dispatch::new() + .chain( + // Console output with colors and formatting + fern::Dispatch::new() + .format(move |out, message, record| { + out.finish(format_args!( + "[{}] {} {} - {}", + chrono::Local::now().format("%Y-%m-%d %H:%M:%S%.3f"), + colors.color(record.level()), + record.target(), + message + )) + }) + .chain(io::stdout()), + ) + .chain( + // File output without colors and with formatting + fern::Dispatch::new() + .format(|out, message, record| { + out.finish(format_args!( + "[{}] {} {} - {}", + chrono::Local::now().format("%Y-%m-%d %H:%M:%S%.3f"), + record.level(), + record.target(), + message + )) + }) + .chain(fern::log_file(format!("{}/app.log", log_dir))?), + ) + .level(log_level) + .apply()?; + + Ok(()) +} diff --git a/cli/src/manifest.rs b/cli/src/manifest.rs new file mode 100644 index 00000000..5c89af38 --- /dev/null +++ b/cli/src/manifest.rs @@ -0,0 +1,26 @@ +use std::{ + fs, + io::{Read, Seek}, + path::Path, +}; + +use droplet_rs::manifest::{Manifest, generate_manifest_rusty}; +use indicatif::{ProgressBar, ProgressStyle}; + +pub async fn generate_manifest(dir: &Path) -> anyhow::Result { + let progress_bar = ProgressBar::new(100_00).with_style( + ProgressStyle::default_bar() + .template("[{elapsed_precise}] [ETA {eta}] {bar} {percent_precise}%") + .unwrap(), + ); + let res = generate_manifest_rusty( + dir, + |progress| { + let progress_int = (progress * 100f32).round() as u64; + progress_bar.set_position(progress_int); + }, + |log| progress_bar.println(log), + ) + .await; + res +} From 85b2e65b5f7a3897425baacb65274d54e1e4d202 Mon Sep 17 00:00:00 2001 From: quexeky Date: Tue, 20 Jan 2026 08:31:45 +1100 Subject: [PATCH 06/22] chore: Mostly finished s3 config --- cli/Cargo.lock | 1360 +++++++++++-------------- cli/Cargo.toml | 5 +- cli/src/cli.rs | 5 +- cli/src/commands/upload/interface.rs | 20 +- cli/src/commands/upload/mod.rs | 3 +- cli/src/commands/upload/s3.rs | 58 +- cli/src/commands/upload/speedtest.rs | 33 + cli/src/commands/upload/uploadable.rs | 15 +- cli/src/commands/upload/void.rs | 8 +- cli/src/config.rs | 67 ++ cli/src/main.rs | 19 +- cli/src/manifest.rs | 2 - 12 files changed, 775 insertions(+), 820 deletions(-) create mode 100644 cli/src/commands/upload/speedtest.rs create mode 100644 cli/src/config.rs diff --git a/cli/Cargo.lock b/cli/Cargo.lock index 1973d175..aec11375 100644 --- a/cli/Cargo.lock +++ b/cli/Cargo.lock @@ -2,12 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "allocator-api2" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" - [[package]] name = "android_system_properties" version = "0.1.5" @@ -157,6 +151,21 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "attohttpc" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e2cdb6d5ed835199484bb92bb8b3edd526effe995c61732580439c1a67e2e9" +dependencies = [ + "base64", + "http", + "log", + "native-tls", + "serde", + "serde_json", + "url", +] + [[package]] name = "autocfg" version = "1.5.0" @@ -164,15 +173,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] -name = "aws-credential-types" -version = "1.2.11" +name = "aws-creds" +version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cd362783681b15d136480ad555a099e82ecd8e2d10a841e14dfd0078d67fee3" +checksum = "ca3b85155d265df828f84e53886ed9e427aed979dd8a39f5b8b2162c77e142d7" dependencies = [ - "aws-smithy-async", - "aws-smithy-runtime-api", - "aws-smithy-types", - "zeroize", + "attohttpc", + "home", + "log", + "quick-xml", + "rust-ini", + "serde", + "thiserror 2.0.17", + "time", + "url", ] [[package]] @@ -198,323 +212,20 @@ dependencies = [ ] [[package]] -name = "aws-runtime" -version = "1.5.18" +name = "aws-region" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "959dab27ce613e6c9658eb3621064d0e2027e5f2acb65bc526a43577facea557" +checksum = "838b36c8dc927b6db1b6c6b8f5d05865f2213550b9e83bf92fa99ed6525472c0" dependencies = [ - "aws-credential-types", - "aws-sigv4", - "aws-smithy-async", - "aws-smithy-eventstream", - "aws-smithy-http", - "aws-smithy-runtime", - "aws-smithy-runtime-api", - "aws-smithy-types", - "aws-types", - "bytes", - "fastrand", - "http 0.2.12", - "http-body 0.4.6", - "percent-encoding", - "pin-project-lite", - "tracing", - "uuid", + "thiserror 2.0.17", ] -[[package]] -name = "aws-sdk-s3" -version = "1.120.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06673901e961f20fa8d7da907da48f7ad6c1b383e3726c22bd418900f015abe1" -dependencies = [ - "aws-credential-types", - "aws-runtime", - "aws-sigv4", - "aws-smithy-async", - "aws-smithy-checksums", - "aws-smithy-eventstream", - "aws-smithy-http", - "aws-smithy-json", - "aws-smithy-observability", - "aws-smithy-runtime", - "aws-smithy-runtime-api", - "aws-smithy-types", - "aws-smithy-xml", - "aws-types", - "bytes", - "fastrand", - "hex", - "hmac", - "http 0.2.12", - "http 1.4.0", - "http-body 0.4.6", - "lru", - "percent-encoding", - "regex-lite", - "sha2", - "tracing", - "url", -] - -[[package]] -name = "aws-sigv4" -version = "1.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e523e1c4e8e7e8ff219d732988e22bfeae8a1cafdbe6d9eca1546fa080be7c" -dependencies = [ - "aws-credential-types", - "aws-smithy-eventstream", - "aws-smithy-http", - "aws-smithy-runtime-api", - "aws-smithy-types", - "bytes", - "crypto-bigint 0.5.5", - "form_urlencoded", - "hex", - "hmac", - "http 0.2.12", - "http 1.4.0", - "p256", - "percent-encoding", - "ring", - "sha2", - "subtle", - "time", - "tracing", - "zeroize", -] - -[[package]] -name = "aws-smithy-async" -version = "1.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ee19095c7c4dda59f1697d028ce704c24b2d33c6718790c7f1d5a3015b4107c" -dependencies = [ - "futures-util", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "aws-smithy-checksums" -version = "0.63.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23374b9170cbbcc6f5df8dc5ebb9b6c5c28a3c8f599f0e8b8b10eb6f4a5c6e74" -dependencies = [ - "aws-smithy-http", - "aws-smithy-types", - "bytes", - "crc-fast", - "hex", - "http 0.2.12", - "http-body 0.4.6", - "md-5", - "pin-project-lite", - "sha1", - "sha2", - "tracing", -] - -[[package]] -name = "aws-smithy-eventstream" -version = "0.60.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc12f8b310e38cad85cf3bef45ad236f470717393c613266ce0a89512286b650" -dependencies = [ - "aws-smithy-types", - "bytes", - "crc32fast", -] - -[[package]] -name = "aws-smithy-http" -version = "0.62.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826141069295752372f8203c17f28e30c464d22899a43a0c9fd9c458d469c88b" -dependencies = [ - "aws-smithy-eventstream", - "aws-smithy-runtime-api", - "aws-smithy-types", - "bytes", - "bytes-utils", - "futures-core", - "futures-util", - "http 0.2.12", - "http 1.4.0", - "http-body 0.4.6", - "percent-encoding", - "pin-project-lite", - "pin-utils", - "tracing", -] - -[[package]] -name = "aws-smithy-http-client" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59e62db736db19c488966c8d787f52e6270be565727236fd5579eaa301e7bc4a" -dependencies = [ - "aws-smithy-async", - "aws-smithy-runtime-api", - "aws-smithy-types", - "h2 0.3.27", - "h2 0.4.13", - "http 0.2.12", - "http 1.4.0", - "http-body 0.4.6", - "hyper 0.14.32", - "hyper 1.8.1", - "hyper-rustls 0.24.2", - "hyper-rustls 0.27.7", - "hyper-util", - "pin-project-lite", - "rustls 0.21.12", - "rustls 0.23.36", - "rustls-native-certs", - "rustls-pki-types", - "tokio", - "tokio-rustls 0.26.4", - "tower", - "tracing", -] - -[[package]] -name = "aws-smithy-json" -version = "0.61.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49fa1213db31ac95288d981476f78d05d9cbb0353d22cdf3472cc05bb02f6551" -dependencies = [ - "aws-smithy-types", -] - -[[package]] -name = "aws-smithy-observability" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef1fcbefc7ece1d70dcce29e490f269695dfca2d2bacdeaf9e5c3f799e4e6a42" -dependencies = [ - "aws-smithy-runtime-api", -] - -[[package]] -name = "aws-smithy-runtime" -version = "1.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb5b6167fcdf47399024e81ac08e795180c576a20e4d4ce67949f9a88ae37dc1" -dependencies = [ - "aws-smithy-async", - "aws-smithy-http", - "aws-smithy-http-client", - "aws-smithy-observability", - "aws-smithy-runtime-api", - "aws-smithy-types", - "bytes", - "fastrand", - "http 0.2.12", - "http 1.4.0", - "http-body 0.4.6", - "http-body 1.0.1", - "pin-project-lite", - "pin-utils", - "tokio", - "tracing", -] - -[[package]] -name = "aws-smithy-runtime-api" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efce7aaaf59ad53c5412f14fc19b2d5c6ab2c3ec688d272fd31f76ec12f44fb0" -dependencies = [ - "aws-smithy-async", - "aws-smithy-types", - "bytes", - "http 0.2.12", - "http 1.4.0", - "pin-project-lite", - "tokio", - "tracing", - "zeroize", -] - -[[package]] -name = "aws-smithy-types" -version = "1.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65f172bcb02424eb94425db8aed1b6d583b5104d4d5ddddf22402c661a320048" -dependencies = [ - "base64-simd", - "bytes", - "bytes-utils", - "futures-core", - "http 0.2.12", - "http 1.4.0", - "http-body 0.4.6", - "http-body 1.0.1", - "http-body-util", - "itoa", - "num-integer", - "pin-project-lite", - "pin-utils", - "ryu", - "serde", - "time", - "tokio", - "tokio-util", -] - -[[package]] -name = "aws-smithy-xml" -version = "0.60.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11b2f670422ff42bf7065031e72b45bc52a3508bd089f743ea90731ca2b6ea57" -dependencies = [ - "xmlparser", -] - -[[package]] -name = "aws-types" -version = "1.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d980627d2dd7bfc32a3c025685a033eeab8d365cc840c631ef59d1b8f428164" -dependencies = [ - "aws-credential-types", - "aws-smithy-async", - "aws-smithy-runtime-api", - "aws-smithy-types", - "rustc_version", - "tracing", -] - -[[package]] -name = "base16ct" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" - [[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "base64-simd" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195" -dependencies = [ - "outref", - "vsimd", -] - -[[package]] -name = "base64ct" -version = "1.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" - [[package]] name = "bitflags" version = "2.10.0" @@ -543,13 +254,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" [[package]] -name = "bytes-utils" -version = "0.1.4" +name = "castaway" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dafe3a8757b027e2be6e4e5601ed563c55989fcf1546e933c66c8eb3a058d35" +checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" dependencies = [ - "bytes", - "either", + "rustversion", ] [[package]] @@ -592,7 +302,7 @@ dependencies = [ "js-sys", "num-traits", "wasm-bindgen", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -670,6 +380,19 @@ dependencies = [ "memchr", ] +[[package]] +name = "compact_str" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f" +dependencies = [ + "castaway", + "cfg-if", + "itoa", + "ryu", + "static_assertions", +] + [[package]] name = "console" version = "0.16.2" @@ -684,10 +407,24 @@ dependencies = [ ] [[package]] -name = "const-oid" -version = "0.9.6" +name = "const-random" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom 0.2.16", + "once_cell", + "tiny-keccak", +] [[package]] name = "core-foundation" @@ -725,62 +462,10 @@ dependencies = [ ] [[package]] -name = "crc" -version = "3.3.0" +name = "crunchy" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" -dependencies = [ - "crc-catalog", -] - -[[package]] -name = "crc-catalog" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" - -[[package]] -name = "crc-fast" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd92aca2c6001b1bf5ba0ff84ee74ec8501b52bbef0cac80bf25a6c1d87a83d" -dependencies = [ - "crc", - "digest", - "rustversion", - "spin", -] - -[[package]] -name = "crc32fast" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crypto-bigint" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" -dependencies = [ - "generic-array", - "rand_core 0.6.4", - "subtle", - "zeroize", -] - -[[package]] -name = "crypto-bigint" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" -dependencies = [ - "rand_core 0.6.4", - "subtle", -] +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "crypto-common" @@ -798,16 +483,6 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" -[[package]] -name = "der" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" -dependencies = [ - "const-oid", - "zeroize", -] - [[package]] name = "der-parser" version = "9.0.0" @@ -843,6 +518,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", + "serde_core", ] [[package]] @@ -879,12 +555,21 @@ dependencies = [ "syn", ] +[[package]] +name = "dlv-list" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f" +dependencies = [ + "const-random", +] + [[package]] name = "downpour" version = "0.1.0" dependencies = [ "anyhow", - "aws-sdk-s3", + "async-trait", "chrono", "clap", "console", @@ -893,10 +578,13 @@ dependencies = [ "fern", "indicatif", "log", - "reqwest", + "rand", + "reqwest 0.13.1", + "rust-s3", "serde", "serde_json", "tokio", + "tokio-util", "url", "webbrowser", ] @@ -936,44 +624,6 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" -[[package]] -name = "ecdsa" -version = "0.14.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" -dependencies = [ - "der", - "elliptic-curve", - "rfc6979", - "signature", -] - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - -[[package]] -name = "elliptic-curve" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" -dependencies = [ - "base16ct", - "crypto-bigint 0.4.9", - "der", - "digest", - "ff", - "generic-array", - "group", - "pkcs8", - "rand_core 0.6.4", - "sec1", - "subtle", - "zeroize", -] - [[package]] name = "encode_unicode" version = "1.0.0" @@ -1021,16 +671,6 @@ dependencies = [ "log", ] -[[package]] -name = "ff" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" -dependencies = [ - "rand_core 0.6.4", - "subtle", -] - [[package]] name = "find-msvc-tools" version = "0.1.5" @@ -1044,10 +684,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] -name = "foldhash" -version = "0.2.0" +name = "foreign-types" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" @@ -1190,36 +839,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "group" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" -dependencies = [ - "ff", - "rand_core 0.6.4", - "subtle", -] - -[[package]] -name = "h2" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http 0.2.12", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - [[package]] name = "h2" version = "0.4.13" @@ -1231,7 +850,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http 1.4.0", + "http", "indexmap", "slab", "tokio", @@ -1239,16 +858,17 @@ dependencies = [ "tracing", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + [[package]] name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" -dependencies = [ - "allocator-api2", - "equivalent", - "foldhash", -] [[package]] name = "heck" @@ -1272,14 +892,12 @@ dependencies = [ ] [[package]] -name = "http" -version = "0.2.12" +name = "home" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" dependencies = [ - "bytes", - "fnv", - "itoa", + "windows-sys 0.61.2", ] [[package]] @@ -1292,17 +910,6 @@ dependencies = [ "itoa", ] -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.12", - "pin-project-lite", -] - [[package]] name = "http-body" version = "1.0.1" @@ -1310,7 +917,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.4.0", + "http", ] [[package]] @@ -1321,8 +928,8 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http 1.4.0", - "http-body 1.0.1", + "http", + "http-body", "pin-project-lite", ] @@ -1332,12 +939,6 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - [[package]] name = "humansize" version = "2.1.3" @@ -1347,30 +948,6 @@ dependencies = [ "libm", ] -[[package]] -name = "hyper" -version = "0.14.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2 0.3.27", - "http 0.2.12", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2 0.5.10", - "tokio", - "tower-service", - "tracing", - "want", -] - [[package]] name = "hyper" version = "1.8.1" @@ -1381,9 +958,9 @@ dependencies = [ "bytes", "futures-channel", "futures-core", - "h2 0.4.13", - "http 1.4.0", - "http-body 1.0.1", + "h2", + "http", + "http-body", "httparse", "itoa", "pin-project-lite", @@ -1393,35 +970,35 @@ dependencies = [ "want", ] -[[package]] -name = "hyper-rustls" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" -dependencies = [ - "futures-util", - "http 0.2.12", - "hyper 0.14.32", - "log", - "rustls 0.21.12", - "tokio", - "tokio-rustls 0.24.1", -] - [[package]] name = "hyper-rustls" version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "http 1.4.0", - "hyper 1.8.1", + "http", + "hyper", "hyper-util", - "rustls 0.23.36", - "rustls-native-certs", + "rustls", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.4", + "tokio-rustls", + "tower-service", +] + +[[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", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", "tower-service", ] @@ -1436,14 +1013,14 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "http 1.4.0", - "http-body 1.0.1", - "hyper 1.8.1", + "http", + "http-body", + "hyper", "ipnet", "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.1", + "socket2", "system-configuration", "tokio", "tower-service", @@ -1463,7 +1040,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core", + "windows-core 0.62.2", ] [[package]] @@ -1584,7 +1161,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.16.1", ] [[package]] @@ -1706,15 +1283,6 @@ version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" -[[package]] -name = "lru" -version = "0.16.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1dc47f592c06f33f8e3aea9591776ec7c9f9e4124778ff8a3c3b87159f7e593" -dependencies = [ - "hashbrown", -] - [[package]] name = "lru-slab" version = "0.1.2" @@ -1722,15 +1290,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" [[package]] -name = "md-5" -version = "0.10.6" +name = "maybe-async" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" dependencies = [ - "cfg-if", - "digest", + "proc-macro2", + "quote", + "syn", ] +[[package]] +name = "md5" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae960838283323069879657ca3de837e9f7bbb4c7bf6ea7f1b290d5e9476d2e0" + [[package]] name = "memchr" version = "2.7.6" @@ -1743,6 +1318,15 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "minidom" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e394a0e3c7ccc2daea3dffabe82f09857b6b510cb25af87d54bf3e910ac1642d" +dependencies = [ + "rxml", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -1760,6 +1344,23 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe 0.1.6", + "openssl-sys", + "schannel", + "security-framework 2.11.1", + "security-framework-sys", + "tempfile", +] + [[package]] name = "ndk-context" version = "0.1.1" @@ -1776,6 +1377,15 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "ntapi" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c70f219e21142367c70c0b30c6a9e3a14d55b4d12a204d897fbec83a0363f081" +dependencies = [ + "winapi", +] + [[package]] name = "num-bigint" version = "0.4.6" @@ -1819,6 +1429,15 @@ dependencies = [ "objc2-encode", ] +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags", +] + [[package]] name = "objc2-encode" version = "4.1.0" @@ -1835,6 +1454,16 @@ dependencies = [ "objc2", ] +[[package]] +name = "objc2-io-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15" +dependencies = [ + "libc", + "objc2-core-foundation", +] + [[package]] name = "oid-registry" version = "0.7.1" @@ -1865,6 +1494,38 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +[[package]] +name = "openssl" +version = "0.10.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + [[package]] name = "openssl-probe" version = "0.2.0" @@ -1872,20 +1533,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f50d9b3dabb09ecd771ad0aa242ca6894994c130308ca3d7684634df8037391" [[package]] -name = "outref" -version = "0.5.2" +name = "openssl-sys" +version = "0.9.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] [[package]] -name = "p256" -version = "0.11.1" +name = "ordered-multimap" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594" +checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79" dependencies = [ - "ecdsa", - "elliptic-curve", - "sha2", + "dlv-list", + "hashbrown 0.14.5", ] [[package]] @@ -1917,14 +1583,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] -name = "pkcs8" -version = "0.9.0" +name = "pkg-config" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" -dependencies = [ - "der", - "spki", -] +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "portable-atomic" @@ -1965,6 +1627,16 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "quick-xml" +version = "0.38.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "quinn" version = "0.11.9" @@ -1977,8 +1649,8 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.23.36", - "socket2 0.6.1", + "rustls", + "socket2", "thiserror 2.0.17", "tokio", "tracing", @@ -1998,7 +1670,7 @@ dependencies = [ "rand", "ring", "rustc-hash", - "rustls 0.23.36", + "rustls", "rustls-pki-types", "slab", "thiserror 2.0.17", @@ -2016,7 +1688,7 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.1", + "socket2", "tracing", "windows-sys 0.60.2", ] @@ -2043,7 +1715,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha", - "rand_core 0.9.3", + "rand_core", ] [[package]] @@ -2053,16 +1725,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.3", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.16", + "rand_core", ] [[package]] @@ -2089,10 +1752,43 @@ dependencies = [ ] [[package]] -name = "regex-lite" -version = "0.1.8" +name = "reqwest" +version = "0.12.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d942b98df5e658f56f20d592c7f868833fe38115e65c33003d8cd224b0155da" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-tls", + "hyper-util", + "js-sys", + "log", + "native-tls", + "percent-encoding", + "pin-project-lite", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-native-tls", + "tokio-util", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", +] [[package]] name = "reqwest" @@ -2104,12 +1800,12 @@ dependencies = [ "bytes", "encoding_rs", "futures-core", - "h2 0.4.13", - "http 1.4.0", - "http-body 1.0.1", + "h2", + "http", + "http-body", "http-body-util", - "hyper 1.8.1", - "hyper-rustls 0.27.7", + "hyper", + "hyper-rustls", "hyper-util", "js-sys", "log", @@ -2117,14 +1813,14 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.36", + "rustls", "rustls-pki-types", "rustls-platform-verifier", "serde", "serde_json", "sync_wrapper", "tokio", - "tokio-rustls 0.26.4", + "tokio-rustls", "tower", "tower-http", "tower-service", @@ -2134,17 +1830,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "rfc6979" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" -dependencies = [ - "crypto-bigint 0.4.9", - "hmac", - "zeroize", -] - [[package]] name = "ring" version = "0.17.14" @@ -2159,21 +1844,57 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rust-ini" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "796e8d2b6696392a43bea58116b667fb4c29727dc5abd27d6acf338bb4f688c7" +dependencies = [ + "cfg-if", + "ordered-multimap", +] + +[[package]] +name = "rust-s3" +version = "0.37.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4af74047374528b627109d579ce86b23ccf6ffba7ff363c807126c1aff69e1bb" +dependencies = [ + "async-trait", + "aws-creds", + "aws-region", + "base64", + "bytes", + "cfg-if", + "futures-util", + "hex", + "hmac", + "http", + "log", + "maybe-async", + "md5", + "minidom", + "percent-encoding", + "quick-xml", + "reqwest 0.12.28", + "serde", + "serde_derive", + "serde_json", + "sha2", + "sysinfo", + "thiserror 2.0.17", + "time", + "tokio", + "tokio-stream", + "url", +] + [[package]] name = "rustc-hash" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - [[package]] name = "rusticata-macros" version = "4.1.0" @@ -2196,18 +1917,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "rustls" -version = "0.21.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" -dependencies = [ - "log", - "ring", - "rustls-webpki 0.101.7", - "sct", -] - [[package]] name = "rustls" version = "0.23.36" @@ -2217,7 +1926,7 @@ dependencies = [ "aws-lc-rs", "once_cell", "rustls-pki-types", - "rustls-webpki 0.103.8", + "rustls-webpki", "subtle", "zeroize", ] @@ -2228,10 +1937,10 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" dependencies = [ - "openssl-probe", + "openssl-probe 0.2.0", "rustls-pki-types", "schannel", - "security-framework", + "security-framework 3.5.1", ] [[package]] @@ -2255,11 +1964,11 @@ dependencies = [ "jni", "log", "once_cell", - "rustls 0.23.36", + "rustls", "rustls-native-certs", "rustls-platform-verifier-android", - "rustls-webpki 0.103.8", - "security-framework", + "rustls-webpki", + "security-framework 3.5.1", "security-framework-sys", "webpki-root-certs", "windows-sys 0.61.2", @@ -2271,16 +1980,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" -[[package]] -name = "rustls-webpki" -version = "0.101.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "rustls-webpki" version = "0.103.8" @@ -2299,6 +1998,25 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +[[package]] +name = "rxml" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc94b580d0f5a6b7a2d604e597513d3c673154b52ddeccd1d5c32360d945ee" +dependencies = [ + "bytes", + "rxml_validation", +] + +[[package]] +name = "rxml_validation" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826e80413b9a35e9d33217b3dcac04cf95f6559d15944b93887a08be5496c4a4" +dependencies = [ + "compact_str", +] + [[package]] name = "ryu" version = "1.0.22" @@ -2324,27 +2042,16 @@ dependencies = [ ] [[package]] -name = "sct" -version = "0.7.1" +name = "security-framework" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "sec1" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" -dependencies = [ - "base16ct", - "der", - "generic-array", - "pkcs8", - "subtle", - "zeroize", + "bitflags", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", ] [[package]] @@ -2370,12 +2077,6 @@ dependencies = [ "libc", ] -[[package]] -name = "semver" -version = "1.0.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" - [[package]] name = "serde" version = "1.0.228" @@ -2420,14 +2121,15 @@ dependencies = [ ] [[package]] -name = "sha1" -version = "0.10.6" +name = "serde_urlencoded" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ - "cfg-if", - "cpufeatures", - "digest", + "form_urlencoded", + "itoa", + "ryu", + "serde", ] [[package]] @@ -2462,16 +2164,6 @@ dependencies = [ "libc", ] -[[package]] -name = "signature" -version = "1.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" -dependencies = [ - "digest", - "rand_core 0.6.4", -] - [[package]] name = "slab" version = "0.4.11" @@ -2484,16 +2176,6 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" -[[package]] -name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - [[package]] name = "socket2" version = "0.6.1" @@ -2504,28 +2186,18 @@ dependencies = [ "windows-sys 0.60.2", ] -[[package]] -name = "spin" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" - -[[package]] -name = "spki" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" -dependencies = [ - "base64ct", - "der", -] - [[package]] name = "stable_deref_trait" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strsim" version = "0.11.1" @@ -2569,6 +2241,20 @@ dependencies = [ "syn", ] +[[package]] +name = "sysinfo" +version = "0.37.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16607d5caffd1c07ce073528f9ed972d88db15dd44023fa57142963be3feb11f" +dependencies = [ + "libc", + "memchr", + "ntapi", + "objc2-core-foundation", + "objc2-io-kit", + "windows", +] + [[package]] name = "system-configuration" version = "0.6.1" @@ -2674,6 +2360,15 @@ dependencies = [ "time-core", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinystr" version = "0.8.2" @@ -2710,7 +2405,7 @@ dependencies = [ "mio", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.1", + "socket2", "tokio-macros", "windows-sys 0.61.2", ] @@ -2727,12 +2422,12 @@ dependencies = [ ] [[package]] -name = "tokio-rustls" -version = "0.24.1" +name = "tokio-native-tls" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" dependencies = [ - "rustls 0.21.12", + "native-tls", "tokio", ] @@ -2742,7 +2437,18 @@ version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls 0.23.36", + "rustls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" +dependencies = [ + "futures-core", + "pin-project-lite", "tokio", ] @@ -2783,8 +2489,8 @@ dependencies = [ "bitflags", "bytes", "futures-util", - "http 1.4.0", - "http-body 1.0.1", + "http", + "http-body", "iri-string", "pin-project-lite", "tower", @@ -2811,21 +2517,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "pin-project-lite", - "tracing-attributes", "tracing-core", ] -[[package]] -name = "tracing-attributes" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "tracing-core" version = "0.1.36" @@ -2906,18 +2600,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" -[[package]] -name = "vsimd" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" - [[package]] name = "walkdir" version = "2.5.0" @@ -3010,6 +2704,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-streams" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "web-sys" version = "0.3.83" @@ -3055,6 +2762,22 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + [[package]] name = "winapi-util" version = "0.1.11" @@ -3064,6 +2787,47 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.61.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections", + "windows-core 0.61.2", + "windows-future", + "windows-link 0.1.3", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core 0.61.2", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.4.2", +] + [[package]] name = "windows-core" version = "0.62.2" @@ -3072,9 +2836,20 @@ checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", - "windows-link", - "windows-result", - "windows-strings", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", + "windows-threading", ] [[package]] @@ -3099,21 +2874,46 @@ dependencies = [ "syn", ] +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", +] + [[package]] name = "windows-registry" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" dependencies = [ - "windows-link", - "windows-result", - "windows-strings", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link 0.1.3", ] [[package]] @@ -3122,7 +2922,16 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-link", + "windows-link 0.2.1", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", ] [[package]] @@ -3131,7 +2940,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -3167,7 +2976,7 @@ version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -3207,7 +3016,7 @@ version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows-link", + "windows-link 0.2.1", "windows_aarch64_gnullvm 0.53.1", "windows_aarch64_msvc 0.53.1", "windows_i686_gnu 0.53.1", @@ -3218,6 +3027,15 @@ dependencies = [ "windows_x86_64_msvc 0.53.1", ] +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link 0.1.3", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -3404,12 +3222,6 @@ dependencies = [ "time", ] -[[package]] -name = "xmlparser" -version = "0.13.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" - [[package]] name = "yasna" version = "0.5.2" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index de7ab3b7..be242caa 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] anyhow = "1.0.100" -aws-sdk-s3 = "1.120.0" +async-trait = "0.1.89" chrono = "0.4.43" clap = { version = "4.5.54", features = ["derive"] } console = "0.16.2" @@ -14,9 +14,12 @@ droplet-rs = { git = "https://github.com/Drop-OSS/droplet-rs.git", version = "0. fern = { version = "0.7.1", features = ["colored"] } indicatif = "0.18.3" log = "0.4.29" +rand = "0.9.2" reqwest = { version = "0.13.1", features = ["json"] } +rust-s3 = "0.37.1" serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0.148" tokio = { version = "1.48.0", features = ["macros"] } +tokio-util = "0.7.18" url = "2.5.8" webbrowser = "1.0.6" diff --git a/cli/src/cli.rs b/cli/src/cli.rs index b420d07d..96e11d2b 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -28,9 +28,9 @@ pub enum Commands { } #[derive(Args)] pub struct UploadInfo { - /// Sets + /// Identifies the specific upload style that will be used for the set depot pub upload_style: UploadStyle, - /// Path of new version + /// Relative path to new version files #[arg(short, long)] pub path: PathBuf, /// ID of game to attach to @@ -44,5 +44,4 @@ pub struct UploadInfo { #[derive(ValueEnum, Copy, Clone, Debug, PartialEq, Eq)] pub enum UploadStyle { S3, - Nginx, } diff --git a/cli/src/commands/upload/interface.rs b/cli/src/commands/upload/interface.rs index a88f1f94..c4e81834 100644 --- a/cli/src/commands/upload/interface.rs +++ b/cli/src/commands/upload/interface.rs @@ -2,33 +2,39 @@ use std::path::Path; use crate::{ cli::UploadInfo, - commands::upload::{uploadable::Uploadable, void::VoidUploadable}, + commands::upload::{s3::S3, uploadable::Uploadable}, + config::Config, manifest::generate_manifest, }; use log::info; -pub async fn upload(info: &UploadInfo) -> anyhow::Result<()> { +pub async fn upload(info: &UploadInfo, config: Config) -> anyhow::Result<()> { let game_id = &info.game_id; let path = &info.path; let version_id = &info.version_id; let manifest = generate_manifest(&Path::new(path)).await?; let mut uploader: Box = match info.upload_style { - crate::cli::UploadStyle::S3 => Box::new(VoidUploadable::new()), - crate::cli::UploadStyle::Nginx => Box::new(VoidUploadable::new()), + crate::cli::UploadStyle::S3 => Box::new(S3::new( + config + .get_active_s3() + .ok_or(anyhow::Error::msg("Could not get active S3 value"))?, + )?), }; info!("Uploading chunks"); for (id, data) in &manifest.chunks { info!("Uploading chunk id {id}"); - uploader.upload_chunk(game_id, version_id, id, data)?; + uploader.upload_chunk(game_id, version_id, id, data).await?; } info!("Finished uploading chunks"); info!("Uploading manifest"); - uploader.upload_manifest(manifest, game_id, version_id)?; + uploader + .upload_manifest(manifest, game_id, version_id) + .await?; info!("Uploading speedtest"); - uploader.upload_speedtest(game_id, version_id)?; + uploader.upload_speedtest().await?; Ok(()) } diff --git a/cli/src/commands/upload/mod.rs b/cli/src/commands/upload/mod.rs index e1c44a3a..8c948cde 100644 --- a/cli/src/commands/upload/mod.rs +++ b/cli/src/commands/upload/mod.rs @@ -1,4 +1,5 @@ pub mod interface; pub mod s3; pub mod uploadable; -pub mod void; \ No newline at end of file +pub mod void; +pub mod speedtest; \ No newline at end of file diff --git a/cli/src/commands/upload/s3.rs b/cli/src/commands/upload/s3.rs index c6a990bb..a838d29e 100644 --- a/cli/src/commands/upload/s3.rs +++ b/cli/src/commands/upload/s3.rs @@ -1,10 +1,29 @@ +use crate::{ + commands::upload::{ + speedtest::{SPEEDTEST_PATH, Speedtest}, + uploadable::Uploadable, + }, + config::S3Config, +}; +use async_trait::async_trait; use droplet_rs::manifest::{ChunkData, Manifest}; +use s3::{Bucket, creds::Credentials}; +use serde_json::json; +use std::{ops::Deref, path::PathBuf}; -use crate::commands::upload::uploadable::Uploadable; - -pub type S3 = aws_sdk_s3::Client; +pub struct S3 { + bucket: s3::Bucket, +} +impl S3 { + pub fn new(config: &S3Config) -> anyhow::Result { + Ok(Self { + bucket: config.generate_bucket()?, + }) + } +} +#[async_trait] impl Uploadable for S3 { - fn upload_chunk( + async fn upload_chunk( &mut self, id: &String, version: &String, @@ -13,16 +32,39 @@ impl Uploadable for S3 { ) -> anyhow::Result<()> { todo!() } - fn upload_speedtest(&mut self, game_id: &String, version_id: &String) -> anyhow::Result<()> { - todo!() + async fn upload_speedtest(&mut self) -> anyhow::Result<()> { + if self.object_exists(SPEEDTEST_PATH).await? { + return Ok(()); + } + let mut speedtest = Speedtest::new(); + self.put_object_stream(&mut speedtest, SPEEDTEST_PATH) + .await?; + Ok(()) } - fn upload_manifest( + async fn upload_manifest( &mut self, manifest: Manifest, game_id: &String, version_id: &String, ) -> anyhow::Result<()> { - todo!() + self.put_object( + PathBuf::from(game_id) + .join(version_id) + .join("manifest.json") + .to_string_lossy() + .to_string(), + json!(manifest).to_string().as_bytes(), + ) + .await?; + Ok(()) + } +} + +impl Deref for S3 { + type Target = Bucket; + + fn deref(&self) -> &Self::Target { + &self.bucket } } diff --git a/cli/src/commands/upload/speedtest.rs b/cli/src/commands/upload/speedtest.rs new file mode 100644 index 00000000..5cde5efa --- /dev/null +++ b/cli/src/commands/upload/speedtest.rs @@ -0,0 +1,33 @@ +use rand::{RngCore, SeedableRng, rng, rngs::StdRng}; +use tokio::io::AsyncRead; + +#[derive(Clone, Debug)] +pub struct Speedtest { + core: rand::rngs::StdRng, + to_write: usize, +} +pub const SPEEDTEST_BYTES: usize = 64 * 1024 * 1024; +pub const SPEEDTEST_PATH: &str = "speedtest"; + +impl AsyncRead for Speedtest { + fn poll_read( + self: std::pin::Pin<&mut Self>, + _cx: &mut std::task::Context<'_>, + buf: &mut tokio::io::ReadBuf<'_>, + ) -> std::task::Poll> { + let mut s = self; + let to_write = buf.remaining().min(s.to_write); + s.to_write = s.to_write.saturating_sub(to_write); + let fill_slice = buf.initialize_unfilled_to(to_write); + s.core.fill_bytes(fill_slice); + std::task::Poll::Ready(Ok(())) + } +} +impl Speedtest { + pub fn new() -> Self { + Self { + core: StdRng::from_rng(&mut rng()), + to_write: SPEEDTEST_BYTES, + } + } +} \ No newline at end of file diff --git a/cli/src/commands/upload/uploadable.rs b/cli/src/commands/upload/uploadable.rs index 9b2548e0..f8f40544 100644 --- a/cli/src/commands/upload/uploadable.rs +++ b/cli/src/commands/upload/uploadable.rs @@ -1,20 +1,15 @@ +use async_trait::async_trait; use droplet_rs::manifest::{ChunkData, Manifest}; +#[async_trait] pub trait Uploadable { - fn upload_chunk( + async fn upload_chunk( &mut self, id: &String, version: &String, chunk_id: &String, chunk: &ChunkData, ) -> anyhow::Result<()>; - fn upload_speedtest(&mut self, game_id: &String, version_id: &String) -> anyhow::Result<()>; - fn upload_manifest(&mut self, manifest: Manifest, game_id: &String, version_id: &String) -> anyhow::Result<()>; -} -pub enum UploadableConfig { - S3 { - api_secret: String, - api_key_identifier: String, - region: String, - }, + async fn upload_speedtest(&mut self) -> anyhow::Result<()>; + async fn upload_manifest(&mut self, manifest: Manifest, game_id: &String, version_id: &String) -> anyhow::Result<()>; } diff --git a/cli/src/commands/upload/void.rs b/cli/src/commands/upload/void.rs index 1a28358e..28503c8b 100644 --- a/cli/src/commands/upload/void.rs +++ b/cli/src/commands/upload/void.rs @@ -1,11 +1,13 @@ +use async_trait::async_trait; use droplet_rs::manifest::{ChunkData, Manifest}; use log::warn; use crate::commands::upload::uploadable::Uploadable; pub struct VoidUploadable; +#[async_trait] impl Uploadable for VoidUploadable { - fn upload_chunk( + async fn upload_chunk( &mut self, _id: &String, _version: &String, @@ -16,12 +18,12 @@ impl Uploadable for VoidUploadable { Ok(()) } - fn upload_speedtest(&mut self, _game_id: &String, _version_id: &String) -> anyhow::Result<()> { + async fn upload_speedtest(&mut self) -> anyhow::Result<()> { warn!("Uploading speedtest to VoidUploader"); Ok(()) } - fn upload_manifest( + async fn upload_manifest( &mut self, _manifest: Manifest, _game_id: &String, diff --git a/cli/src/config.rs b/cli/src/config.rs new file mode 100644 index 00000000..ef66a075 --- /dev/null +++ b/cli/src/config.rs @@ -0,0 +1,67 @@ +use std::str::FromStr; + +use s3::{Bucket, Region, creds::Credentials}; + +pub struct Config { + items: Vec, + active_s3: Option, +} +pub struct ConfigItem { + name: String, + config_option: ConfigOption, +} +enum ConfigOption { + S3(S3Config), +} +pub struct S3Config { + secret_key: String, + key_id: String, + region: String, + bucket_name: String, + endpoint: Option, +} +impl Config { + pub fn new() -> Self { + Self { + items: Vec::new(), + active_s3: None, + } + } + pub fn get_active_s3(&self) -> Option<&S3Config> { + if let Some(active_s3) = &self.active_s3 { + self.items + .iter() + .filter_map(|item| { + if item.name == *active_s3 { + match &item.config_option { + ConfigOption::S3(s3_config) => Some(s3_config), + } + } else { + None + } + }) + .next() + } else { + None + } + } +} +impl S3Config { + pub fn generate_bucket(&self) -> anyhow::Result { + let credentials = + Credentials::new(Some(&self.key_id), Some(&self.secret_key), None, None, None)?; + + let region = if let Some(endpoint) = &self.endpoint { + Region::Custom { + region: self.region.clone(), + endpoint: endpoint.clone(), + } + } else { + Region::from_str(&self.region)? + }; + + let bucket = Bucket::new(&self.bucket_name, region, credentials)?; + + Ok(*bucket) + } +} diff --git a/cli/src/main.rs b/cli/src/main.rs index 5c62aa46..0d0fc98b 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,6 +1,6 @@ use crate::{ cli::{Cli, Commands}, - commands::{configure::interactive_configure, upload}, + commands::{configure::interactive_configure, upload}, config::Config, }; use clap::Parser; use fern::colors::{Color, ColoredLevelConfig}; @@ -8,15 +8,16 @@ use log::LevelFilter; use std::env; use std::fs; use std::io; - mod cli; mod commands; +mod config; mod manifest; #[tokio::main] async fn main() -> anyhow::Result<()> { configure_logging()?; let cli = Cli::parse(); + let config = Config::new(); match &cli.command { Commands::Configure { url, token } => { if let Some(token) = token { @@ -25,7 +26,7 @@ async fn main() -> anyhow::Result<()> { } } Commands::Upload(info) => { - upload::interface::upload(info).await?; + upload::interface::upload(info, config).await?; } }; @@ -34,7 +35,6 @@ async fn main() -> anyhow::Result<()> { pub fn configure_logging() -> anyhow::Result<()> { let log_level = env::var("RUST_LOG") - .or_else(|_| env::var("LOG_LEVEL")) .unwrap_or_else(|_| "info".to_string()) .parse::()?; @@ -45,27 +45,24 @@ pub fn configure_logging() -> anyhow::Result<()> { let colors = ColoredLevelConfig::new() .error(Color::Red) .warn(Color::Yellow) - .info(Color::Green) - .debug(Color::Blue) + .info(Color::Blue) + .debug(Color::Green) .trace(Color::Magenta); fern::Dispatch::new() .chain( - // Console output with colors and formatting fern::Dispatch::new() .format(move |out, message, record| { out.finish(format_args!( - "[{}] {} {} - {}", - chrono::Local::now().format("%Y-%m-%d %H:%M:%S%.3f"), + "[{}] {}: {}", + chrono::Local::now().format("%H:%M:%S%.3f"), colors.color(record.level()), - record.target(), message )) }) .chain(io::stdout()), ) .chain( - // File output without colors and with formatting fern::Dispatch::new() .format(|out, message, record| { out.finish(format_args!( diff --git a/cli/src/manifest.rs b/cli/src/manifest.rs index 5c89af38..0953fb43 100644 --- a/cli/src/manifest.rs +++ b/cli/src/manifest.rs @@ -1,6 +1,4 @@ use std::{ - fs, - io::{Read, Seek}, path::Path, }; From a3cc54f8a67a403d368c1ccf3a90fbab83c77479 Mon Sep 17 00:00:00 2001 From: quexeky Date: Tue, 20 Jan 2026 17:44:33 +1100 Subject: [PATCH 07/22] feat: CLI Configuration and maintainability --- cli/.gitignore | 3 +- cli/Cargo.lock | 400 ++++++++++++++++++++++++++- cli/Cargo.toml | 3 + cli/flake.nix | 1 + cli/src/cli.rs | 12 +- cli/src/commands/upload/interface.rs | 7 +- cli/src/commands/upload/mod.rs | 3 +- cli/src/commands/upload/s3.rs | 5 +- cli/src/commands/upload/void.rs | 40 --- cli/src/config.rs | 67 ----- cli/src/config/config.rs | 90 ++++++ cli/src/config/configurable.rs | 7 + cli/src/config/mod.rs | 4 + cli/src/config/s3.rs | 72 +++++ cli/src/config/server.rs | 18 ++ cli/src/interactive.rs | 47 ++++ cli/src/main.rs | 29 +- 17 files changed, 672 insertions(+), 136 deletions(-) delete mode 100644 cli/src/commands/upload/void.rs delete mode 100644 cli/src/config.rs create mode 100644 cli/src/config/config.rs create mode 100644 cli/src/config/configurable.rs create mode 100644 cli/src/config/mod.rs create mode 100644 cli/src/config/s3.rs create mode 100644 cli/src/config/server.rs create mode 100644 cli/src/interactive.rs diff --git a/cli/.gitignore b/cli/.gitignore index b13d16da..9c242044 100644 --- a/cli/.gitignore +++ b/cli/.gitignore @@ -1,2 +1,3 @@ /target -logs/ \ No newline at end of file +logs/ +.vscode \ No newline at end of file diff --git a/cli/Cargo.lock b/cli/Cargo.lock index aec11375..524ea235 100644 --- a/cli/Cargo.lock +++ b/cli/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "addr2line" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -220,6 +235,21 @@ dependencies = [ "thiserror 2.0.17", ] +[[package]] +name = "backtrace" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-link 0.2.1", +] + [[package]] name = "base64" version = "0.22.1" @@ -354,6 +384,33 @@ dependencies = [ "cc", ] +[[package]] +name = "color-eyre" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5920befb47832a6d61ee3a3a846565cfa39b331331e68a3b1d1116630f2f26d" +dependencies = [ + "backtrace", + "color-spantrace", + "eyre", + "indenter", + "once_cell", + "owo-colors", + "tracing-error", +] + +[[package]] +name = "color-spantrace" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8b88ea9df13354b55bc7234ebcce36e6ef896aca2e42a15de9e10edce01b427" +dependencies = [ + "once_cell", + "owo-colors", + "tracing-core", + "tracing-error", +] + [[package]] name = "colorchoice" version = "1.0.4" @@ -426,6 +483,15 @@ dependencies = [ "tiny-keccak", ] +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -461,6 +527,33 @@ dependencies = [ "libc", ] +[[package]] +name = "crossterm" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" +dependencies = [ + "bitflags", + "crossterm_winapi", + "derive_more", + "document-features", + "mio", + "parking_lot", + "rustix", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +dependencies = [ + "winapi", +] + [[package]] name = "crunchy" version = "0.2.4" @@ -521,6 +614,28 @@ dependencies = [ "serde_core", ] +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn", +] + [[package]] name = "dialoguer" version = "0.12.0" @@ -544,6 +659,27 @@ dependencies = [ "subtle", ] +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.61.2", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -564,6 +700,15 @@ dependencies = [ "const-random", ] +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + [[package]] name = "downpour" version = "0.1.0" @@ -572,11 +717,14 @@ dependencies = [ "async-trait", "chrono", "clap", + "color-eyre", "console", "dialoguer", + "dirs", "droplet-rs", "fern", "indicatif", + "inquire", "log", "rand", "reqwest 0.13.1", @@ -655,6 +803,16 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "eyre" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +dependencies = [ + "indenter", + "once_cell", +] + [[package]] name = "fastrand" version = "2.3.0" @@ -802,6 +960,15 @@ dependencies = [ "slab", ] +[[package]] +name = "fuzzy-matcher" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94" +dependencies = [ + "thread_local", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -839,6 +1006,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gimli" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" + [[package]] name = "h2" version = "0.4.13" @@ -1154,6 +1327,12 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "indenter" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5" + [[package]] name = "indexmap" version = "2.12.1" @@ -1177,6 +1356,20 @@ dependencies = [ "web-time", ] +[[package]] +name = "inquire" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae51d5da01ce7039024fbdec477767c102c454dbdb09d4e2a432ece705b1b25d" +dependencies = [ + "bitflags", + "crossterm", + "dyn-clone", + "fuzzy-matcher", + "unicode-segmentation", + "unicode-width", +] + [[package]] name = "ipnet" version = "2.11.0" @@ -1265,6 +1458,16 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +[[package]] +name = "libredox" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +dependencies = [ + "bitflags", + "libc", +] + [[package]] name = "linux-raw-sys" version = "0.11.0" @@ -1277,6 +1480,21 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + [[package]] name = "log" version = "0.4.29" @@ -1333,6 +1551,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + [[package]] name = "mio" version = "1.1.1" @@ -1340,6 +1567,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", + "log", "wasi", "windows-sys 0.61.2", ] @@ -1464,6 +1692,15 @@ dependencies = [ "objc2-core-foundation", ] +[[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] + [[package]] name = "oid-registry" version = "0.7.1" @@ -1544,6 +1781,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "ordered-multimap" version = "0.7.3" @@ -1554,6 +1797,35 @@ dependencies = [ "hashbrown 0.14.5", ] +[[package]] +name = "owo-colors" +version = "4.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link 0.2.1", +] + [[package]] name = "pem" version = "3.0.6" @@ -1695,9 +1967,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.42" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" dependencies = [ "proc-macro2", ] @@ -1751,6 +2023,26 @@ dependencies = [ "yasna", ] +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom 0.2.16", + "libredox", + "thiserror 2.0.17", +] + [[package]] name = "reqwest" version = "0.12.28" @@ -1889,12 +2181,27 @@ dependencies = [ "url", ] +[[package]] +name = "rustc-demangle" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" + [[package]] name = "rustc-hash" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rusticata-macros" version = "4.1.0" @@ -2041,6 +2348,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "security-framework" version = "2.11.1" @@ -2077,6 +2390,12 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + [[package]] name = "serde" version = "1.0.228" @@ -2143,6 +2462,15 @@ dependencies = [ "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 = "shell-words" version = "1.1.1" @@ -2155,6 +2483,27 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "signal-hook" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc" +dependencies = [ + "libc", + "mio", + "signal-hook", +] + [[package]] name = "signal-hook-registry" version = "1.4.7" @@ -2212,9 +2561,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.111" +version = "2.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" dependencies = [ "proc-macro2", "quote", @@ -2329,6 +2678,15 @@ dependencies = [ "syn", ] +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + [[package]] name = "time" version = "0.3.44" @@ -2527,6 +2885,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-error" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" +dependencies = [ + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +dependencies = [ + "sharded-slab", + "thread_local", + "tracing-core", ] [[package]] @@ -2547,6 +2927,12 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + [[package]] name = "unicode-width" version = "0.2.2" @@ -2600,6 +2986,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + [[package]] name = "vcpkg" version = "0.2.15" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index be242caa..0d407dd5 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -10,6 +10,7 @@ chrono = "0.4.43" clap = { version = "4.5.54", features = ["derive"] } console = "0.16.2" dialoguer = "0.12.0" +dirs = "6.0.0" droplet-rs = { git = "https://github.com/Drop-OSS/droplet-rs.git", version = "0.14" } fern = { version = "0.7.1", features = ["colored"] } indicatif = "0.18.3" @@ -23,3 +24,5 @@ tokio = { version = "1.48.0", features = ["macros"] } tokio-util = "0.7.18" url = "2.5.8" webbrowser = "1.0.6" +color-eyre = "0.6.5" +inquire = "0.9.2" diff --git a/cli/flake.nix b/cli/flake.nix index e196f2cc..e98989c5 100644 --- a/cli/flake.nix +++ b/cli/flake.nix @@ -34,6 +34,7 @@ git rust-bin.nightly.latest.default rust-analyzer + cargo-expand ]; diff --git a/cli/src/cli.rs b/cli/src/cli.rs index 96e11d2b..944b95ad 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -2,6 +2,8 @@ use std::path::PathBuf; use clap::{Args, Parser, Subcommand, ValueEnum}; +use crate::config::config::ConfigOption; + #[derive(Parser)] #[command(version, about, long_about = None)] pub struct Cli { @@ -16,16 +18,12 @@ pub struct Cli { #[derive(Subcommand)] pub enum Commands { /// Configures a new Drop server - Configure { - /// Endpoint of the Drop server - url: String, - /// API token for non-interactive configuration. - #[arg(short, long)] - token: Option, - }, + #[command(subcommand)] + Configure(ConfigOption), /// Uploads new game version to depot Upload(UploadInfo), } + #[derive(Args)] pub struct UploadInfo { /// Identifies the specific upload style that will be used for the set depot diff --git a/cli/src/commands/upload/interface.rs b/cli/src/commands/upload/interface.rs index c4e81834..dbcbd988 100644 --- a/cli/src/commands/upload/interface.rs +++ b/cli/src/commands/upload/interface.rs @@ -1,10 +1,7 @@ use std::path::Path; use crate::{ - cli::UploadInfo, - commands::upload::{s3::S3, uploadable::Uploadable}, - config::Config, - manifest::generate_manifest, + cli::UploadInfo, commands::upload::{s3::S3, uploadable::Uploadable}, config::config::Config, manifest::generate_manifest }; use log::info; @@ -16,7 +13,7 @@ pub async fn upload(info: &UploadInfo, config: Config) -> anyhow::Result<()> { let manifest = generate_manifest(&Path::new(path)).await?; let mut uploader: Box = match info.upload_style { crate::cli::UploadStyle::S3 => Box::new(S3::new( - config + &config .get_active_s3() .ok_or(anyhow::Error::msg("Could not get active S3 value"))?, )?), diff --git a/cli/src/commands/upload/mod.rs b/cli/src/commands/upload/mod.rs index 8c948cde..54a7fc1b 100644 --- a/cli/src/commands/upload/mod.rs +++ b/cli/src/commands/upload/mod.rs @@ -1,5 +1,4 @@ pub mod interface; pub mod s3; +pub mod speedtest; pub mod uploadable; -pub mod void; -pub mod speedtest; \ No newline at end of file diff --git a/cli/src/commands/upload/s3.rs b/cli/src/commands/upload/s3.rs index a838d29e..2de7c614 100644 --- a/cli/src/commands/upload/s3.rs +++ b/cli/src/commands/upload/s3.rs @@ -2,12 +2,11 @@ use crate::{ commands::upload::{ speedtest::{SPEEDTEST_PATH, Speedtest}, uploadable::Uploadable, - }, - config::S3Config, + }, config::s3::S3Config, }; use async_trait::async_trait; use droplet_rs::manifest::{ChunkData, Manifest}; -use s3::{Bucket, creds::Credentials}; +use s3::Bucket; use serde_json::json; use std::{ops::Deref, path::PathBuf}; diff --git a/cli/src/commands/upload/void.rs b/cli/src/commands/upload/void.rs deleted file mode 100644 index 28503c8b..00000000 --- a/cli/src/commands/upload/void.rs +++ /dev/null @@ -1,40 +0,0 @@ -use async_trait::async_trait; -use droplet_rs::manifest::{ChunkData, Manifest}; -use log::warn; - -use crate::commands::upload::uploadable::Uploadable; - -pub struct VoidUploadable; -#[async_trait] -impl Uploadable for VoidUploadable { - async fn upload_chunk( - &mut self, - _id: &String, - _version: &String, - _chunk_id: &String, - _chunk: &ChunkData, - ) -> anyhow::Result<()> { - warn!("Uploading chunk to VoidUploader"); - Ok(()) - } - - async fn upload_speedtest(&mut self) -> anyhow::Result<()> { - warn!("Uploading speedtest to VoidUploader"); - Ok(()) - } - - async fn upload_manifest( - &mut self, - _manifest: Manifest, - _game_id: &String, - _version_id: &String, - ) -> anyhow::Result<()> { - warn!("Uploading manifest to VoidUploader"); - Ok(()) - } -} -impl VoidUploadable { - pub fn new() -> Self { - Self - } -} diff --git a/cli/src/config.rs b/cli/src/config.rs deleted file mode 100644 index ef66a075..00000000 --- a/cli/src/config.rs +++ /dev/null @@ -1,67 +0,0 @@ -use std::str::FromStr; - -use s3::{Bucket, Region, creds::Credentials}; - -pub struct Config { - items: Vec, - active_s3: Option, -} -pub struct ConfigItem { - name: String, - config_option: ConfigOption, -} -enum ConfigOption { - S3(S3Config), -} -pub struct S3Config { - secret_key: String, - key_id: String, - region: String, - bucket_name: String, - endpoint: Option, -} -impl Config { - pub fn new() -> Self { - Self { - items: Vec::new(), - active_s3: None, - } - } - pub fn get_active_s3(&self) -> Option<&S3Config> { - if let Some(active_s3) = &self.active_s3 { - self.items - .iter() - .filter_map(|item| { - if item.name == *active_s3 { - match &item.config_option { - ConfigOption::S3(s3_config) => Some(s3_config), - } - } else { - None - } - }) - .next() - } else { - None - } - } -} -impl S3Config { - pub fn generate_bucket(&self) -> anyhow::Result { - let credentials = - Credentials::new(Some(&self.key_id), Some(&self.secret_key), None, None, None)?; - - let region = if let Some(endpoint) = &self.endpoint { - Region::Custom { - region: self.region.clone(), - endpoint: endpoint.clone(), - } - } else { - Region::from_str(&self.region)? - }; - - let bucket = Bucket::new(&self.bucket_name, region, credentials)?; - - Ok(*bucket) - } -} diff --git a/cli/src/config/config.rs b/cli/src/config/config.rs new file mode 100644 index 00000000..27ff92a2 --- /dev/null +++ b/cli/src/config/config.rs @@ -0,0 +1,90 @@ +use std::{fs, str::FromStr}; + +use clap::Subcommand; +use dialoguer::{Input, theme::ColorfulTheme}; +use log::warn; +use serde::{Deserialize, Serialize}; + +use crate::config::{ + s3::{S3Config, S3ConfigCli}, + server::ServerConfig, +}; + +const CONFIG_DIR: &str = "downpour/config.json"; + +#[derive(Serialize, Deserialize)] +pub struct Config { + items: Vec, + active_s3: Option, +} +impl Config { + pub fn save(&self) -> anyhow::Result<()> { + let json = serde_json::to_string(self)?; + let save_path = dirs::config_dir() + .expect("Apparently your home directory doesn't exist") // Should probably formalise that error + .join(CONFIG_DIR); + fs::write(save_path, json)?; + Ok(()) + } + pub fn read() -> Self { + let save_path = dirs::config_dir() + .expect("Apparently your home directory doesn't exist") // Should probably formalise that error + .join(CONFIG_DIR); + if fs::exists(&save_path).expect(&format!("Could not read save path {:#?}", &save_path)) { + serde_json::from_str(&fs::read_to_string(save_path).unwrap()).unwrap() + } else { + Config::new() + } + } + pub fn add_item(&mut self, item: ConfigItem) { + if matches!(item.config_option, ConfigOption::S3(..)) { + self.active_s3 = Some(item.name.clone()) + } + self.items.push(item); + } +} + +#[derive(Serialize, Deserialize)] +pub struct ConfigItem { + name: String, + config_option: ConfigOption, +} +#[derive(Subcommand, Serialize, Deserialize)] +pub enum ConfigOption { + Server(ServerConfig), + S3(S3ConfigCli), +} + +impl Config { + pub fn new() -> Self { + Self { + items: Vec::new(), + active_s3: None, + } + } + pub fn get_active_s3(&self) -> Option { + if let Some(active_s3) = &self.active_s3 { + self.items + .iter() + .filter_map(|item| { + if item.name == *active_s3 { + match &item.config_option { + ConfigOption::S3(s3_config) => Some(s3_config), + _ => { + warn!("Name {} is not of type 'S3'", item.name); + None + } + } + } else { + None + } + }) + .next() + .cloned() + .map(|c| c.into()) + } else { + None + } + } +} + diff --git a/cli/src/config/configurable.rs b/cli/src/config/configurable.rs new file mode 100644 index 00000000..8a81aca2 --- /dev/null +++ b/cli/src/config/configurable.rs @@ -0,0 +1,7 @@ +use crate::config::config::Config; + +/// Trait which represents data which may be stored in `config_dir/downpour/config.json` +pub trait Configurable { + fn configure(&self, config: &mut Config); +} + diff --git a/cli/src/config/mod.rs b/cli/src/config/mod.rs new file mode 100644 index 00000000..8fd2538b --- /dev/null +++ b/cli/src/config/mod.rs @@ -0,0 +1,4 @@ +pub mod config; +pub mod configurable; +pub mod s3; +pub mod server; diff --git a/cli/src/config/s3.rs b/cli/src/config/s3.rs new file mode 100644 index 00000000..798f8eee --- /dev/null +++ b/cli/src/config/s3.rs @@ -0,0 +1,72 @@ +use std::str::FromStr; + +use clap::Args; +use dialoguer::{Input, theme::ColorfulTheme}; +use s3::{Bucket, Region, creds::Credentials}; +use serde::{Deserialize, Serialize}; + +use crate::{config::configurable::Configurable, interactive_optional_variable, interactive_variable}; + + +#[derive(Serialize, Deserialize, Args, Clone)] +pub struct S3ConfigCli { + secret_key: Option, + key_id: Option, + region: Option, + bucket_name: Option, + endpoint: Option, +} + +impl From for S3Config { + fn from(value: S3ConfigCli) -> Self { + interactive_variable!(value, secret_key, "S3 Secret Key"); + interactive_variable!(value, key_id, "S3 Key ID"); + interactive_variable!(value, region, "S3 Region"); + interactive_variable!(value, bucket_name, "S3 Bucket Name"); + interactive_optional_variable!(value, endpoint, "S3 Endpoint (leave blank for none"); + Self { + secret_key, + key_id, + region, + bucket_name, + endpoint, + } + } +} + + + +#[derive(Serialize, Deserialize, Debug)] +pub struct S3Config { + secret_key: String, + key_id: String, + region: String, + bucket_name: String, + endpoint: Option, +} + +impl S3Config { + pub fn generate_bucket(&self) -> anyhow::Result { + let credentials = + Credentials::new(Some(&self.key_id), Some(&self.secret_key), None, None, None)?; + + let region = if let Some(endpoint) = &self.endpoint { + Region::Custom { + region: self.region.clone(), + endpoint: endpoint.clone(), + } + } else { + Region::from_str(&self.region)? + }; + + let bucket = Bucket::new(&self.bucket_name, region, credentials)?; + + Ok(*bucket) + } +} + +impl Configurable for S3Config { + fn configure(&self, config: &mut super::config::Config) { + println!("Configuring S3Config with {:?}", self); + } +} diff --git a/cli/src/config/server.rs b/cli/src/config/server.rs new file mode 100644 index 00000000..a2939826 --- /dev/null +++ b/cli/src/config/server.rs @@ -0,0 +1,18 @@ +use clap::Args; +use serde::{Deserialize, Serialize}; + +use crate::config::configurable::Configurable; + +#[derive(Serialize, Deserialize, Args, Clone)] +pub struct ServerConfig { + /// Endpoint of the Drop server + url: String, + #[arg(short, long)] + token: String, +} + +impl Configurable for ServerConfig { + fn configure(&self, config: &mut super::config::Config) { + println!("Configured ServerConfig") + } +} \ No newline at end of file diff --git a/cli/src/interactive.rs b/cli/src/interactive.rs new file mode 100644 index 00000000..bc87ee4b --- /dev/null +++ b/cli/src/interactive.rs @@ -0,0 +1,47 @@ +use std::str::FromStr; + +use dialoguer::{Input, theme::ColorfulTheme}; + +#[macro_export] +macro_rules! interactive_variable { + ($value:ident, $var:ident, $prompt:expr) => { + let $var = if let Some($var) = $value.$var { + $var + } else { + crate::interactive::query_variable($prompt).unwrap() + }; + }; +} +#[macro_export] +macro_rules! interactive_optional_variable { + ($value:ident, $var:ident, $prompt:expr) => { + let $var = if let Some($var) = $value.$var { + Some($var) + } else { + crate::interactive::query_optional_variable($prompt).unwrap() + }; + }; +} +pub fn query_variable(prompt: impl ToString) -> dialoguer::Result +where + ::Err: ToString, +{ + Input::with_theme(&ColorfulTheme::default()) + .with_prompt(prompt.to_string()) + .interact_text() +} +pub fn query_optional_variable( + prompt: impl ToString, +) -> dialoguer::Result> +where + ::Err: ToString, +{ + let input: T = Input::with_theme(&ColorfulTheme::default()) + .with_prompt(prompt.to_string()) + .allow_empty(true) + .interact_text()?; + if input.to_string().len() == 0 { + return Ok(None); + } + Ok(Some(input)) +} \ No newline at end of file diff --git a/cli/src/main.rs b/cli/src/main.rs index 0d0fc98b..4782ad8b 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,6 +1,11 @@ use crate::{ cli::{Cli, Commands}, - commands::{configure::interactive_configure, upload}, config::Config, + commands::{configure::interactive_configure, upload}, + config::{ + config::{Config, ConfigOption}, + configurable::Configurable, + s3::S3Config, + }, }; use clap::Parser; use fern::colors::{Color, ColoredLevelConfig}; @@ -13,17 +18,18 @@ mod commands; mod config; mod manifest; +#[macro_use] +pub mod interactive; + + #[tokio::main] async fn main() -> anyhow::Result<()> { configure_logging()?; let cli = Cli::parse(); - let config = Config::new(); + let mut config = Config::read(); match &cli.command { - Commands::Configure { url, token } => { - if let Some(token) = token { - } else { - interactive_configure(url.to_string()).await?; - } + Commands::Configure(options) => { + configure_command(&mut config, options).await?; } Commands::Upload(info) => { upload::interface::upload(info, config).await?; @@ -33,6 +39,15 @@ async fn main() -> anyhow::Result<()> { Ok(()) } +async fn configure_command(config: &mut Config, options: &ConfigOption) -> anyhow::Result<()> { + let configuration: Box = match options { + ConfigOption::Server(options) => Box::new(options.clone()), + ConfigOption::S3(options) => Box::new(S3Config::from(options.clone())), + }; + configuration.configure(config); + Ok(()) +} + pub fn configure_logging() -> anyhow::Result<()> { let log_level = env::var("RUST_LOG") .unwrap_or_else(|_| "info".to_string()) From bf35f66961ba0bc814c29839f58b49a08cc6c0a0 Mon Sep 17 00:00:00 2001 From: quexeky Date: Tue, 20 Jan 2026 18:44:40 +1100 Subject: [PATCH 08/22] feat: Storing configs --- cli/src/cli.rs | 19 +++--- cli/src/config/config.rs | 48 ++++++++------- cli/src/config/configurable.rs | 7 --- cli/src/config/configure.rs | 4 ++ cli/src/{ => config}/interactive.rs | 4 +- cli/src/config/mod.rs | 4 +- cli/src/config/s3.rs | 33 +++++------ cli/src/config/server.rs | 8 --- cli/src/logging.rs | 54 +++++++++++++++++ cli/src/main.rs | 90 +++++------------------------ 10 files changed, 123 insertions(+), 148 deletions(-) delete mode 100644 cli/src/config/configurable.rs create mode 100644 cli/src/config/configure.rs rename cli/src/{ => config}/interactive.rs (88%) create mode 100644 cli/src/logging.rs diff --git a/cli/src/cli.rs b/cli/src/cli.rs index 944b95ad..6608edab 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -1,9 +1,6 @@ -use std::path::PathBuf; - +use crate::config::config::ConfigOptionCli; use clap::{Args, Parser, Subcommand, ValueEnum}; -use crate::config::config::ConfigOption; - #[derive(Parser)] #[command(version, about, long_about = None)] pub struct Cli { @@ -17,9 +14,13 @@ pub struct Cli { #[derive(Subcommand)] pub enum Commands { - /// Configures a new Drop server - #[command(subcommand)] - Configure(ConfigOption), + /// Configures downpour endpoints + Configure { + #[arg(short, long)] + name: String, + #[command(subcommand)] + option: ConfigOptionCli + }, /// Uploads new game version to depot Upload(UploadInfo), } @@ -29,8 +30,8 @@ pub struct UploadInfo { /// Identifies the specific upload style that will be used for the set depot pub upload_style: UploadStyle, /// Relative path to new version files - #[arg(short, long)] - pub path: PathBuf, + #[arg(short, long, default_value_t = String::from("."))] + pub path: String, /// ID of game to attach to #[arg(short, long)] pub game_id: String, diff --git a/cli/src/config/config.rs b/cli/src/config/config.rs index 27ff92a2..440e2ed3 100644 --- a/cli/src/config/config.rs +++ b/cli/src/config/config.rs @@ -1,20 +1,17 @@ -use std::{fs, str::FromStr}; - -use clap::Subcommand; -use dialoguer::{Input, theme::ColorfulTheme}; -use log::warn; -use serde::{Deserialize, Serialize}; - use crate::config::{ s3::{S3Config, S3ConfigCli}, server::ServerConfig, }; +use clap::Subcommand; +use log::warn; +use serde::{Deserialize, Serialize}; +use std::{collections::HashMap, fs}; const CONFIG_DIR: &str = "downpour/config.json"; #[derive(Serialize, Deserialize)] pub struct Config { - items: Vec, + items: HashMap, active_s3: Option, } impl Config { @@ -23,6 +20,7 @@ impl Config { let save_path = dirs::config_dir() .expect("Apparently your home directory doesn't exist") // Should probably formalise that error .join(CONFIG_DIR); + fs::create_dir_all(save_path.parent().unwrap())?; fs::write(save_path, json)?; Ok(()) } @@ -36,29 +34,30 @@ impl Config { Config::new() } } - pub fn add_item(&mut self, item: ConfigItem) { - if matches!(item.config_option, ConfigOption::S3(..)) { - self.active_s3 = Some(item.name.clone()) + pub fn add_item(&mut self, name: String, object: ConfigOption) { + if matches!(object, ConfigOption::S3(..)) { + self.active_s3 = Some(name.clone()) } - self.items.push(item); + self.items.insert(name, object); + self.save().expect("Failed to save config"); } } -#[derive(Serialize, Deserialize)] -pub struct ConfigItem { - name: String, - config_option: ConfigOption, -} -#[derive(Subcommand, Serialize, Deserialize)] -pub enum ConfigOption { +#[derive(Subcommand, Clone)] +pub enum ConfigOptionCli { Server(ServerConfig), S3(S3ConfigCli), } +#[derive(Serialize, Deserialize, Clone)] +pub enum ConfigOption { + Server(ServerConfig), + S3(S3Config), +} impl Config { pub fn new() -> Self { Self { - items: Vec::new(), + items: HashMap::new(), active_s3: None, } } @@ -66,12 +65,12 @@ impl Config { if let Some(active_s3) = &self.active_s3 { self.items .iter() - .filter_map(|item| { - if item.name == *active_s3 { - match &item.config_option { + .filter_map(|(name, option)| { + if *name == *active_s3 { + match option { ConfigOption::S3(s3_config) => Some(s3_config), _ => { - warn!("Name {} is not of type 'S3'", item.name); + warn!("Name {} is not of type 'S3'", name); None } } @@ -87,4 +86,3 @@ impl Config { } } } - diff --git a/cli/src/config/configurable.rs b/cli/src/config/configurable.rs deleted file mode 100644 index 8a81aca2..00000000 --- a/cli/src/config/configurable.rs +++ /dev/null @@ -1,7 +0,0 @@ -use crate::config::config::Config; - -/// Trait which represents data which may be stored in `config_dir/downpour/config.json` -pub trait Configurable { - fn configure(&self, config: &mut Config); -} - diff --git a/cli/src/config/configure.rs b/cli/src/config/configure.rs new file mode 100644 index 00000000..5c684cfe --- /dev/null +++ b/cli/src/config/configure.rs @@ -0,0 +1,4 @@ +pub trait Configurable { + type Out; + fn configure(self) -> Self::Out; +} \ No newline at end of file diff --git a/cli/src/interactive.rs b/cli/src/config/interactive.rs similarity index 88% rename from cli/src/interactive.rs rename to cli/src/config/interactive.rs index bc87ee4b..0c72ca03 100644 --- a/cli/src/interactive.rs +++ b/cli/src/config/interactive.rs @@ -8,7 +8,7 @@ macro_rules! interactive_variable { let $var = if let Some($var) = $value.$var { $var } else { - crate::interactive::query_variable($prompt).unwrap() + crate::config::interactive::query_variable($prompt).unwrap() }; }; } @@ -18,7 +18,7 @@ macro_rules! interactive_optional_variable { let $var = if let Some($var) = $value.$var { Some($var) } else { - crate::interactive::query_optional_variable($prompt).unwrap() + crate::config::interactive::query_optional_variable($prompt).unwrap() }; }; } diff --git a/cli/src/config/mod.rs b/cli/src/config/mod.rs index 8fd2538b..00b59511 100644 --- a/cli/src/config/mod.rs +++ b/cli/src/config/mod.rs @@ -1,4 +1,6 @@ pub mod config; -pub mod configurable; pub mod s3; pub mod server; +pub mod configure; +#[macro_use] +pub mod interactive; diff --git a/cli/src/config/s3.rs b/cli/src/config/s3.rs index 798f8eee..d2c11f78 100644 --- a/cli/src/config/s3.rs +++ b/cli/src/config/s3.rs @@ -1,11 +1,10 @@ use std::str::FromStr; use clap::Args; -use dialoguer::{Input, theme::ColorfulTheme}; use s3::{Bucket, Region, creds::Credentials}; use serde::{Deserialize, Serialize}; -use crate::{config::configurable::Configurable, interactive_optional_variable, interactive_variable}; +use crate::{config::configure::Configurable, interactive_optional_variable, interactive_variable}; #[derive(Serialize, Deserialize, Args, Clone)] @@ -17,14 +16,16 @@ pub struct S3ConfigCli { endpoint: Option, } -impl From for S3Config { - fn from(value: S3ConfigCli) -> Self { - interactive_variable!(value, secret_key, "S3 Secret Key"); - interactive_variable!(value, key_id, "S3 Key ID"); - interactive_variable!(value, region, "S3 Region"); - interactive_variable!(value, bucket_name, "S3 Bucket Name"); - interactive_optional_variable!(value, endpoint, "S3 Endpoint (leave blank for none"); - Self { +impl Configurable for S3ConfigCli { + type Out = S3Config; + + fn configure(self) -> Self::Out { + interactive_variable!(self, secret_key, "S3 Secret Key"); + interactive_variable!(self, key_id, "S3 Key ID"); + interactive_variable!(self, region, "S3 Region"); + interactive_variable!(self, bucket_name, "S3 Bucket Name"); + interactive_optional_variable!(self, endpoint, "S3 Endpoint (leave blank for none"); + Self::Out { secret_key, key_id, region, @@ -34,9 +35,7 @@ impl From for S3Config { } } - - -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone)] pub struct S3Config { secret_key: String, key_id: String, @@ -63,10 +62,4 @@ impl S3Config { Ok(*bucket) } -} - -impl Configurable for S3Config { - fn configure(&self, config: &mut super::config::Config) { - println!("Configuring S3Config with {:?}", self); - } -} +} \ No newline at end of file diff --git a/cli/src/config/server.rs b/cli/src/config/server.rs index a2939826..5ecf6757 100644 --- a/cli/src/config/server.rs +++ b/cli/src/config/server.rs @@ -1,18 +1,10 @@ use clap::Args; use serde::{Deserialize, Serialize}; -use crate::config::configurable::Configurable; - #[derive(Serialize, Deserialize, Args, Clone)] pub struct ServerConfig { /// Endpoint of the Drop server url: String, #[arg(short, long)] token: String, -} - -impl Configurable for ServerConfig { - fn configure(&self, config: &mut super::config::Config) { - println!("Configured ServerConfig") - } } \ No newline at end of file diff --git a/cli/src/logging.rs b/cli/src/logging.rs new file mode 100644 index 00000000..8f64982f --- /dev/null +++ b/cli/src/logging.rs @@ -0,0 +1,54 @@ +use fern::colors::{Color, ColoredLevelConfig}; +use log::LevelFilter; +use std::env; +use std::fs; +use std::io; + + +pub fn configure_logging() -> anyhow::Result<()> { + let log_level = env::var("RUST_LOG") + .unwrap_or_else(|_| "info".to_string()) + .parse::()?; + + let log_dir = env::var("LOG_FILE_DIR").unwrap_or_else(|_| "logs".to_string()); + + fs::create_dir_all(&log_dir)?; + + let colors = ColoredLevelConfig::new() + .error(Color::Red) + .warn(Color::Yellow) + .info(Color::Blue) + .debug(Color::Green) + .trace(Color::Magenta); + + fern::Dispatch::new() + .chain( + fern::Dispatch::new() + .format(move |out, message, record| { + out.finish(format_args!( + "[{}] {}: {}", + chrono::Local::now().format("%H:%M:%S%.3f"), + colors.color(record.level()), + message + )) + }) + .chain(io::stdout()), + ) + .chain( + fern::Dispatch::new() + .format(|out, message, record| { + out.finish(format_args!( + "[{}] {} {} - {}", + chrono::Local::now().format("%Y-%m-%d %H:%M:%S%.3f"), + record.level(), + record.target(), + message + )) + }) + .chain(fern::log_file(format!("{}/app.log", log_dir))?), + ) + .level(log_level) + .apply()?; + + Ok(()) +} diff --git a/cli/src/main.rs b/cli/src/main.rs index 4782ad8b..5d0d9774 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,36 +1,31 @@ +use crate::config::configure::Configurable; use crate::{ cli::{Cli, Commands}, - commands::{configure::interactive_configure, upload}, - config::{ - config::{Config, ConfigOption}, - configurable::Configurable, - s3::S3Config, - }, + commands::upload, + config::config::Config, }; use clap::Parser; -use fern::colors::{Color, ColoredLevelConfig}; -use log::LevelFilter; -use std::env; -use std::fs; -use std::io; mod cli; mod commands; mod config; +mod logging; mod manifest; -#[macro_use] -pub mod interactive; - - #[tokio::main] async fn main() -> anyhow::Result<()> { - configure_logging()?; + crate::logging::configure_logging()?; + let cli = Cli::parse(); + let mut config = Config::read(); match &cli.command { - Commands::Configure(options) => { - configure_command(&mut config, options).await?; - } + Commands::Configure { name, option } => match option { + config::config::ConfigOptionCli::Server(server_config) => todo!(), + config::config::ConfigOptionCli::S3(s3_config_cli) => config.add_item( + name.clone(), + config::config::ConfigOption::S3(s3_config_cli.clone().configure()), + ), + }, Commands::Upload(info) => { upload::interface::upload(info, config).await?; } @@ -38,60 +33,3 @@ async fn main() -> anyhow::Result<()> { Ok(()) } - -async fn configure_command(config: &mut Config, options: &ConfigOption) -> anyhow::Result<()> { - let configuration: Box = match options { - ConfigOption::Server(options) => Box::new(options.clone()), - ConfigOption::S3(options) => Box::new(S3Config::from(options.clone())), - }; - configuration.configure(config); - Ok(()) -} - -pub fn configure_logging() -> anyhow::Result<()> { - let log_level = env::var("RUST_LOG") - .unwrap_or_else(|_| "info".to_string()) - .parse::()?; - - let log_dir = env::var("LOG_FILE_DIR").unwrap_or_else(|_| "logs".to_string()); - - fs::create_dir_all(&log_dir)?; - - let colors = ColoredLevelConfig::new() - .error(Color::Red) - .warn(Color::Yellow) - .info(Color::Blue) - .debug(Color::Green) - .trace(Color::Magenta); - - fern::Dispatch::new() - .chain( - fern::Dispatch::new() - .format(move |out, message, record| { - out.finish(format_args!( - "[{}] {}: {}", - chrono::Local::now().format("%H:%M:%S%.3f"), - colors.color(record.level()), - message - )) - }) - .chain(io::stdout()), - ) - .chain( - fern::Dispatch::new() - .format(|out, message, record| { - out.finish(format_args!( - "[{}] {} {} - {}", - chrono::Local::now().format("%Y-%m-%d %H:%M:%S%.3f"), - record.level(), - record.target(), - message - )) - }) - .chain(fern::log_file(format!("{}/app.log", log_dir))?), - ) - .level(log_level) - .apply()?; - - Ok(()) -} From 38e8ac4839109f99a1c364d2bb2fd6ab59b6d65a Mon Sep 17 00:00:00 2001 From: quexeky Date: Tue, 20 Jan 2026 19:02:54 +1100 Subject: [PATCH 09/22] refactor: Remove ConfigItem --- cli/src/cli.rs | 5 +- cli/src/{ => commands}/config/config.rs | 31 ++----- cli/src/commands/config/config_option.rs | 18 ++++ cli/src/commands/config/configure.rs | 5 ++ cli/src/{ => commands}/config/interactive.rs | 6 +- cli/src/{ => commands}/config/mod.rs | 3 +- cli/src/{ => commands}/config/s3.rs | 46 +++++----- cli/src/commands/config/server.rs | 92 ++++++++++++++++++++ cli/src/commands/configure.rs | 77 ---------------- cli/src/commands/mod.rs | 2 +- cli/src/commands/upload/interface.rs | 5 +- cli/src/commands/upload/s3.rs | 3 +- cli/src/commands/upload/speedtest.rs | 2 +- cli/src/commands/upload/uploadable.rs | 7 +- cli/src/config/configure.rs | 4 - cli/src/config/server.rs | 10 --- cli/src/logging.rs | 1 - cli/src/main.rs | 20 ++--- cli/src/manifest.rs | 4 +- 19 files changed, 178 insertions(+), 163 deletions(-) rename cli/src/{ => commands}/config/config.rs (87%) create mode 100644 cli/src/commands/config/config_option.rs create mode 100644 cli/src/commands/config/configure.rs rename cli/src/{ => commands}/config/interactive.rs (86%) rename cli/src/{ => commands}/config/mod.rs (80%) rename cli/src/{ => commands}/config/s3.rs (84%) create mode 100644 cli/src/commands/config/server.rs delete mode 100644 cli/src/commands/configure.rs delete mode 100644 cli/src/config/configure.rs delete mode 100644 cli/src/config/server.rs diff --git a/cli/src/cli.rs b/cli/src/cli.rs index 6608edab..07b851dd 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -1,6 +1,7 @@ -use crate::config::config::ConfigOptionCli; use clap::{Args, Parser, Subcommand, ValueEnum}; +use crate::commands::config::config_option::ConfigOptionCli; + #[derive(Parser)] #[command(version, about, long_about = None)] pub struct Cli { @@ -19,7 +20,7 @@ pub enum Commands { #[arg(short, long)] name: String, #[command(subcommand)] - option: ConfigOptionCli + option: ConfigOptionCli, }, /// Uploads new game version to depot Upload(UploadInfo), diff --git a/cli/src/config/config.rs b/cli/src/commands/config/config.rs similarity index 87% rename from cli/src/config/config.rs rename to cli/src/commands/config/config.rs index 440e2ed3..abc042cd 100644 --- a/cli/src/config/config.rs +++ b/cli/src/commands/config/config.rs @@ -1,8 +1,4 @@ -use crate::config::{ - s3::{S3Config, S3ConfigCli}, - server::ServerConfig, -}; -use clap::Subcommand; +use crate::commands::config::{config_option::ConfigOption, s3::S3Config}; use log::warn; use serde::{Deserialize, Serialize}; use std::{collections::HashMap, fs}; @@ -15,6 +11,12 @@ pub struct Config { active_s3: Option, } impl Config { + pub fn new() -> Self { + Self { + items: HashMap::new(), + active_s3: None, + } + } pub fn save(&self) -> anyhow::Result<()> { let json = serde_json::to_string(self)?; let save_path = dirs::config_dir() @@ -41,26 +43,7 @@ impl Config { self.items.insert(name, object); self.save().expect("Failed to save config"); } -} -#[derive(Subcommand, Clone)] -pub enum ConfigOptionCli { - Server(ServerConfig), - S3(S3ConfigCli), -} -#[derive(Serialize, Deserialize, Clone)] -pub enum ConfigOption { - Server(ServerConfig), - S3(S3Config), -} - -impl Config { - pub fn new() -> Self { - Self { - items: HashMap::new(), - active_s3: None, - } - } pub fn get_active_s3(&self) -> Option { if let Some(active_s3) = &self.active_s3 { self.items diff --git a/cli/src/commands/config/config_option.rs b/cli/src/commands/config/config_option.rs new file mode 100644 index 00000000..8e61f237 --- /dev/null +++ b/cli/src/commands/config/config_option.rs @@ -0,0 +1,18 @@ +use clap::Subcommand; +use serde::{Deserialize, Serialize}; + +use crate::commands::config::{ + s3::{S3Config, S3ConfigCli}, + server::{ServerConfig, ServerConfigCli}, +}; + +#[derive(Subcommand, Clone)] +pub enum ConfigOptionCli { + Server(ServerConfigCli), + S3(S3ConfigCli), +} +#[derive(Serialize, Deserialize, Clone)] +pub enum ConfigOption { + Server(ServerConfig), + S3(S3Config), +} diff --git a/cli/src/commands/config/configure.rs b/cli/src/commands/config/configure.rs new file mode 100644 index 00000000..736aa5e9 --- /dev/null +++ b/cli/src/commands/config/configure.rs @@ -0,0 +1,5 @@ +use crate::commands::config::config_option::ConfigOption; + +pub trait Configurable { + async fn configure(self) -> anyhow::Result; +} diff --git a/cli/src/config/interactive.rs b/cli/src/commands/config/interactive.rs similarity index 86% rename from cli/src/config/interactive.rs rename to cli/src/commands/config/interactive.rs index 0c72ca03..f1bd1e31 100644 --- a/cli/src/config/interactive.rs +++ b/cli/src/commands/config/interactive.rs @@ -8,7 +8,7 @@ macro_rules! interactive_variable { let $var = if let Some($var) = $value.$var { $var } else { - crate::config::interactive::query_variable($prompt).unwrap() + crate::commands::config::interactive::query_variable($prompt).unwrap() }; }; } @@ -18,7 +18,7 @@ macro_rules! interactive_optional_variable { let $var = if let Some($var) = $value.$var { Some($var) } else { - crate::config::interactive::query_optional_variable($prompt).unwrap() + crate::commands::config::interactive::query_optional_variable($prompt).unwrap() }; }; } @@ -44,4 +44,4 @@ where return Ok(None); } Ok(Some(input)) -} \ No newline at end of file +} diff --git a/cli/src/config/mod.rs b/cli/src/commands/config/mod.rs similarity index 80% rename from cli/src/config/mod.rs rename to cli/src/commands/config/mod.rs index 00b59511..a18d788f 100644 --- a/cli/src/config/mod.rs +++ b/cli/src/commands/config/mod.rs @@ -1,6 +1,7 @@ pub mod config; +pub mod configure; pub mod s3; pub mod server; -pub mod configure; #[macro_use] pub mod interactive; +pub mod config_option; diff --git a/cli/src/config/s3.rs b/cli/src/commands/config/s3.rs similarity index 84% rename from cli/src/config/s3.rs rename to cli/src/commands/config/s3.rs index d2c11f78..6ee48304 100644 --- a/cli/src/config/s3.rs +++ b/cli/src/commands/config/s3.rs @@ -4,10 +4,12 @@ use clap::Args; use s3::{Bucket, Region, creds::Credentials}; use serde::{Deserialize, Serialize}; -use crate::{config::configure::Configurable, interactive_optional_variable, interactive_variable}; +use crate::{ + commands::config::{config_option::ConfigOption, configure::Configurable}, + interactive_optional_variable, interactive_variable, +}; - -#[derive(Serialize, Deserialize, Args, Clone)] +#[derive(Args, Clone)] pub struct S3ConfigCli { secret_key: Option, key_id: Option, @@ -16,25 +18,6 @@ pub struct S3ConfigCli { endpoint: Option, } -impl Configurable for S3ConfigCli { - type Out = S3Config; - - fn configure(self) -> Self::Out { - interactive_variable!(self, secret_key, "S3 Secret Key"); - interactive_variable!(self, key_id, "S3 Key ID"); - interactive_variable!(self, region, "S3 Region"); - interactive_variable!(self, bucket_name, "S3 Bucket Name"); - interactive_optional_variable!(self, endpoint, "S3 Endpoint (leave blank for none"); - Self::Out { - secret_key, - key_id, - region, - bucket_name, - endpoint, - } - } -} - #[derive(Serialize, Deserialize, Debug, Clone)] pub struct S3Config { secret_key: String, @@ -44,6 +27,23 @@ pub struct S3Config { endpoint: Option, } +impl Configurable for S3ConfigCli { + async fn configure(self) -> anyhow::Result { + interactive_variable!(self, secret_key, "S3 Secret Key"); + interactive_variable!(self, key_id, "S3 Key ID"); + interactive_variable!(self, region, "S3 Region"); + interactive_variable!(self, bucket_name, "S3 Bucket Name"); + interactive_optional_variable!(self, endpoint, "S3 Endpoint (leave blank for none"); + Ok(ConfigOption::S3(S3Config { + secret_key, + key_id, + region, + bucket_name, + endpoint, + })) + } +} + impl S3Config { pub fn generate_bucket(&self) -> anyhow::Result { let credentials = @@ -62,4 +62,4 @@ impl S3Config { Ok(*bucket) } -} \ No newline at end of file +} diff --git a/cli/src/commands/config/server.rs b/cli/src/commands/config/server.rs new file mode 100644 index 00000000..6ba3f181 --- /dev/null +++ b/cli/src/commands/config/server.rs @@ -0,0 +1,92 @@ +use clap::Args; +use serde::{Deserialize, Serialize}; +use std::sync::LazyLock; + +use anyhow::{Result, anyhow}; +use dialoguer::{Confirm, Input, theme::ColorfulTheme}; +use reqwest::Client; +use url::Url; + +use crate::commands::config::{config_option::ConfigOption, configure::Configurable}; + +#[derive(Serialize, Deserialize, Clone)] +pub struct ServerConfig { + url: String, + token: String, +} +#[derive(Args, Clone)] +pub struct ServerConfigCli { + /// Endpoint of the Drop server + url: String, + #[arg(short, long)] + token: Option, +} + +const TOKEN_CREATE_PAYLOAD: &str = + "eyJuYW1lIjoiZG93bnBvdXIgKGNsaSkiLCJhY2xzIjpbImRlcG90Om5ldyJdfQ=="; + +impl Configurable for ServerConfigCli { + async fn configure(self) -> anyhow::Result { + let base_url = Url::parse(&self.url)?; + let mut token_create_url = base_url.join("/admin/settings/tokens")?; + { + let mut query = token_create_url.query_pairs_mut(); + query.append_pair("payload", TOKEN_CREATE_PAYLOAD); + }; + + let confirm = Confirm::with_theme(&ColorfulTheme::default()) + .with_prompt(format!( + "Open \"{}\" in your default browser?", + token_create_url.as_str() + )) + .interact()?; + + if !confirm { + return Err(anyhow!("User cancelled action")); + } + + webbrowser::open(token_create_url.as_str())?; + + let token: String = Input::with_theme(&ColorfulTheme::default()) + .with_prompt("API token") + .interact_text()?; + + validate_configuration(&self.url, &token).await?; + + Ok(ConfigOption::Server(ServerConfig { + url: self.url, + token, + })) + } +} + +static CLIENT: LazyLock = LazyLock::new(|| reqwest::Client::new()); +const REQUIRED_ACLS: [&str; 1] = ["depot:new"]; + +pub async fn validate_configuration(url: &str, token: &str) -> Result<()> { + let base_url = Url::parse(&url)?; + let token_check_url = base_url.join("/api/v1/token")?; + + let acl_check = CLIENT + .get(token_check_url) + .bearer_auth(token) + .send() + .await?; + + if !acl_check.status().is_success() { + return Err(anyhow!( + "ACL check failed with response code: {}", + acl_check.status() + )); + } + + let acls: Vec = acl_check.json().await?; + + for acl in REQUIRED_ACLS { + if !acls.contains(&acl.to_string()) { + return Err(anyhow!("Token missing {} acl", acl)); + } + } + + Ok(()) +} diff --git a/cli/src/commands/configure.rs b/cli/src/commands/configure.rs deleted file mode 100644 index c4a2ed1c..00000000 --- a/cli/src/commands/configure.rs +++ /dev/null @@ -1,77 +0,0 @@ -use std::sync::LazyLock; - -use anyhow::{Result, anyhow}; -use dialoguer::{Confirm, Input, theme::ColorfulTheme}; -use reqwest::Client; -use serde::{Deserialize, Serialize}; -use url::Url; - -const TOKEN_CREATE_PAYLOAD: &str = - "eyJuYW1lIjoiZG93bnBvdXIgKGNsaSkiLCJhY2xzIjpbImRlcG90Om5ldyJdfQ=="; - -static CLIENT: LazyLock = LazyLock::new(|| reqwest::Client::new()); -const REQUIRED_ACLS: [&str; 1] = ["depot:new"]; - -pub async fn interactive_configure(url: String) -> Result<()> { - let base_url = Url::parse(&url)?; - let mut token_create_url = base_url.join("/admin/settings/tokens")?; - { - let mut query = token_create_url.query_pairs_mut(); - query.append_pair("payload", TOKEN_CREATE_PAYLOAD); - }; - - let confirm = Confirm::with_theme(&ColorfulTheme::default()) - .with_prompt(format!( - "Open \"{}\" in your default browser?", - token_create_url.as_str() - )) - .interact()?; - - if !confirm { - return Err(anyhow!("User cancelled action")); - } - - webbrowser::open(token_create_url.as_str())?; - - let token: String = Input::with_theme(&ColorfulTheme::default()) - .with_prompt("API token") - .interact_text()?; - - validate_configuration(url, token).await?; - - Ok(()) -} - -pub async fn validate_configuration(url: String, token: String) -> Result<()> { - let base_url = Url::parse(&url)?; - let token_check_url = base_url.join("/api/v1/token")?; - - let acl_check = CLIENT - .get(token_check_url) - .bearer_auth(token) - .send() - .await?; - - if !acl_check.status().is_success() { - return Err(anyhow!( - "ACL check failed with response code: {}", - acl_check.status() - )); - } - - let acls: Vec = acl_check.json().await?; - - for acl in REQUIRED_ACLS { - if !acls.contains(&acl.to_string()) { - return Err(anyhow!("Token missing {} acl", acl)); - } - } - - Ok(()) -} - -#[derive(Serialize, Deserialize)] -pub struct ServerConfiguration { - pub endpoint: String, - pub token: String, -} diff --git a/cli/src/commands/mod.rs b/cli/src/commands/mod.rs index db8ad986..1acc25f6 100644 --- a/cli/src/commands/mod.rs +++ b/cli/src/commands/mod.rs @@ -1,2 +1,2 @@ -pub mod configure; +pub mod config; pub mod upload; diff --git a/cli/src/commands/upload/interface.rs b/cli/src/commands/upload/interface.rs index dbcbd988..c5a5ece3 100644 --- a/cli/src/commands/upload/interface.rs +++ b/cli/src/commands/upload/interface.rs @@ -1,7 +1,10 @@ use std::path::Path; use crate::{ - cli::UploadInfo, commands::upload::{s3::S3, uploadable::Uploadable}, config::config::Config, manifest::generate_manifest + cli::UploadInfo, + commands::config::config::Config, + commands::upload::{s3::S3, uploadable::Uploadable}, + manifest::generate_manifest, }; use log::info; diff --git a/cli/src/commands/upload/s3.rs b/cli/src/commands/upload/s3.rs index 2de7c614..f3ca3d79 100644 --- a/cli/src/commands/upload/s3.rs +++ b/cli/src/commands/upload/s3.rs @@ -1,8 +1,9 @@ use crate::{ + commands::config::s3::S3Config, commands::upload::{ speedtest::{SPEEDTEST_PATH, Speedtest}, uploadable::Uploadable, - }, config::s3::S3Config, + }, }; use async_trait::async_trait; use droplet_rs::manifest::{ChunkData, Manifest}; diff --git a/cli/src/commands/upload/speedtest.rs b/cli/src/commands/upload/speedtest.rs index 5cde5efa..15a16bb9 100644 --- a/cli/src/commands/upload/speedtest.rs +++ b/cli/src/commands/upload/speedtest.rs @@ -30,4 +30,4 @@ impl Speedtest { to_write: SPEEDTEST_BYTES, } } -} \ No newline at end of file +} diff --git a/cli/src/commands/upload/uploadable.rs b/cli/src/commands/upload/uploadable.rs index f8f40544..0bba1054 100644 --- a/cli/src/commands/upload/uploadable.rs +++ b/cli/src/commands/upload/uploadable.rs @@ -11,5 +11,10 @@ pub trait Uploadable { chunk: &ChunkData, ) -> anyhow::Result<()>; async fn upload_speedtest(&mut self) -> anyhow::Result<()>; - async fn upload_manifest(&mut self, manifest: Manifest, game_id: &String, version_id: &String) -> anyhow::Result<()>; + async fn upload_manifest( + &mut self, + manifest: Manifest, + game_id: &String, + version_id: &String, + ) -> anyhow::Result<()>; } diff --git a/cli/src/config/configure.rs b/cli/src/config/configure.rs deleted file mode 100644 index 5c684cfe..00000000 --- a/cli/src/config/configure.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub trait Configurable { - type Out; - fn configure(self) -> Self::Out; -} \ No newline at end of file diff --git a/cli/src/config/server.rs b/cli/src/config/server.rs deleted file mode 100644 index 5ecf6757..00000000 --- a/cli/src/config/server.rs +++ /dev/null @@ -1,10 +0,0 @@ -use clap::Args; -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize, Args, Clone)] -pub struct ServerConfig { - /// Endpoint of the Drop server - url: String, - #[arg(short, long)] - token: String, -} \ No newline at end of file diff --git a/cli/src/logging.rs b/cli/src/logging.rs index 8f64982f..6a2abef1 100644 --- a/cli/src/logging.rs +++ b/cli/src/logging.rs @@ -4,7 +4,6 @@ use std::env; use std::fs; use std::io; - pub fn configure_logging() -> anyhow::Result<()> { let log_level = env::var("RUST_LOG") .unwrap_or_else(|_| "info".to_string()) diff --git a/cli/src/main.rs b/cli/src/main.rs index 5d0d9774..21d74d78 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,13 +1,13 @@ -use crate::config::configure::Configurable; +use crate::commands::config::config_option::ConfigOptionCli; +use crate::commands::config::configure::Configurable; use crate::{ cli::{Cli, Commands}, + commands::config::config::Config, commands::upload, - config::config::Config, }; use clap::Parser; mod cli; mod commands; -mod config; mod logging; mod manifest; @@ -19,13 +19,13 @@ async fn main() -> anyhow::Result<()> { let mut config = Config::read(); match &cli.command { - Commands::Configure { name, option } => match option { - config::config::ConfigOptionCli::Server(server_config) => todo!(), - config::config::ConfigOptionCli::S3(s3_config_cli) => config.add_item( - name.clone(), - config::config::ConfigOption::S3(s3_config_cli.clone().configure()), - ), - }, + Commands::Configure { name, option } => config.add_item( + name.clone(), + match option { + ConfigOptionCli::Server(server_config) => server_config.clone().configure().await?, + ConfigOptionCli::S3(s3_config_cli) => s3_config_cli.clone().configure().await?, + }, + ), Commands::Upload(info) => { upload::interface::upload(info, config).await?; } diff --git a/cli/src/manifest.rs b/cli/src/manifest.rs index 0953fb43..ebc539e4 100644 --- a/cli/src/manifest.rs +++ b/cli/src/manifest.rs @@ -1,6 +1,4 @@ -use std::{ - path::Path, -}; +use std::path::Path; use droplet_rs::manifest::{Manifest, generate_manifest_rusty}; use indicatif::{ProgressBar, ProgressStyle}; From 29a77ff06eec75f985aac1c15309181428e828cd Mon Sep 17 00:00:00 2001 From: quexeky Date: Tue, 20 Jan 2026 19:05:31 +1100 Subject: [PATCH 10/22] refactor: Rename commands/config to commands/configure --- cli/src/cli.rs | 2 +- cli/src/commands/{config => configure}/config.rs | 2 +- cli/src/commands/{config => configure}/config_option.rs | 2 +- cli/src/commands/{config => configure}/configure.rs | 2 +- cli/src/commands/{config => configure}/interactive.rs | 4 ++-- cli/src/commands/{config => configure}/mod.rs | 0 cli/src/commands/{config => configure}/s3.rs | 2 +- cli/src/commands/{config => configure}/server.rs | 2 +- cli/src/commands/mod.rs | 2 +- cli/src/commands/upload/interface.rs | 2 +- cli/src/commands/upload/s3.rs | 2 +- cli/src/main.rs | 6 +++--- 12 files changed, 14 insertions(+), 14 deletions(-) rename cli/src/commands/{config => configure}/config.rs (96%) rename cli/src/commands/{config => configure}/config_option.rs (91%) rename cli/src/commands/{config => configure}/configure.rs (59%) rename cli/src/commands/{config => configure}/interactive.rs (86%) rename cli/src/commands/{config => configure}/mod.rs (100%) rename cli/src/commands/{config => configure}/s3.rs (95%) rename cli/src/commands/{config => configure}/server.rs (96%) diff --git a/cli/src/cli.rs b/cli/src/cli.rs index 07b851dd..af391b0d 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -1,6 +1,6 @@ use clap::{Args, Parser, Subcommand, ValueEnum}; -use crate::commands::config::config_option::ConfigOptionCli; +use crate::commands::configure::config_option::ConfigOptionCli; #[derive(Parser)] #[command(version, about, long_about = None)] diff --git a/cli/src/commands/config/config.rs b/cli/src/commands/configure/config.rs similarity index 96% rename from cli/src/commands/config/config.rs rename to cli/src/commands/configure/config.rs index abc042cd..7035332f 100644 --- a/cli/src/commands/config/config.rs +++ b/cli/src/commands/configure/config.rs @@ -1,4 +1,4 @@ -use crate::commands::config::{config_option::ConfigOption, s3::S3Config}; +use crate::commands::configure::{config_option::ConfigOption, s3::S3Config}; use log::warn; use serde::{Deserialize, Serialize}; use std::{collections::HashMap, fs}; diff --git a/cli/src/commands/config/config_option.rs b/cli/src/commands/configure/config_option.rs similarity index 91% rename from cli/src/commands/config/config_option.rs rename to cli/src/commands/configure/config_option.rs index 8e61f237..638b2a8d 100644 --- a/cli/src/commands/config/config_option.rs +++ b/cli/src/commands/configure/config_option.rs @@ -1,7 +1,7 @@ use clap::Subcommand; use serde::{Deserialize, Serialize}; -use crate::commands::config::{ +use crate::commands::configure::{ s3::{S3Config, S3ConfigCli}, server::{ServerConfig, ServerConfigCli}, }; diff --git a/cli/src/commands/config/configure.rs b/cli/src/commands/configure/configure.rs similarity index 59% rename from cli/src/commands/config/configure.rs rename to cli/src/commands/configure/configure.rs index 736aa5e9..f8240083 100644 --- a/cli/src/commands/config/configure.rs +++ b/cli/src/commands/configure/configure.rs @@ -1,4 +1,4 @@ -use crate::commands::config::config_option::ConfigOption; +use crate::commands::configure::config_option::ConfigOption; pub trait Configurable { async fn configure(self) -> anyhow::Result; diff --git a/cli/src/commands/config/interactive.rs b/cli/src/commands/configure/interactive.rs similarity index 86% rename from cli/src/commands/config/interactive.rs rename to cli/src/commands/configure/interactive.rs index f1bd1e31..d567f3f5 100644 --- a/cli/src/commands/config/interactive.rs +++ b/cli/src/commands/configure/interactive.rs @@ -8,7 +8,7 @@ macro_rules! interactive_variable { let $var = if let Some($var) = $value.$var { $var } else { - crate::commands::config::interactive::query_variable($prompt).unwrap() + crate::commands::configure::interactive::query_variable($prompt).unwrap() }; }; } @@ -18,7 +18,7 @@ macro_rules! interactive_optional_variable { let $var = if let Some($var) = $value.$var { Some($var) } else { - crate::commands::config::interactive::query_optional_variable($prompt).unwrap() + crate::commands::configure::interactive::query_optional_variable($prompt).unwrap() }; }; } diff --git a/cli/src/commands/config/mod.rs b/cli/src/commands/configure/mod.rs similarity index 100% rename from cli/src/commands/config/mod.rs rename to cli/src/commands/configure/mod.rs diff --git a/cli/src/commands/config/s3.rs b/cli/src/commands/configure/s3.rs similarity index 95% rename from cli/src/commands/config/s3.rs rename to cli/src/commands/configure/s3.rs index 6ee48304..fc037907 100644 --- a/cli/src/commands/config/s3.rs +++ b/cli/src/commands/configure/s3.rs @@ -5,7 +5,7 @@ use s3::{Bucket, Region, creds::Credentials}; use serde::{Deserialize, Serialize}; use crate::{ - commands::config::{config_option::ConfigOption, configure::Configurable}, + commands::configure::{config_option::ConfigOption, configure::Configurable}, interactive_optional_variable, interactive_variable, }; diff --git a/cli/src/commands/config/server.rs b/cli/src/commands/configure/server.rs similarity index 96% rename from cli/src/commands/config/server.rs rename to cli/src/commands/configure/server.rs index 6ba3f181..4a3eeed7 100644 --- a/cli/src/commands/config/server.rs +++ b/cli/src/commands/configure/server.rs @@ -7,7 +7,7 @@ use dialoguer::{Confirm, Input, theme::ColorfulTheme}; use reqwest::Client; use url::Url; -use crate::commands::config::{config_option::ConfigOption, configure::Configurable}; +use crate::commands::configure::{config_option::ConfigOption, configure::Configurable}; #[derive(Serialize, Deserialize, Clone)] pub struct ServerConfig { diff --git a/cli/src/commands/mod.rs b/cli/src/commands/mod.rs index 1acc25f6..db8ad986 100644 --- a/cli/src/commands/mod.rs +++ b/cli/src/commands/mod.rs @@ -1,2 +1,2 @@ -pub mod config; +pub mod configure; pub mod upload; diff --git a/cli/src/commands/upload/interface.rs b/cli/src/commands/upload/interface.rs index c5a5ece3..068961c4 100644 --- a/cli/src/commands/upload/interface.rs +++ b/cli/src/commands/upload/interface.rs @@ -2,7 +2,7 @@ use std::path::Path; use crate::{ cli::UploadInfo, - commands::config::config::Config, + commands::configure::config::Config, commands::upload::{s3::S3, uploadable::Uploadable}, manifest::generate_manifest, }; diff --git a/cli/src/commands/upload/s3.rs b/cli/src/commands/upload/s3.rs index f3ca3d79..5c348b34 100644 --- a/cli/src/commands/upload/s3.rs +++ b/cli/src/commands/upload/s3.rs @@ -1,5 +1,5 @@ use crate::{ - commands::config::s3::S3Config, + commands::configure::s3::S3Config, commands::upload::{ speedtest::{SPEEDTEST_PATH, Speedtest}, uploadable::Uploadable, diff --git a/cli/src/main.rs b/cli/src/main.rs index 21d74d78..3aaa3dc1 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,8 +1,8 @@ -use crate::commands::config::config_option::ConfigOptionCli; -use crate::commands::config::configure::Configurable; +use crate::commands::configure::config_option::ConfigOptionCli; +use crate::commands::configure::configure::Configurable; use crate::{ cli::{Cli, Commands}, - commands::config::config::Config, + commands::configure::config::Config, commands::upload, }; use clap::Parser; From d8e487a273e5fbef277bd7ac3e7b95053e384182 Mon Sep 17 00:00:00 2001 From: quexeky Date: Tue, 20 Jan 2026 19:06:25 +1100 Subject: [PATCH 11/22] refactor: Rename commands/configure/configure.rs to commands/configure/configurable.rs --- cli/src/commands/configure/{configure.rs => configurable.rs} | 0 cli/src/commands/configure/mod.rs | 2 +- cli/src/commands/configure/s3.rs | 2 +- cli/src/commands/configure/server.rs | 2 +- cli/src/main.rs | 2 +- 5 files changed, 4 insertions(+), 4 deletions(-) rename cli/src/commands/configure/{configure.rs => configurable.rs} (100%) diff --git a/cli/src/commands/configure/configure.rs b/cli/src/commands/configure/configurable.rs similarity index 100% rename from cli/src/commands/configure/configure.rs rename to cli/src/commands/configure/configurable.rs diff --git a/cli/src/commands/configure/mod.rs b/cli/src/commands/configure/mod.rs index a18d788f..843cc4c5 100644 --- a/cli/src/commands/configure/mod.rs +++ b/cli/src/commands/configure/mod.rs @@ -1,5 +1,5 @@ pub mod config; -pub mod configure; +pub mod configurable; pub mod s3; pub mod server; #[macro_use] diff --git a/cli/src/commands/configure/s3.rs b/cli/src/commands/configure/s3.rs index fc037907..92dc3502 100644 --- a/cli/src/commands/configure/s3.rs +++ b/cli/src/commands/configure/s3.rs @@ -5,7 +5,7 @@ use s3::{Bucket, Region, creds::Credentials}; use serde::{Deserialize, Serialize}; use crate::{ - commands::configure::{config_option::ConfigOption, configure::Configurable}, + commands::configure::{config_option::ConfigOption, configurable::Configurable}, interactive_optional_variable, interactive_variable, }; diff --git a/cli/src/commands/configure/server.rs b/cli/src/commands/configure/server.rs index 4a3eeed7..a9be5c21 100644 --- a/cli/src/commands/configure/server.rs +++ b/cli/src/commands/configure/server.rs @@ -7,7 +7,7 @@ use dialoguer::{Confirm, Input, theme::ColorfulTheme}; use reqwest::Client; use url::Url; -use crate::commands::configure::{config_option::ConfigOption, configure::Configurable}; +use crate::commands::configure::{config_option::ConfigOption, configurable::Configurable}; #[derive(Serialize, Deserialize, Clone)] pub struct ServerConfig { diff --git a/cli/src/main.rs b/cli/src/main.rs index 3aaa3dc1..74fe1295 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,5 +1,5 @@ use crate::commands::configure::config_option::ConfigOptionCli; -use crate::commands::configure::configure::Configurable; +use crate::commands::configure::configurable::Configurable; use crate::{ cli::{Cli, Commands}, commands::configure::config::Config, From 69bef2b7856bfcbbce6ffd65b6617a51aa098134 Mon Sep 17 00:00:00 2001 From: quexeky Date: Tue, 20 Jan 2026 19:19:48 +1100 Subject: [PATCH 12/22] feat: Add config overwrite confirmation --- cli/Cargo.lock | 187 --------------------------- cli/Cargo.toml | 1 - cli/src/commands/configure/config.rs | 36 +++++- cli/src/main.rs | 13 +- 4 files changed, 39 insertions(+), 198 deletions(-) diff --git a/cli/Cargo.lock b/cli/Cargo.lock index 524ea235..2b5d10b0 100644 --- a/cli/Cargo.lock +++ b/cli/Cargo.lock @@ -483,15 +483,6 @@ dependencies = [ "tiny-keccak", ] -[[package]] -name = "convert_case" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "core-foundation" version = "0.9.4" @@ -527,33 +518,6 @@ dependencies = [ "libc", ] -[[package]] -name = "crossterm" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" -dependencies = [ - "bitflags", - "crossterm_winapi", - "derive_more", - "document-features", - "mio", - "parking_lot", - "rustix", - "signal-hook", - "signal-hook-mio", - "winapi", -] - -[[package]] -name = "crossterm_winapi" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" -dependencies = [ - "winapi", -] - [[package]] name = "crunchy" version = "0.2.4" @@ -614,28 +578,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "derive_more" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" -dependencies = [ - "derive_more-impl", -] - -[[package]] -name = "derive_more-impl" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version", - "syn", -] - [[package]] name = "dialoguer" version = "0.12.0" @@ -700,15 +642,6 @@ dependencies = [ "const-random", ] -[[package]] -name = "document-features" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" -dependencies = [ - "litrs", -] - [[package]] name = "downpour" version = "0.1.0" @@ -724,7 +657,6 @@ dependencies = [ "droplet-rs", "fern", "indicatif", - "inquire", "log", "rand", "reqwest 0.13.1", @@ -960,15 +892,6 @@ dependencies = [ "slab", ] -[[package]] -name = "fuzzy-matcher" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94" -dependencies = [ - "thread_local", -] - [[package]] name = "generic-array" version = "0.14.7" @@ -1356,20 +1279,6 @@ dependencies = [ "web-time", ] -[[package]] -name = "inquire" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae51d5da01ce7039024fbdec477767c102c454dbdb09d4e2a432ece705b1b25d" -dependencies = [ - "bitflags", - "crossterm", - "dyn-clone", - "fuzzy-matcher", - "unicode-segmentation", - "unicode-width", -] - [[package]] name = "ipnet" version = "2.11.0" @@ -1480,21 +1389,6 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" -[[package]] -name = "litrs" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" - -[[package]] -name = "lock_api" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" -dependencies = [ - "scopeguard", -] - [[package]] name = "log" version = "0.4.29" @@ -1567,7 +1461,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", - "log", "wasi", "windows-sys 0.61.2", ] @@ -1803,29 +1696,6 @@ version = "4.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52" -[[package]] -name = "parking_lot" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-link 0.2.1", -] - [[package]] name = "pem" version = "3.0.6" @@ -2023,15 +1893,6 @@ dependencies = [ "yasna", ] -[[package]] -name = "redox_syscall" -version = "0.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" -dependencies = [ - "bitflags", -] - [[package]] name = "redox_users" version = "0.5.2" @@ -2193,15 +2054,6 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - [[package]] name = "rusticata-macros" version = "4.1.0" @@ -2348,12 +2200,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - [[package]] name = "security-framework" version = "2.11.1" @@ -2390,12 +2236,6 @@ dependencies = [ "libc", ] -[[package]] -name = "semver" -version = "1.0.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" - [[package]] name = "serde" version = "1.0.228" @@ -2483,27 +2323,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" -[[package]] -name = "signal-hook" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" -dependencies = [ - "libc", - "signal-hook-registry", -] - -[[package]] -name = "signal-hook-mio" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc" -dependencies = [ - "libc", - "mio", - "signal-hook", -] - [[package]] name = "signal-hook-registry" version = "1.4.7" @@ -2927,12 +2746,6 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" -[[package]] -name = "unicode-segmentation" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" - [[package]] name = "unicode-width" version = "0.2.2" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 0d407dd5..80b1d19f 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -25,4 +25,3 @@ tokio-util = "0.7.18" url = "2.5.8" webbrowser = "1.0.6" color-eyre = "0.6.5" -inquire = "0.9.2" diff --git a/cli/src/commands/configure/config.rs b/cli/src/commands/configure/config.rs index 7035332f..a5697496 100644 --- a/cli/src/commands/configure/config.rs +++ b/cli/src/commands/configure/config.rs @@ -1,4 +1,9 @@ -use crate::commands::configure::{config_option::ConfigOption, s3::S3Config}; +use crate::commands::configure::{ + config_option::{ConfigOption, ConfigOptionCli}, + configurable::Configurable, + s3::S3Config, +}; +use dialoguer::{Confirm, theme::ColorfulTheme}; use log::warn; use serde::{Deserialize, Serialize}; use std::{collections::HashMap, fs}; @@ -17,6 +22,9 @@ impl Config { active_s3: None, } } + pub fn exists(&self, name: &String) -> bool { + self.items.contains_key(name) + } pub fn save(&self) -> anyhow::Result<()> { let json = serde_json::to_string(self)?; let save_path = dirs::config_dir() @@ -69,3 +77,29 @@ impl Config { } } } + +pub async fn manage_configuration( + config: &mut Config, + name: &String, + option: &ConfigOptionCli, +) -> anyhow::Result<()> { + if config.exists(&name) { + let confirm = Confirm::with_theme(&ColorfulTheme::default()) + .with_prompt(format!( + "An entry already exists with the name \"{}\". Would you like to overwrite it?", + &name + )) + .interact()?; + if !confirm { + return Err(anyhow::anyhow!("User cancelled action")); + } + } + config.add_item( + name.clone(), + match option { + ConfigOptionCli::Server(server_config) => server_config.clone().configure().await?, + ConfigOptionCli::S3(s3_config_cli) => s3_config_cli.clone().configure().await?, + }, + ); + Ok(()) +} diff --git a/cli/src/main.rs b/cli/src/main.rs index 74fe1295..6c9527a3 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,5 +1,4 @@ -use crate::commands::configure::config_option::ConfigOptionCli; -use crate::commands::configure::configurable::Configurable; +use crate::commands::configure::config::manage_configuration; use crate::{ cli::{Cli, Commands}, commands::configure::config::Config, @@ -19,13 +18,9 @@ async fn main() -> anyhow::Result<()> { let mut config = Config::read(); match &cli.command { - Commands::Configure { name, option } => config.add_item( - name.clone(), - match option { - ConfigOptionCli::Server(server_config) => server_config.clone().configure().await?, - ConfigOptionCli::S3(s3_config_cli) => s3_config_cli.clone().configure().await?, - }, - ), + Commands::Configure { name, option } => { + manage_configuration(&mut config, name, option).await? + } Commands::Upload(info) => { upload::interface::upload(info, config).await?; } From 1db9e6264b12c7e3175115bf29978704e846decb Mon Sep 17 00:00:00 2001 From: quexeky Date: Wed, 21 Jan 2026 20:35:39 +1100 Subject: [PATCH 13/22] feat: S3 chunk uploading --- cli/.envrc | 1 + cli/.gitignore | 3 +- cli/Cargo.lock | 157 +----------------------- cli/Cargo.toml | 4 +- cli/flake.nix | 2 +- cli/src/commands/upload/chunk_reader.rs | 95 ++++++++++++++ cli/src/commands/upload/mod.rs | 1 + cli/src/commands/upload/s3.rs | 15 ++- 8 files changed, 110 insertions(+), 168 deletions(-) create mode 100644 cli/.envrc create mode 100644 cli/src/commands/upload/chunk_reader.rs diff --git a/cli/.envrc b/cli/.envrc new file mode 100644 index 00000000..3550a30f --- /dev/null +++ b/cli/.envrc @@ -0,0 +1 @@ +use flake diff --git a/cli/.gitignore b/cli/.gitignore index 9c242044..83807067 100644 --- a/cli/.gitignore +++ b/cli/.gitignore @@ -1,3 +1,4 @@ /target logs/ -.vscode \ No newline at end of file +.vscode +.direnv \ No newline at end of file diff --git a/cli/Cargo.lock b/cli/Cargo.lock index 2b5d10b0..a1ca3993 100644 --- a/cli/Cargo.lock +++ b/cli/Cargo.lock @@ -2,21 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "addr2line" -version = "0.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - [[package]] name = "android_system_properties" version = "0.1.5" @@ -235,21 +220,6 @@ dependencies = [ "thiserror 2.0.17", ] -[[package]] -name = "backtrace" -version = "0.3.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-link 0.2.1", -] - [[package]] name = "base64" version = "0.22.1" @@ -384,33 +354,6 @@ dependencies = [ "cc", ] -[[package]] -name = "color-eyre" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5920befb47832a6d61ee3a3a846565cfa39b331331e68a3b1d1116630f2f26d" -dependencies = [ - "backtrace", - "color-spantrace", - "eyre", - "indenter", - "once_cell", - "owo-colors", - "tracing-error", -] - -[[package]] -name = "color-spantrace" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8b88ea9df13354b55bc7234ebcce36e6ef896aca2e42a15de9e10edce01b427" -dependencies = [ - "once_cell", - "owo-colors", - "tracing-core", - "tracing-error", -] - [[package]] name = "colorchoice" version = "1.0.4" @@ -650,12 +593,12 @@ dependencies = [ "async-trait", "chrono", "clap", - "color-eyre", "console", "dialoguer", "dirs", "droplet-rs", "fern", + "futures", "indicatif", "log", "rand", @@ -735,16 +678,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "eyre" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" -dependencies = [ - "indenter", - "once_cell", -] - [[package]] name = "fastrand" version = "2.3.0" @@ -929,12 +862,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "gimli" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" - [[package]] name = "h2" version = "0.4.13" @@ -1250,12 +1177,6 @@ dependencies = [ "icu_properties", ] -[[package]] -name = "indenter" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5" - [[package]] name = "indexmap" version = "2.12.1" @@ -1445,15 +1366,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", -] - [[package]] name = "mio" version = "1.1.1" @@ -1585,15 +1497,6 @@ dependencies = [ "objc2-core-foundation", ] -[[package]] -name = "object" -version = "0.37.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" -dependencies = [ - "memchr", -] - [[package]] name = "oid-registry" version = "0.7.1" @@ -1690,12 +1593,6 @@ dependencies = [ "hashbrown 0.14.5", ] -[[package]] -name = "owo-colors" -version = "4.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52" - [[package]] name = "pem" version = "3.0.6" @@ -2042,12 +1939,6 @@ dependencies = [ "url", ] -[[package]] -name = "rustc-demangle" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" - [[package]] name = "rustc-hash" version = "2.1.1" @@ -2302,15 +2193,6 @@ dependencies = [ "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 = "shell-words" version = "1.1.1" @@ -2497,15 +2379,6 @@ dependencies = [ "syn", ] -[[package]] -name = "thread_local" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" -dependencies = [ - "cfg-if", -] - [[package]] name = "time" version = "0.3.44" @@ -2704,28 +2577,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", - "valuable", -] - -[[package]] -name = "tracing-error" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" -dependencies = [ - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" -dependencies = [ - "sharded-slab", - "thread_local", - "tracing-core", ] [[package]] @@ -2799,12 +2650,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "valuable" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" - [[package]] name = "vcpkg" version = "0.2.15" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 80b1d19f..f3202a91 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -13,6 +13,7 @@ dialoguer = "0.12.0" dirs = "6.0.0" droplet-rs = { git = "https://github.com/Drop-OSS/droplet-rs.git", version = "0.14" } fern = { version = "0.7.1", features = ["colored"] } +futures = "0.3.31" indicatif = "0.18.3" log = "0.4.29" rand = "0.9.2" @@ -20,8 +21,7 @@ reqwest = { version = "0.13.1", features = ["json"] } rust-s3 = "0.37.1" serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0.148" -tokio = { version = "1.48.0", features = ["macros"] } +tokio = { version = "1.48.0", features = ["fs", "macros"] } tokio-util = "0.7.18" url = "2.5.8" webbrowser = "1.0.6" -color-eyre = "0.6.5" diff --git a/cli/flake.nix b/cli/flake.nix index e98989c5..7c806fd3 100644 --- a/cli/flake.nix +++ b/cli/flake.nix @@ -41,10 +41,10 @@ buildInputs = libraries; shellHook = '' - echo "Drop-OSS app development environment loaded." export LD_LIBRARY_PATH="${ pkgs.lib.makeLibraryPath libraries }:$LD_LIBRARY_PATH" + echo "Downpour development environment loaded" ''; }; } diff --git a/cli/src/commands/upload/chunk_reader.rs b/cli/src/commands/upload/chunk_reader.rs new file mode 100644 index 00000000..52035f19 --- /dev/null +++ b/cli/src/commands/upload/chunk_reader.rs @@ -0,0 +1,95 @@ +use droplet_rs::manifest::ChunkData; +use std::{ + cmp::min, + fs::File, + io::{Read, Seek, SeekFrom}, + task::Poll, vec::IntoIter, +}; +use tokio::io::AsyncRead; + +pub struct ChunkReader { + files: IntoIter, + active: Option, +} + +pub struct LimitedFileReader { + file: File, + to_read_remaining: usize, +} + +impl Read for LimitedFileReader { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + let to_read = min(self.to_read_remaining, buf.len()); + let (to_read, _remaining) = buf.split_at_mut(to_read); + let read = self.file.read(to_read)?; + self.to_read_remaining -= read; + Ok(read) + } +} + +impl ChunkReader { + pub fn new(chunk: &ChunkData) -> Self { + let files = chunk.files.iter().map(|f| { + let mut file = File::open(&f.filename).unwrap(); + file.seek(SeekFrom::Start(f.start as u64)).unwrap(); // TODO: Fix unwraps + LimitedFileReader { + file, + to_read_remaining: f.length, + } + }).collect::>().into_iter(); + Self { + files: files, + active: None, + } + } +} +impl AsyncRead for ChunkReader { + fn poll_read( + self: std::pin::Pin<&mut Self>, + _cx: &mut std::task::Context<'_>, + buf: &mut tokio::io::ReadBuf<'_>, + ) -> std::task::Poll> { + let mut s = self; + loop { + if let Some(active) = &mut s.active { + match active.read(buf.initialize_unfilled()) { + Ok(0) => { + s.active = None; + continue; + } + Ok(_) => return Poll::Ready(Ok(())), + Err(e) => return Poll::Ready(Err(e)), + } + } else { + if let Some(next) = s.files.next() { + s.active = Some(next); + } else { + return Poll::Ready(Ok(())); + } + } + } + } +} + +impl Read for ChunkReader { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + loop { + if let Some(active) = &mut self.active { + match active.read(buf) { + Ok(0) => { + self.active = None; + continue; + } + Ok(n) => return Ok(n), + Err(e) => return Err(e), + } + } else { + if let Some(next) = self.files.next() { + self.active = Some(next); + } else { + return Ok(0); + } + } + } + } +} diff --git a/cli/src/commands/upload/mod.rs b/cli/src/commands/upload/mod.rs index 54a7fc1b..3628fe41 100644 --- a/cli/src/commands/upload/mod.rs +++ b/cli/src/commands/upload/mod.rs @@ -2,3 +2,4 @@ pub mod interface; pub mod s3; pub mod speedtest; pub mod uploadable; +pub mod chunk_reader; diff --git a/cli/src/commands/upload/s3.rs b/cli/src/commands/upload/s3.rs index 5c348b34..ba852600 100644 --- a/cli/src/commands/upload/s3.rs +++ b/cli/src/commands/upload/s3.rs @@ -1,10 +1,6 @@ -use crate::{ - commands::configure::s3::S3Config, - commands::upload::{ - speedtest::{SPEEDTEST_PATH, Speedtest}, - uploadable::Uploadable, - }, -}; +use crate::commands::{configure::s3::S3Config, upload::{ + chunk_reader::ChunkReader, speedtest::{SPEEDTEST_PATH, Speedtest}, uploadable::Uploadable + }}; use async_trait::async_trait; use droplet_rs::manifest::{ChunkData, Manifest}; use s3::Bucket; @@ -30,7 +26,10 @@ impl Uploadable for S3 { chunk_id: &String, chunk: &ChunkData, ) -> anyhow::Result<()> { - todo!() + let path = &PathBuf::from(id).join(version).join(chunk_id).to_string_lossy().to_string(); + let mut reader = ChunkReader::new(chunk); + self.put_object_stream(&mut reader, path).await?; + Ok(()) } async fn upload_speedtest(&mut self) -> anyhow::Result<()> { if self.object_exists(SPEEDTEST_PATH).await? { From e462fe3efd30cea2a9fa77d900e388bf93fe200b Mon Sep 17 00:00:00 2001 From: quexeky Date: Wed, 21 Jan 2026 22:20:05 +1100 Subject: [PATCH 14/22] fix: AsyncRead not advancing initialised buffer --- cli/src/commands/upload/chunk_reader.rs | 78 ++++++++++++++----------- cli/src/commands/upload/interface.rs | 4 +- cli/src/commands/upload/s3.rs | 31 +++++++--- cli/src/commands/upload/uploadable.rs | 3 + 4 files changed, 73 insertions(+), 43 deletions(-) diff --git a/cli/src/commands/upload/chunk_reader.rs b/cli/src/commands/upload/chunk_reader.rs index 52035f19..507b3d07 100644 --- a/cli/src/commands/upload/chunk_reader.rs +++ b/cli/src/commands/upload/chunk_reader.rs @@ -3,7 +3,9 @@ use std::{ cmp::min, fs::File, io::{Read, Seek, SeekFrom}, - task::Poll, vec::IntoIter, + path::Path, + task::Poll, + vec::IntoIter, }; use tokio::io::AsyncRead; @@ -28,15 +30,20 @@ impl Read for LimitedFileReader { } impl ChunkReader { - pub fn new(chunk: &ChunkData) -> Self { - let files = chunk.files.iter().map(|f| { - let mut file = File::open(&f.filename).unwrap(); - file.seek(SeekFrom::Start(f.start as u64)).unwrap(); // TODO: Fix unwraps - LimitedFileReader { - file, - to_read_remaining: f.length, - } - }).collect::>().into_iter(); + pub fn new(path: impl AsRef, chunk: &ChunkData) -> Self { + let files = chunk + .files + .iter() + .map(|f| { + let mut file = File::open(path.as_ref().join(&f.filename)).unwrap(); + file.seek(SeekFrom::Start(f.start as u64)).unwrap(); // TODO: Fix unwraps + LimitedFileReader { + file, + to_read_remaining: f.length, + } + }) + .collect::>() + .into_iter(); Self { files: files, active: None, @@ -57,7 +64,12 @@ impl AsyncRead for ChunkReader { s.active = None; continue; } - Ok(_) => return Poll::Ready(Ok(())), + Ok(n) => { + + buf.advance(n); + + return Poll::Ready(Ok(())); + } Err(e) => return Poll::Ready(Err(e)), } } else { @@ -71,25 +83,25 @@ impl AsyncRead for ChunkReader { } } -impl Read for ChunkReader { - fn read(&mut self, buf: &mut [u8]) -> std::io::Result { - loop { - if let Some(active) = &mut self.active { - match active.read(buf) { - Ok(0) => { - self.active = None; - continue; - } - Ok(n) => return Ok(n), - Err(e) => return Err(e), - } - } else { - if let Some(next) = self.files.next() { - self.active = Some(next); - } else { - return Ok(0); - } - } - } - } -} +// impl Read for ChunkReader { +// fn read(&mut self, buf: &mut [u8]) -> std::io::Result { +// loop { +// if let Some(active) = &mut self.active { +// match active.read(buf) { +// Ok(0) => { +// self.active = None; +// continue; +// } +// Ok(n) => return Ok(n), +// Err(e) => return Err(e), +// } +// } else { +// if let Some(next) = self.files.next() { +// self.active = Some(next); +// } else { +// return Ok(0); +// } +// } +// } +// } +// } diff --git a/cli/src/commands/upload/interface.rs b/cli/src/commands/upload/interface.rs index 068961c4..d87c0817 100644 --- a/cli/src/commands/upload/interface.rs +++ b/cli/src/commands/upload/interface.rs @@ -1,4 +1,4 @@ -use std::path::Path; +use std::path::{Path, PathBuf}; use crate::{ cli::UploadInfo, @@ -24,7 +24,7 @@ pub async fn upload(info: &UploadInfo, config: Config) -> anyhow::Result<()> { info!("Uploading chunks"); for (id, data) in &manifest.chunks { info!("Uploading chunk id {id}"); - uploader.upload_chunk(game_id, version_id, id, data).await?; + uploader.upload_chunk(PathBuf::from(path), game_id, version_id, id, data).await?; } info!("Finished uploading chunks"); diff --git a/cli/src/commands/upload/s3.rs b/cli/src/commands/upload/s3.rs index ba852600..387b6bcc 100644 --- a/cli/src/commands/upload/s3.rs +++ b/cli/src/commands/upload/s3.rs @@ -1,8 +1,15 @@ -use crate::commands::{configure::s3::S3Config, upload::{ - chunk_reader::ChunkReader, speedtest::{SPEEDTEST_PATH, Speedtest}, uploadable::Uploadable - }}; +use crate::commands::{ + configure::s3::S3Config, + upload::{ + chunk_reader::ChunkReader, + speedtest::{SPEEDTEST_PATH, Speedtest}, + uploadable::Uploadable, + }, +}; use async_trait::async_trait; -use droplet_rs::manifest::{ChunkData, Manifest}; +use droplet_rs::{ + manifest::{ChunkData, Manifest}, +}; use s3::Bucket; use serde_json::json; use std::{ops::Deref, path::PathBuf}; @@ -21,20 +28,26 @@ impl S3 { impl Uploadable for S3 { async fn upload_chunk( &mut self, + base_path: PathBuf, id: &String, version: &String, chunk_id: &String, chunk: &ChunkData, ) -> anyhow::Result<()> { - let path = &PathBuf::from(id).join(version).join(chunk_id).to_string_lossy().to_string(); - let mut reader = ChunkReader::new(chunk); - self.put_object_stream(&mut reader, path).await?; + let path = &PathBuf::from(id) + .join(version) + .join(chunk_id) + .to_string_lossy() + .to_string(); + let mut reader = ChunkReader::new(&base_path, chunk); + self.put_object_stream(&mut reader, &path).await?; Ok(()) } async fn upload_speedtest(&mut self) -> anyhow::Result<()> { if self.object_exists(SPEEDTEST_PATH).await? { return Ok(()); } + println!("Uploading speedtest"); let mut speedtest = Speedtest::new(); self.put_object_stream(&mut speedtest, SPEEDTEST_PATH) .await?; @@ -47,7 +60,7 @@ impl Uploadable for S3 { game_id: &String, version_id: &String, ) -> anyhow::Result<()> { - self.put_object( + self.put_object_builder( PathBuf::from(game_id) .join(version_id) .join("manifest.json") @@ -55,6 +68,8 @@ impl Uploadable for S3 { .to_string(), json!(manifest).to_string().as_bytes(), ) + .with_content_type("application/json") + .execute() .await?; Ok(()) } diff --git a/cli/src/commands/upload/uploadable.rs b/cli/src/commands/upload/uploadable.rs index 0bba1054..e6dbec3d 100644 --- a/cli/src/commands/upload/uploadable.rs +++ b/cli/src/commands/upload/uploadable.rs @@ -1,3 +1,5 @@ +use std::path::PathBuf; + use async_trait::async_trait; use droplet_rs::manifest::{ChunkData, Manifest}; @@ -5,6 +7,7 @@ use droplet_rs::manifest::{ChunkData, Manifest}; pub trait Uploadable { async fn upload_chunk( &mut self, + base_path: PathBuf, id: &String, version: &String, chunk_id: &String, From a9d1c6eea4ab947bf1c428107f78afd936d8f4e8 Mon Sep 17 00:00:00 2001 From: quexeky Date: Sun, 25 Jan 2026 08:02:23 +1100 Subject: [PATCH 15/22] chore: Add spec.md --- cli/spec.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 cli/spec.md diff --git a/cli/spec.md b/cli/spec.md new file mode 100644 index 00000000..83285320 --- /dev/null +++ b/cli/spec.md @@ -0,0 +1,11 @@ +# Downpour CLI spec +`downpour [command] --opts` +## Commands: +- new - creates/initalizes a depot at the endpoint. Creates manifest.json and speedtest +- connect [name] - connects to an s3 endpoint and saves the endpoint to some sort of credentials file. Name is either as provided or the hostname of the endpoint +- upload - uploads game as described before. Should fail if depot isn't initialized with new from above +- copy - copies between two depots +- mark-exists - modifies depot's manifest.json to show content exists without copying (for third party copies) - maybe throw in checking one or two checks to see if they exist? +- mark-absent - the same as above, but the reverse +- rename - renames an endpoint [NEEDS API ROUTES - can't do yet] +- delete - delete an endpoint [NEEDS API ROUTES - can't do yet] From 2518d9e023c1014172c5b4295d0420c4eac0362c Mon Sep 17 00:00:00 2001 From: quexeky Date: Sun, 25 Jan 2026 12:14:39 +1100 Subject: [PATCH 16/22] chore: Update spec.md --- cli/spec.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cli/spec.md b/cli/spec.md index 83285320..e5401750 100644 --- a/cli/spec.md +++ b/cli/spec.md @@ -5,7 +5,6 @@ - connect [name] - connects to an s3 endpoint and saves the endpoint to some sort of credentials file. Name is either as provided or the hostname of the endpoint - upload - uploads game as described before. Should fail if depot isn't initialized with new from above - copy - copies between two depots -- mark-exists - modifies depot's manifest.json to show content exists without copying (for third party copies) - maybe throw in checking one or two checks to see if they exist? -- mark-absent - the same as above, but the reverse +- mark [exists/absent] - modifies depot's manifest.json to show content exists or is absent without copying (for third party copies) - rename - renames an endpoint [NEEDS API ROUTES - can't do yet] - delete - delete an endpoint [NEEDS API ROUTES - can't do yet] From 8c8e9ad4c9ccce16091d4bedc42f23f5369c9ce0 Mon Sep 17 00:00:00 2001 From: quexeky Date: Sun, 25 Jan 2026 21:04:03 +1100 Subject: [PATCH 17/22] feat: Migrate to Apache opendal --- cli/Cargo.lock | 687 ++++++------------ cli/Cargo.toml | 4 +- cli/src/cli.rs | 4 +- cli/src/commands/configure/config_option.rs | 18 - cli/src/commands/configure/configurable.rs | 5 - cli/src/commands/configure/s3.rs | 65 -- cli/src/commands/configure/server.rs | 92 --- .../commands/{configure => connect}/config.rs | 65 +- cli/src/commands/connect/config_option.rs | 26 + cli/src/commands/connect/configurable.rs | 5 + .../{configure => connect}/interactive.rs | 4 +- .../commands/{configure => connect}/mod.rs | 1 - cli/src/commands/connect/s3.rs | 66 ++ cli/src/commands/mod.rs | 2 +- cli/src/commands/upload/interface.rs | 26 +- cli/src/commands/upload/mod.rs | 1 - cli/src/commands/upload/s3.rs | 84 --- cli/src/commands/upload/uploadable.rs | 19 +- cli/src/main.rs | 6 +- cli/src/manifest.rs | 35 +- 20 files changed, 443 insertions(+), 772 deletions(-) delete mode 100644 cli/src/commands/configure/config_option.rs delete mode 100644 cli/src/commands/configure/configurable.rs delete mode 100644 cli/src/commands/configure/s3.rs delete mode 100644 cli/src/commands/configure/server.rs rename cli/src/commands/{configure => connect}/config.rs (60%) create mode 100644 cli/src/commands/connect/config_option.rs create mode 100644 cli/src/commands/connect/configurable.rs rename cli/src/commands/{configure => connect}/interactive.rs (86%) rename cli/src/commands/{configure => connect}/mod.rs (86%) create mode 100644 cli/src/commands/connect/s3.rs delete mode 100644 cli/src/commands/upload/s3.rs diff --git a/cli/Cargo.lock b/cli/Cargo.lock index a1ca3993..50755aba 100644 --- a/cli/Cargo.lock +++ b/cli/Cargo.lock @@ -151,44 +151,12 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" -[[package]] -name = "attohttpc" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e2cdb6d5ed835199484bb92bb8b3edd526effe995c61732580439c1a67e2e9" -dependencies = [ - "base64", - "http", - "log", - "native-tls", - "serde", - "serde_json", - "url", -] - [[package]] name = "autocfg" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" -[[package]] -name = "aws-creds" -version = "0.39.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3b85155d265df828f84e53886ed9e427aed979dd8a39f5b8b2162c77e142d7" -dependencies = [ - "attohttpc", - "home", - "log", - "quick-xml", - "rust-ini", - "serde", - "thiserror 2.0.17", - "time", - "url", -] - [[package]] name = "aws-lc-rs" version = "1.15.2" @@ -212,12 +180,14 @@ dependencies = [ ] [[package]] -name = "aws-region" -version = "0.28.1" +name = "backon" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "838b36c8dc927b6db1b6c6b8f5d05865f2213550b9e83bf92fa99ed6525472c0" +checksum = "cffb0e931875b666fc4fcb20fee52e9bbd1ef836fd9e9e04ec21555f9f85f7ef" dependencies = [ - "thiserror 2.0.17", + "fastrand", + "gloo-timers", + "tokio", ] [[package]] @@ -253,15 +223,6 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" -[[package]] -name = "castaway" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" -dependencies = [ - "rustversion", -] - [[package]] name = "cc" version = "1.2.49" @@ -302,7 +263,7 @@ dependencies = [ "js-sys", "num-traits", "wasm-bindgen", - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -380,19 +341,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "compact_str" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f" -dependencies = [ - "castaway", - "cfg-if", - "itoa", - "ryu", - "static_assertions", -] - [[package]] name = "console" version = "0.16.2" @@ -406,6 +354,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "const-random" version = "0.1.18" @@ -461,6 +415,15 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32c" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a47af21622d091a8f0fb295b88bc886ac74efcc613efc19f5d0b21de5c89e47" +dependencies = [ + "rustc_version", +] + [[package]] name = "crunchy" version = "0.2.4" @@ -518,7 +481,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", - "serde_core", ] [[package]] @@ -540,6 +502,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", "subtle", ] @@ -601,9 +564,9 @@ dependencies = [ "futures", "indicatif", "log", - "rand", + "opendal", + "rand 0.9.2", "reqwest 0.13.1", - "rust-s3", "serde", "serde_json", "tokio", @@ -706,21 +669,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "form_urlencoded" version = "1.2.2" @@ -862,6 +810,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "h2" version = "0.4.13" @@ -1007,22 +967,7 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", -] - -[[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", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", + "webpki-roots", ] [[package]] @@ -1063,7 +1008,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.62.2", + "windows-core", ] [[package]] @@ -1228,6 +1173,47 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +[[package]] +name = "jiff" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67e8da4c49d6d9909fe03361f9b620f58898859f5c7aded68351e85e71ecf50" +dependencies = [ + "jiff-static", + "jiff-tzdb-platform", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", + "windows-sys 0.61.2", +] + +[[package]] +name = "jiff-static" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0c84ee7f197eca9a86c6fd6cb771e55eb991632f15f2bc3ca6ec838929e6e78" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "jiff-tzdb" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68971ebff725b9e2ca27a601c5eb38a4c5d64422c4cbab0c535f248087eda5c2" + +[[package]] +name = "jiff-tzdb-platform" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8" +dependencies = [ + "jiff-tzdb", +] + [[package]] name = "jni" version = "0.21.1" @@ -1323,22 +1309,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" [[package]] -name = "maybe-async" -version = "0.2.10" +name = "md-5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ - "proc-macro2", - "quote", - "syn", + "cfg-if", + "digest", ] -[[package]] -name = "md5" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae960838283323069879657ca3de837e9f7bbb4c7bf6ea7f1b290d5e9476d2e0" - [[package]] name = "memchr" version = "2.7.6" @@ -1351,15 +1330,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "minidom" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e394a0e3c7ccc2daea3dffabe82f09857b6b510cb25af87d54bf3e910ac1642d" -dependencies = [ - "rxml", -] - [[package]] name = "minimal-lexical" version = "0.2.1" @@ -1377,23 +1347,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "native-tls" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe 0.1.6", - "openssl-sys", - "schannel", - "security-framework 2.11.1", - "security-framework-sys", - "tempfile", -] - [[package]] name = "ndk-context" version = "0.1.1" @@ -1410,15 +1363,6 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "ntapi" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c70f219e21142367c70c0b30c6a9e3a14d55b4d12a204d897fbec83a0363f081" -dependencies = [ - "winapi", -] - [[package]] name = "num-bigint" version = "0.4.6" @@ -1462,15 +1406,6 @@ dependencies = [ "objc2-encode", ] -[[package]] -name = "objc2-core-foundation" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" -dependencies = [ - "bitflags", -] - [[package]] name = "objc2-encode" version = "4.1.0" @@ -1487,16 +1422,6 @@ dependencies = [ "objc2", ] -[[package]] -name = "objc2-io-kit" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15" -dependencies = [ - "libc", - "objc2-core-foundation", -] - [[package]] name = "oid-registry" version = "0.7.1" @@ -1528,55 +1453,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] -name = "openssl" -version = "0.10.75" +name = "opendal" +version = "0.55.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" +checksum = "d075ab8a203a6ab4bc1bce0a4b9fe486a72bf8b939037f4b78d95386384bc80a" dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", + "anyhow", + "backon", + "base64", + "bytes", + "crc32c", + "futures", + "getrandom 0.2.16", + "http", + "http-body", + "jiff", + "log", + "md-5", + "percent-encoding", + "quick-xml 0.38.4", + "reqsign", + "reqwest 0.12.28", + "serde", + "serde_json", + "tokio", + "url", + "uuid", ] -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "openssl-probe" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" - [[package]] name = "openssl-probe" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f50d9b3dabb09ecd771ad0aa242ca6894994c130308ca3d7684634df8037391" -[[package]] -name = "openssl-sys" -version = "0.9.111" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "option-ext" version = "0.2.0" @@ -1621,18 +1531,21 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "pkg-config" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" - [[package]] name = "portable-atomic" version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + [[package]] name = "potential_utf" version = "0.1.4" @@ -1666,6 +1579,16 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "quick-xml" +version = "0.37.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "quick-xml" version = "0.38.4" @@ -1706,7 +1629,7 @@ dependencies = [ "bytes", "getrandom 0.3.4", "lru-slab", - "rand", + "rand 0.9.2", "ring", "rustc-hash", "rustls", @@ -1747,14 +1670,35 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + [[package]] name = "rand" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ - "rand_chacha", - "rand_core", + "rand_chacha 0.9.0", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", ] [[package]] @@ -1764,7 +1708,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", ] [[package]] @@ -1801,6 +1754,35 @@ dependencies = [ "thiserror 2.0.17", ] +[[package]] +name = "reqsign" +version = "0.16.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43451dbf3590a7590684c25fb8d12ecdcc90ed3ac123433e500447c7d77ed701" +dependencies = [ + "anyhow", + "async-trait", + "base64", + "chrono", + "form_urlencoded", + "getrandom 0.2.16", + "hex", + "hmac", + "home", + "http", + "log", + "percent-encoding", + "quick-xml 0.37.5", + "rand 0.8.5", + "reqwest 0.12.28", + "rust-ini", + "serde", + "serde_json", + "sha1", + "sha2", + "tokio", +] + [[package]] name = "reqwest" version = "0.12.28" @@ -1815,20 +1797,21 @@ dependencies = [ "http-body", "http-body-util", "hyper", - "hyper-tls", + "hyper-rustls", "hyper-util", "js-sys", "log", - "native-tls", "percent-encoding", "pin-project-lite", + "quinn", + "rustls", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", "tokio", - "tokio-native-tls", + "tokio-rustls", "tokio-util", "tower", "tower-http", @@ -1838,6 +1821,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", + "webpki-roots", ] [[package]] @@ -1904,47 +1888,21 @@ dependencies = [ "ordered-multimap", ] -[[package]] -name = "rust-s3" -version = "0.37.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4af74047374528b627109d579ce86b23ccf6ffba7ff363c807126c1aff69e1bb" -dependencies = [ - "async-trait", - "aws-creds", - "aws-region", - "base64", - "bytes", - "cfg-if", - "futures-util", - "hex", - "hmac", - "http", - "log", - "maybe-async", - "md5", - "minidom", - "percent-encoding", - "quick-xml", - "reqwest 0.12.28", - "serde", - "serde_derive", - "serde_json", - "sha2", - "sysinfo", - "thiserror 2.0.17", - "time", - "tokio", - "tokio-stream", - "url", -] - [[package]] name = "rustc-hash" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rusticata-macros" version = "4.1.0" @@ -1975,6 +1933,7 @@ checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" dependencies = [ "aws-lc-rs", "once_cell", + "ring", "rustls-pki-types", "rustls-webpki", "subtle", @@ -1987,10 +1946,10 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" dependencies = [ - "openssl-probe 0.2.0", + "openssl-probe", "rustls-pki-types", "schannel", - "security-framework 3.5.1", + "security-framework", ] [[package]] @@ -2018,7 +1977,7 @@ dependencies = [ "rustls-native-certs", "rustls-platform-verifier-android", "rustls-webpki", - "security-framework 3.5.1", + "security-framework", "security-framework-sys", "webpki-root-certs", "windows-sys 0.61.2", @@ -2048,25 +2007,6 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" -[[package]] -name = "rxml" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc94b580d0f5a6b7a2d604e597513d3c673154b52ddeccd1d5c32360d945ee" -dependencies = [ - "bytes", - "rxml_validation", -] - -[[package]] -name = "rxml_validation" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826e80413b9a35e9d33217b3dcac04cf95f6559d15944b93887a08be5496c4a4" -dependencies = [ - "compact_str", -] - [[package]] name = "ryu" version = "1.0.22" @@ -2091,19 +2031,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags", - "core-foundation 0.9.4", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - [[package]] name = "security-framework" version = "3.5.1" @@ -2127,6 +2054,12 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + [[package]] name = "serde" version = "1.0.228" @@ -2182,6 +2115,17 @@ dependencies = [ "serde", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha2" version = "0.10.9" @@ -2242,12 +2186,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "strsim" version = "0.11.1" @@ -2291,20 +2229,6 @@ dependencies = [ "syn", ] -[[package]] -name = "sysinfo" -version = "0.37.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16607d5caffd1c07ce073528f9ed972d88db15dd44023fa57142963be3feb11f" -dependencies = [ - "libc", - "memchr", - "ntapi", - "objc2-core-foundation", - "objc2-io-kit", - "windows", -] - [[package]] name = "system-configuration" version = "0.6.1" @@ -2471,16 +2395,6 @@ dependencies = [ "syn", ] -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - [[package]] name = "tokio-rustls" version = "0.26.4" @@ -2491,17 +2405,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-stream" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - [[package]] name = "tokio-util" version = "0.7.18" @@ -2510,6 +2413,7 @@ checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" dependencies = [ "bytes", "futures-core", + "futures-io", "futures-sink", "pin-project-lite", "tokio", @@ -2647,15 +2551,10 @@ checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" dependencies = [ "getrandom 0.3.4", "js-sys", + "serde_core", "wasm-bindgen", ] -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "version_check" version = "0.9.5" @@ -2813,21 +2712,14 @@ dependencies = [ ] [[package]] -name = "winapi" -version = "0.3.9" +name = "webpki-roots" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c" dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", + "rustls-pki-types", ] -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - [[package]] name = "winapi-util" version = "0.1.11" @@ -2837,47 +2729,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows" -version = "0.61.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" -dependencies = [ - "windows-collections", - "windows-core 0.61.2", - "windows-future", - "windows-link 0.1.3", - "windows-numerics", -] - -[[package]] -name = "windows-collections" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" -dependencies = [ - "windows-core 0.61.2", -] - -[[package]] -name = "windows-core" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link 0.1.3", - "windows-result 0.3.4", - "windows-strings 0.4.2", -] - [[package]] name = "windows-core" version = "0.62.2" @@ -2886,20 +2737,9 @@ checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", - "windows-link 0.2.1", - "windows-result 0.4.1", - "windows-strings 0.5.1", -] - -[[package]] -name = "windows-future" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" -dependencies = [ - "windows-core 0.61.2", - "windows-link 0.1.3", - "windows-threading", + "windows-link", + "windows-result", + "windows-strings", ] [[package]] @@ -2924,46 +2764,21 @@ dependencies = [ "syn", ] -[[package]] -name = "windows-link" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" -[[package]] -name = "windows-numerics" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" -dependencies = [ - "windows-core 0.61.2", - "windows-link 0.1.3", -] - [[package]] name = "windows-registry" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" dependencies = [ - "windows-link 0.2.1", - "windows-result 0.4.1", - "windows-strings 0.5.1", -] - -[[package]] -name = "windows-result" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" -dependencies = [ - "windows-link 0.1.3", + "windows-link", + "windows-result", + "windows-strings", ] [[package]] @@ -2972,16 +2787,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-link 0.2.1", -] - -[[package]] -name = "windows-strings" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" -dependencies = [ - "windows-link 0.1.3", + "windows-link", ] [[package]] @@ -2990,7 +2796,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -3026,7 +2832,7 @@ version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -3066,7 +2872,7 @@ version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows-link 0.2.1", + "windows-link", "windows_aarch64_gnullvm 0.53.1", "windows_aarch64_msvc 0.53.1", "windows_i686_gnu 0.53.1", @@ -3077,15 +2883,6 @@ dependencies = [ "windows_x86_64_msvc 0.53.1", ] -[[package]] -name = "windows-threading" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" -dependencies = [ - "windows-link 0.1.3", -] - [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index f3202a91..cdfbd0fa 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -16,12 +16,12 @@ fern = { version = "0.7.1", features = ["colored"] } futures = "0.3.31" indicatif = "0.18.3" log = "0.4.29" +opendal = { version = "0.55.0", features = ["services-s3"] } rand = "0.9.2" reqwest = { version = "0.13.1", features = ["json"] } -rust-s3 = "0.37.1" serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0.148" tokio = { version = "1.48.0", features = ["fs", "macros"] } -tokio-util = "0.7.18" +tokio-util = { version = "0.7.18", features = ["compat"] } url = "2.5.8" webbrowser = "1.0.6" diff --git a/cli/src/cli.rs b/cli/src/cli.rs index af391b0d..1ebd41e1 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -1,6 +1,6 @@ use clap::{Args, Parser, Subcommand, ValueEnum}; -use crate::commands::configure::config_option::ConfigOptionCli; +use crate::commands::connect::config_option::ConfigOptionCli; #[derive(Parser)] #[command(version, about, long_about = None)] @@ -16,7 +16,7 @@ pub struct Cli { #[derive(Subcommand)] pub enum Commands { /// Configures downpour endpoints - Configure { + Connect { #[arg(short, long)] name: String, #[command(subcommand)] diff --git a/cli/src/commands/configure/config_option.rs b/cli/src/commands/configure/config_option.rs deleted file mode 100644 index 638b2a8d..00000000 --- a/cli/src/commands/configure/config_option.rs +++ /dev/null @@ -1,18 +0,0 @@ -use clap::Subcommand; -use serde::{Deserialize, Serialize}; - -use crate::commands::configure::{ - s3::{S3Config, S3ConfigCli}, - server::{ServerConfig, ServerConfigCli}, -}; - -#[derive(Subcommand, Clone)] -pub enum ConfigOptionCli { - Server(ServerConfigCli), - S3(S3ConfigCli), -} -#[derive(Serialize, Deserialize, Clone)] -pub enum ConfigOption { - Server(ServerConfig), - S3(S3Config), -} diff --git a/cli/src/commands/configure/configurable.rs b/cli/src/commands/configure/configurable.rs deleted file mode 100644 index f8240083..00000000 --- a/cli/src/commands/configure/configurable.rs +++ /dev/null @@ -1,5 +0,0 @@ -use crate::commands::configure::config_option::ConfigOption; - -pub trait Configurable { - async fn configure(self) -> anyhow::Result; -} diff --git a/cli/src/commands/configure/s3.rs b/cli/src/commands/configure/s3.rs deleted file mode 100644 index 92dc3502..00000000 --- a/cli/src/commands/configure/s3.rs +++ /dev/null @@ -1,65 +0,0 @@ -use std::str::FromStr; - -use clap::Args; -use s3::{Bucket, Region, creds::Credentials}; -use serde::{Deserialize, Serialize}; - -use crate::{ - commands::configure::{config_option::ConfigOption, configurable::Configurable}, - interactive_optional_variable, interactive_variable, -}; - -#[derive(Args, Clone)] -pub struct S3ConfigCli { - secret_key: Option, - key_id: Option, - region: Option, - bucket_name: Option, - endpoint: Option, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct S3Config { - secret_key: String, - key_id: String, - region: String, - bucket_name: String, - endpoint: Option, -} - -impl Configurable for S3ConfigCli { - async fn configure(self) -> anyhow::Result { - interactive_variable!(self, secret_key, "S3 Secret Key"); - interactive_variable!(self, key_id, "S3 Key ID"); - interactive_variable!(self, region, "S3 Region"); - interactive_variable!(self, bucket_name, "S3 Bucket Name"); - interactive_optional_variable!(self, endpoint, "S3 Endpoint (leave blank for none"); - Ok(ConfigOption::S3(S3Config { - secret_key, - key_id, - region, - bucket_name, - endpoint, - })) - } -} - -impl S3Config { - pub fn generate_bucket(&self) -> anyhow::Result { - let credentials = - Credentials::new(Some(&self.key_id), Some(&self.secret_key), None, None, None)?; - - let region = if let Some(endpoint) = &self.endpoint { - Region::Custom { - region: self.region.clone(), - endpoint: endpoint.clone(), - } - } else { - Region::from_str(&self.region)? - }; - - let bucket = Bucket::new(&self.bucket_name, region, credentials)?; - - Ok(*bucket) - } -} diff --git a/cli/src/commands/configure/server.rs b/cli/src/commands/configure/server.rs deleted file mode 100644 index a9be5c21..00000000 --- a/cli/src/commands/configure/server.rs +++ /dev/null @@ -1,92 +0,0 @@ -use clap::Args; -use serde::{Deserialize, Serialize}; -use std::sync::LazyLock; - -use anyhow::{Result, anyhow}; -use dialoguer::{Confirm, Input, theme::ColorfulTheme}; -use reqwest::Client; -use url::Url; - -use crate::commands::configure::{config_option::ConfigOption, configurable::Configurable}; - -#[derive(Serialize, Deserialize, Clone)] -pub struct ServerConfig { - url: String, - token: String, -} -#[derive(Args, Clone)] -pub struct ServerConfigCli { - /// Endpoint of the Drop server - url: String, - #[arg(short, long)] - token: Option, -} - -const TOKEN_CREATE_PAYLOAD: &str = - "eyJuYW1lIjoiZG93bnBvdXIgKGNsaSkiLCJhY2xzIjpbImRlcG90Om5ldyJdfQ=="; - -impl Configurable for ServerConfigCli { - async fn configure(self) -> anyhow::Result { - let base_url = Url::parse(&self.url)?; - let mut token_create_url = base_url.join("/admin/settings/tokens")?; - { - let mut query = token_create_url.query_pairs_mut(); - query.append_pair("payload", TOKEN_CREATE_PAYLOAD); - }; - - let confirm = Confirm::with_theme(&ColorfulTheme::default()) - .with_prompt(format!( - "Open \"{}\" in your default browser?", - token_create_url.as_str() - )) - .interact()?; - - if !confirm { - return Err(anyhow!("User cancelled action")); - } - - webbrowser::open(token_create_url.as_str())?; - - let token: String = Input::with_theme(&ColorfulTheme::default()) - .with_prompt("API token") - .interact_text()?; - - validate_configuration(&self.url, &token).await?; - - Ok(ConfigOption::Server(ServerConfig { - url: self.url, - token, - })) - } -} - -static CLIENT: LazyLock = LazyLock::new(|| reqwest::Client::new()); -const REQUIRED_ACLS: [&str; 1] = ["depot:new"]; - -pub async fn validate_configuration(url: &str, token: &str) -> Result<()> { - let base_url = Url::parse(&url)?; - let token_check_url = base_url.join("/api/v1/token")?; - - let acl_check = CLIENT - .get(token_check_url) - .bearer_auth(token) - .send() - .await?; - - if !acl_check.status().is_success() { - return Err(anyhow!( - "ACL check failed with response code: {}", - acl_check.status() - )); - } - - let acls: Vec = acl_check.json().await?; - - for acl in REQUIRED_ACLS { - if !acls.contains(&acl.to_string()) { - return Err(anyhow!("Token missing {} acl", acl)); - } - } - - Ok(()) -} diff --git a/cli/src/commands/configure/config.rs b/cli/src/commands/connect/config.rs similarity index 60% rename from cli/src/commands/configure/config.rs rename to cli/src/commands/connect/config.rs index a5697496..8ac23e81 100644 --- a/cli/src/commands/configure/config.rs +++ b/cli/src/commands/connect/config.rs @@ -1,29 +1,32 @@ -use crate::commands::configure::{ +use crate::{commands::{connect::{ config_option::{ConfigOption, ConfigOptionCli}, - configurable::Configurable, + configurable::Configure, s3::S3Config, -}; +}, upload::speedtest::Speedtest}, manifest::DepotManifest}; use dialoguer::{Confirm, theme::ColorfulTheme}; -use log::warn; +use futures::AsyncWriteExt; +use log::{debug, info, warn}; +use opendal::Operator; use serde::{Deserialize, Serialize}; -use std::{collections::HashMap, fs}; +use tokio_util::compat::FuturesAsyncWriteCompatExt; +use std::{collections::HashMap, fs, ops::Not}; const CONFIG_DIR: &str = "downpour/config.json"; #[derive(Serialize, Deserialize)] pub struct Config { - items: HashMap, + configurations: HashMap, active_s3: Option, } impl Config { pub fn new() -> Self { Self { - items: HashMap::new(), + configurations: HashMap::new(), active_s3: None, } } pub fn exists(&self, name: &String) -> bool { - self.items.contains_key(name) + self.configurations.contains_key(name) } pub fn save(&self) -> anyhow::Result<()> { let json = serde_json::to_string(self)?; @@ -48,13 +51,13 @@ impl Config { if matches!(object, ConfigOption::S3(..)) { self.active_s3 = Some(name.clone()) } - self.items.insert(name, object); + self.configurations.insert(name, object); self.save().expect("Failed to save config"); } pub fn get_active_s3(&self) -> Option { if let Some(active_s3) = &self.active_s3 { - self.items + self.configurations .iter() .filter_map(|(name, option)| { if *name == *active_s3 { @@ -76,6 +79,9 @@ impl Config { None } } + pub fn get>(&self, name: T) -> Option<&ConfigOption> { + self.configurations.get(name.as_ref()) + } } pub async fn manage_configuration( @@ -94,12 +100,37 @@ pub async fn manage_configuration( return Err(anyhow::anyhow!("User cancelled action")); } } - config.add_item( - name.clone(), - match option { - ConfigOptionCli::Server(server_config) => server_config.clone().configure().await?, - ConfigOptionCli::S3(s3_config_cli) => s3_config_cli.clone().configure().await?, - }, - ); + let config_option = match option { + ConfigOptionCli::S3(s3_config_cli) => s3_config_cli.clone().configure().await?, + }; + config.add_item(name.clone(), config_option.clone()); + let operator = config_option.build()?; + + generate_speedtest(&operator).await?; + generate_manifest(&operator).await?; + Ok(()) } + +async fn generate_speedtest(operator: &Operator) -> anyhow::Result<()> { + if operator.exists("speedtest").await?.not() { + info!("Speedtest already exists on Depot. Skipping speedtest upload..."); + return Ok(()) + } + let mut writer = operator.writer("speedtest").await?.into_futures_async_write().compat_write(); + let mut reader = Speedtest::new(); + let written = tokio::io::copy(&mut reader, &mut writer).await?; + debug!("Wrote {} bytes to {:?}", written, operator.info()); + writer.into_inner().close().await?; + Ok(()) +} +async fn generate_manifest(operator: &Operator) -> anyhow::Result<()> { + info!("Manifest already exists on Depot. Skipping manifest upload..."); + if operator.exists("manifest.json").await?.not() { + return Ok(()) + } + let data = DepotManifest::new(); + operator.write("manifest.json", serde_json::to_string(&data)?).await?; + + Ok(()) +} \ No newline at end of file diff --git a/cli/src/commands/connect/config_option.rs b/cli/src/commands/connect/config_option.rs new file mode 100644 index 00000000..fd90453e --- /dev/null +++ b/cli/src/commands/connect/config_option.rs @@ -0,0 +1,26 @@ +use clap::Subcommand; +use opendal::{Operator, layers::LoggingLayer}; +use serde::{Deserialize, Serialize}; + +use crate::commands::{ + connect::s3::{S3Config, S3ConfigCli}, + upload::uploadable::OperatorBuilder, +}; + +#[derive(Subcommand, Clone)] +pub enum ConfigOptionCli { + S3(S3ConfigCli), +} +#[derive(Serialize, Deserialize, Clone)] +pub enum ConfigOption { + S3(S3Config), +} + +impl ConfigOption { + pub fn build(&self) -> anyhow::Result { + Ok(match self { + ConfigOption::S3(s3_config) => s3_config.build()?, + } + .layer(LoggingLayer::default())) + } +} diff --git a/cli/src/commands/connect/configurable.rs b/cli/src/commands/connect/configurable.rs new file mode 100644 index 00000000..ad7b4a61 --- /dev/null +++ b/cli/src/commands/connect/configurable.rs @@ -0,0 +1,5 @@ +use crate::commands::connect::config_option::ConfigOption; + +pub trait Configure { + async fn configure(self) -> anyhow::Result; +} diff --git a/cli/src/commands/configure/interactive.rs b/cli/src/commands/connect/interactive.rs similarity index 86% rename from cli/src/commands/configure/interactive.rs rename to cli/src/commands/connect/interactive.rs index d567f3f5..8c53012d 100644 --- a/cli/src/commands/configure/interactive.rs +++ b/cli/src/commands/connect/interactive.rs @@ -8,7 +8,7 @@ macro_rules! interactive_variable { let $var = if let Some($var) = $value.$var { $var } else { - crate::commands::configure::interactive::query_variable($prompt).unwrap() + crate::commands::connect::interactive::query_variable($prompt).unwrap() }; }; } @@ -18,7 +18,7 @@ macro_rules! interactive_optional_variable { let $var = if let Some($var) = $value.$var { Some($var) } else { - crate::commands::configure::interactive::query_optional_variable($prompt).unwrap() + crate::commands::connect::interactive::query_optional_variable($prompt).unwrap() }; }; } diff --git a/cli/src/commands/configure/mod.rs b/cli/src/commands/connect/mod.rs similarity index 86% rename from cli/src/commands/configure/mod.rs rename to cli/src/commands/connect/mod.rs index 843cc4c5..dcb64e3e 100644 --- a/cli/src/commands/configure/mod.rs +++ b/cli/src/commands/connect/mod.rs @@ -1,7 +1,6 @@ pub mod config; pub mod configurable; pub mod s3; -pub mod server; #[macro_use] pub mod interactive; pub mod config_option; diff --git a/cli/src/commands/connect/s3.rs b/cli/src/commands/connect/s3.rs new file mode 100644 index 00000000..6a7608d4 --- /dev/null +++ b/cli/src/commands/connect/s3.rs @@ -0,0 +1,66 @@ +use clap::Args; +use opendal::Operator; +use serde::{Deserialize, Serialize}; + +use crate::{ + commands::{ + connect::{config_option::ConfigOption, configurable::Configure}, + upload::uploadable::OperatorBuilder, + }, + interactive_variable, +}; + +#[derive(Args, Clone)] +pub struct S3ConfigCli { + key_id: Option, + secret_key: Option, + endpoint: Option, + region: Option, + bucket_name: Option, + root: Option, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct S3Config { + key_id: String, + secret_key: String, + endpoint: String, + region: String, + bucket_name: String, + root: Option, +} + +impl Configure for S3ConfigCli { + async fn configure(self) -> anyhow::Result { + interactive_variable!(self, key_id, "S3 Key ID"); + interactive_variable!(self, secret_key, "S3 Secret Key"); + interactive_variable!(self, region, "S3 Region"); + interactive_variable!(self, bucket_name, "S3 Bucket Name"); + interactive_variable!(self, endpoint, "S3 Endpoint"); + Ok(ConfigOption::S3(S3Config { + secret_key, + key_id, + region, + bucket_name, + endpoint, + root: self.root, + })) + } +} + +impl OperatorBuilder for S3Config { + fn build(&self) -> anyhow::Result { + let builder = opendal::services::S3::default() + .access_key_id(&self.key_id) + .secret_access_key(&self.secret_key) + .region(&self.region) + .endpoint(&self.endpoint) + .root(self.root.as_ref().map(|s| s.as_str()).unwrap_or("/")) + .bucket(&self.bucket_name) + .disable_config_load(); + + let op: Operator = Operator::new(builder)?.finish(); + + Ok(op) + } +} diff --git a/cli/src/commands/mod.rs b/cli/src/commands/mod.rs index db8ad986..0a9a925a 100644 --- a/cli/src/commands/mod.rs +++ b/cli/src/commands/mod.rs @@ -1,2 +1,2 @@ -pub mod configure; +pub mod connect; pub mod upload; diff --git a/cli/src/commands/upload/interface.rs b/cli/src/commands/upload/interface.rs index d87c0817..b2244142 100644 --- a/cli/src/commands/upload/interface.rs +++ b/cli/src/commands/upload/interface.rs @@ -2,11 +2,11 @@ use std::path::{Path, PathBuf}; use crate::{ cli::UploadInfo, - commands::configure::config::Config, - commands::upload::{s3::S3, uploadable::Uploadable}, + commands::{connect::config::Config, upload::{chunk_reader::ChunkReader, uploadable::OperatorBuilder}}, manifest::generate_manifest, }; use log::info; +use tokio_util::compat::FuturesAsyncWriteCompatExt; pub async fn upload(info: &UploadInfo, config: Config) -> anyhow::Result<()> { let game_id = &info.game_id; @@ -14,27 +14,19 @@ pub async fn upload(info: &UploadInfo, config: Config) -> anyhow::Result<()> { let version_id = &info.version_id; let manifest = generate_manifest(&Path::new(path)).await?; - let mut uploader: Box = match info.upload_style { - crate::cli::UploadStyle::S3 => Box::new(S3::new( - &config + let operator = match info.upload_style { + crate::cli::UploadStyle::S3 => config .get_active_s3() - .ok_or(anyhow::Error::msg("Could not get active S3 value"))?, - )?), + .ok_or(anyhow::Error::msg("Could not get active S3 value"))?.build()?, }; info!("Uploading chunks"); for (id, data) in &manifest.chunks { info!("Uploading chunk id {id}"); - uploader.upload_chunk(PathBuf::from(path), game_id, version_id, id, data).await?; + let mut reader = ChunkReader::new(&path, data); + let mut writer = operator.writer(&format!("{game_id}/{version_id}/{id}")).await?.into_futures_async_write().compat_write(); + tokio::io::copy(&mut reader, &mut writer); } info!("Finished uploading chunks"); - - info!("Uploading manifest"); - uploader - .upload_manifest(manifest, game_id, version_id) - .await?; - - info!("Uploading speedtest"); - uploader.upload_speedtest().await?; - Ok(()) } + diff --git a/cli/src/commands/upload/mod.rs b/cli/src/commands/upload/mod.rs index 3628fe41..76fe819d 100644 --- a/cli/src/commands/upload/mod.rs +++ b/cli/src/commands/upload/mod.rs @@ -1,5 +1,4 @@ pub mod interface; -pub mod s3; pub mod speedtest; pub mod uploadable; pub mod chunk_reader; diff --git a/cli/src/commands/upload/s3.rs b/cli/src/commands/upload/s3.rs deleted file mode 100644 index 387b6bcc..00000000 --- a/cli/src/commands/upload/s3.rs +++ /dev/null @@ -1,84 +0,0 @@ -use crate::commands::{ - configure::s3::S3Config, - upload::{ - chunk_reader::ChunkReader, - speedtest::{SPEEDTEST_PATH, Speedtest}, - uploadable::Uploadable, - }, -}; -use async_trait::async_trait; -use droplet_rs::{ - manifest::{ChunkData, Manifest}, -}; -use s3::Bucket; -use serde_json::json; -use std::{ops::Deref, path::PathBuf}; - -pub struct S3 { - bucket: s3::Bucket, -} -impl S3 { - pub fn new(config: &S3Config) -> anyhow::Result { - Ok(Self { - bucket: config.generate_bucket()?, - }) - } -} -#[async_trait] -impl Uploadable for S3 { - async fn upload_chunk( - &mut self, - base_path: PathBuf, - id: &String, - version: &String, - chunk_id: &String, - chunk: &ChunkData, - ) -> anyhow::Result<()> { - let path = &PathBuf::from(id) - .join(version) - .join(chunk_id) - .to_string_lossy() - .to_string(); - let mut reader = ChunkReader::new(&base_path, chunk); - self.put_object_stream(&mut reader, &path).await?; - Ok(()) - } - async fn upload_speedtest(&mut self) -> anyhow::Result<()> { - if self.object_exists(SPEEDTEST_PATH).await? { - return Ok(()); - } - println!("Uploading speedtest"); - let mut speedtest = Speedtest::new(); - self.put_object_stream(&mut speedtest, SPEEDTEST_PATH) - .await?; - Ok(()) - } - - async fn upload_manifest( - &mut self, - manifest: Manifest, - game_id: &String, - version_id: &String, - ) -> anyhow::Result<()> { - self.put_object_builder( - PathBuf::from(game_id) - .join(version_id) - .join("manifest.json") - .to_string_lossy() - .to_string(), - json!(manifest).to_string().as_bytes(), - ) - .with_content_type("application/json") - .execute() - .await?; - Ok(()) - } -} - -impl Deref for S3 { - type Target = Bucket; - - fn deref(&self) -> &Self::Target { - &self.bucket - } -} diff --git a/cli/src/commands/upload/uploadable.rs b/cli/src/commands/upload/uploadable.rs index e6dbec3d..268a5d0b 100644 --- a/cli/src/commands/upload/uploadable.rs +++ b/cli/src/commands/upload/uploadable.rs @@ -2,22 +2,9 @@ use std::path::PathBuf; use async_trait::async_trait; use droplet_rs::manifest::{ChunkData, Manifest}; +use opendal::Operator; #[async_trait] -pub trait Uploadable { - async fn upload_chunk( - &mut self, - base_path: PathBuf, - id: &String, - version: &String, - chunk_id: &String, - chunk: &ChunkData, - ) -> anyhow::Result<()>; - async fn upload_speedtest(&mut self) -> anyhow::Result<()>; - async fn upload_manifest( - &mut self, - manifest: Manifest, - game_id: &String, - version_id: &String, - ) -> anyhow::Result<()>; +pub trait OperatorBuilder { + fn build(&self) -> anyhow::Result; } diff --git a/cli/src/main.rs b/cli/src/main.rs index 6c9527a3..e87e1969 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,7 +1,7 @@ -use crate::commands::configure::config::manage_configuration; +use crate::commands::connect::config::manage_configuration; use crate::{ cli::{Cli, Commands}, - commands::configure::config::Config, + commands::connect::config::Config, commands::upload, }; use clap::Parser; @@ -18,7 +18,7 @@ async fn main() -> anyhow::Result<()> { let mut config = Config::read(); match &cli.command { - Commands::Configure { name, option } => { + Commands::Connect { name, option } => { manage_configuration(&mut config, name, option).await? } Commands::Upload(info) => { diff --git a/cli/src/manifest.rs b/cli/src/manifest.rs index ebc539e4..0ef40c0f 100644 --- a/cli/src/manifest.rs +++ b/cli/src/manifest.rs @@ -1,7 +1,40 @@ -use std::path::Path; +use std::{collections::HashMap, path::Path}; use droplet_rs::manifest::{Manifest, generate_manifest_rusty}; use indicatif::{ProgressBar, ProgressStyle}; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +pub struct DepotManifest { + content: HashMap, +} +#[derive(Serialize, Deserialize)] +struct DepotManifestGameData { + version_id: String, + compression: CompressionOption, +} +#[derive(Serialize, Deserialize)] +pub enum CompressionOption { + None, + Gzip, + Zstd, +} +impl DepotManifest { + pub fn new() -> Self { + Self { + content: HashMap::new(), + } + } + pub fn add(&mut self, game_id: String, version_id: String, compression: CompressionOption) { + self.content.insert( + game_id, + DepotManifestGameData { + version_id, + compression, + }, + ); + } +} pub async fn generate_manifest(dir: &Path) -> anyhow::Result { let progress_bar = ProgressBar::new(100_00).with_style( From bb3280cedf108d1b76151073914069939bdbd95c Mon Sep 17 00:00:00 2001 From: quexeky Date: Sun, 25 Jan 2026 22:07:50 +1100 Subject: [PATCH 18/22] fix: Speedtest not registering number of bytes read --- cli/src/commands/connect/config.rs | 63 +++++++++++++------ cli/src/commands/connect/interactive.rs | 6 +- cli/src/commands/connect/mod.rs | 1 + cli/src/commands/connect/s3.rs | 2 +- .../commands/{upload => connect}/speedtest.rs | 22 ++++--- cli/src/commands/upload/chunk_reader.rs | 3 +- cli/src/commands/upload/interface.rs | 27 +++++--- cli/src/commands/upload/mod.rs | 5 +- cli/src/commands/upload/uploadable.rs | 2 - cli/src/manifest.rs | 10 +-- 10 files changed, 90 insertions(+), 51 deletions(-) rename cli/src/commands/{upload => connect}/speedtest.rs (55%) diff --git a/cli/src/commands/connect/config.rs b/cli/src/commands/connect/config.rs index 8ac23e81..1f42f7db 100644 --- a/cli/src/commands/connect/config.rs +++ b/cli/src/commands/connect/config.rs @@ -1,15 +1,22 @@ -use crate::{commands::{connect::{ - config_option::{ConfigOption, ConfigOptionCli}, - configurable::Configure, - s3::S3Config, -}, upload::speedtest::Speedtest}, manifest::DepotManifest}; +use crate::{ + commands::{ + connect::{ + config_option::{ConfigOption, ConfigOptionCli}, + configurable::Configure, + s3::S3Config, + speedtest::{SPEEDTEST_PATH, Speedtest} + }, + }, + manifest::DepotManifest, +}; use dialoguer::{Confirm, theme::ColorfulTheme}; use futures::AsyncWriteExt; +use indicatif::{ProgressBar, ProgressStyle}; use log::{debug, info, warn}; use opendal::Operator; use serde::{Deserialize, Serialize}; -use tokio_util::compat::FuturesAsyncWriteCompatExt; use std::{collections::HashMap, fs, ops::Not}; +use tokio_util::compat::FuturesAsyncWriteCompatExt; const CONFIG_DIR: &str = "downpour/config.json"; @@ -41,7 +48,7 @@ impl Config { let save_path = dirs::config_dir() .expect("Apparently your home directory doesn't exist") // Should probably formalise that error .join(CONFIG_DIR); - if fs::exists(&save_path).expect(&format!("Could not read save path {:#?}", &save_path)) { + if fs::exists(&save_path).unwrap_or_else(|_| panic!("Could not read save path {:#?}", &save_path)) { serde_json::from_str(&fs::read_to_string(save_path).unwrap()).unwrap() } else { Config::new() @@ -74,7 +81,6 @@ impl Config { }) .next() .cloned() - .map(|c| c.into()) } else { None } @@ -89,7 +95,7 @@ pub async fn manage_configuration( name: &String, option: &ConfigOptionCli, ) -> anyhow::Result<()> { - if config.exists(&name) { + if config.exists(name) { let confirm = Confirm::with_theme(&ColorfulTheme::default()) .with_prompt(format!( "An entry already exists with the name \"{}\". Would you like to overwrite it?", @@ -106,31 +112,50 @@ pub async fn manage_configuration( config.add_item(name.clone(), config_option.clone()); let operator = config_option.build()?; - generate_speedtest(&operator).await?; generate_manifest(&operator).await?; + generate_speedtest(&operator).await?; Ok(()) } async fn generate_speedtest(operator: &Operator) -> anyhow::Result<()> { - if operator.exists("speedtest").await?.not() { + // Workaround to operator.exists("...") also logging a 404 warning + let lister = operator.list_with(SPEEDTEST_PATH).limit(1).await?; + if lister.is_empty().not() { info!("Speedtest already exists on Depot. Skipping speedtest upload..."); - return Ok(()) + return Ok(()); } - let mut writer = operator.writer("speedtest").await?.into_futures_async_write().compat_write(); - let mut reader = Speedtest::new(); + let mut writer = operator + .writer(SPEEDTEST_PATH) + .await? + .into_futures_async_write() + .compat_write(); + + let progress_bar = ProgressBar::new(10_000).with_style( + ProgressStyle::default_bar() + .template("[{elapsed_precise}] [ETA {eta}] {bar} {percent_precise}%") + .unwrap(), + ); + + let mut reader = Speedtest::new(|progress| { + let progress_int = (progress * 100f32).round() as u64; + progress_bar.set_position(progress_int); + }); let written = tokio::io::copy(&mut reader, &mut writer).await?; debug!("Wrote {} bytes to {:?}", written, operator.info()); writer.into_inner().close().await?; Ok(()) } async fn generate_manifest(operator: &Operator) -> anyhow::Result<()> { - info!("Manifest already exists on Depot. Skipping manifest upload..."); - if operator.exists("manifest.json").await?.not() { - return Ok(()) + let lister = operator.list_with("manifest.json").limit(1).await?; + if lister.is_empty().not() { + info!("Manifest already exists on Depot. Skipping manifest upload..."); + return Ok(()); } let data = DepotManifest::new(); - operator.write("manifest.json", serde_json::to_string(&data)?).await?; + operator + .write("manifest.json", serde_json::to_string(&data)?) + .await?; Ok(()) -} \ No newline at end of file +} diff --git a/cli/src/commands/connect/interactive.rs b/cli/src/commands/connect/interactive.rs index 8c53012d..8e823198 100644 --- a/cli/src/commands/connect/interactive.rs +++ b/cli/src/commands/connect/interactive.rs @@ -8,7 +8,7 @@ macro_rules! interactive_variable { let $var = if let Some($var) = $value.$var { $var } else { - crate::commands::connect::interactive::query_variable($prompt).unwrap() + $crate::commands::connect::interactive::query_variable($prompt).unwrap() }; }; } @@ -18,7 +18,7 @@ macro_rules! interactive_optional_variable { let $var = if let Some($var) = $value.$var { Some($var) } else { - crate::commands::connect::interactive::query_optional_variable($prompt).unwrap() + $crate::commands::connect::interactive::query_optional_variable($prompt).unwrap() }; }; } @@ -40,7 +40,7 @@ where .with_prompt(prompt.to_string()) .allow_empty(true) .interact_text()?; - if input.to_string().len() == 0 { + if input.to_string().is_empty() { return Ok(None); } Ok(Some(input)) diff --git a/cli/src/commands/connect/mod.rs b/cli/src/commands/connect/mod.rs index dcb64e3e..397bc110 100644 --- a/cli/src/commands/connect/mod.rs +++ b/cli/src/commands/connect/mod.rs @@ -4,3 +4,4 @@ pub mod s3; #[macro_use] pub mod interactive; pub mod config_option; +pub mod speedtest; \ No newline at end of file diff --git a/cli/src/commands/connect/s3.rs b/cli/src/commands/connect/s3.rs index 6a7608d4..1b95c9e3 100644 --- a/cli/src/commands/connect/s3.rs +++ b/cli/src/commands/connect/s3.rs @@ -55,7 +55,7 @@ impl OperatorBuilder for S3Config { .secret_access_key(&self.secret_key) .region(&self.region) .endpoint(&self.endpoint) - .root(self.root.as_ref().map(|s| s.as_str()).unwrap_or("/")) + .root(self.root.as_deref().unwrap_or("/")) .bucket(&self.bucket_name) .disable_config_load(); diff --git a/cli/src/commands/upload/speedtest.rs b/cli/src/commands/connect/speedtest.rs similarity index 55% rename from cli/src/commands/upload/speedtest.rs rename to cli/src/commands/connect/speedtest.rs index 15a16bb9..a039469f 100644 --- a/cli/src/commands/upload/speedtest.rs +++ b/cli/src/commands/connect/speedtest.rs @@ -2,14 +2,15 @@ use rand::{RngCore, SeedableRng, rng, rngs::StdRng}; use tokio::io::AsyncRead; #[derive(Clone, Debug)] -pub struct Speedtest { +pub struct Speedtest { core: rand::rngs::StdRng, to_write: usize, + callback: Box, } pub const SPEEDTEST_BYTES: usize = 64 * 1024 * 1024; pub const SPEEDTEST_PATH: &str = "speedtest"; -impl AsyncRead for Speedtest { +impl AsyncRead for Speedtest { fn poll_read( self: std::pin::Pin<&mut Self>, _cx: &mut std::task::Context<'_>, @@ -17,17 +18,24 @@ impl AsyncRead for Speedtest { ) -> std::task::Poll> { let mut s = self; let to_write = buf.remaining().min(s.to_write); - s.to_write = s.to_write.saturating_sub(to_write); - let fill_slice = buf.initialize_unfilled_to(to_write); - s.core.fill_bytes(fill_slice); + + let filled = { + let fill_slice = buf.initialize_unfilled_to(to_write); + s.core.fill_bytes(fill_slice); + fill_slice.len() + }; + s.to_write = s.to_write.saturating_sub(filled); + (s.callback)((1f32 - (s.to_write as f32 / SPEEDTEST_BYTES as f32)) * 100f32); + buf.advance(filled); std::task::Poll::Ready(Ok(())) } } -impl Speedtest { - pub fn new() -> Self { +impl Speedtest { + pub fn new(callback: F) -> Self { Self { core: StdRng::from_rng(&mut rng()), to_write: SPEEDTEST_BYTES, + callback: Box::new(callback), } } } diff --git a/cli/src/commands/upload/chunk_reader.rs b/cli/src/commands/upload/chunk_reader.rs index 507b3d07..e51dc566 100644 --- a/cli/src/commands/upload/chunk_reader.rs +++ b/cli/src/commands/upload/chunk_reader.rs @@ -45,7 +45,7 @@ impl ChunkReader { .collect::>() .into_iter(); Self { - files: files, + files, active: None, } } @@ -65,7 +65,6 @@ impl AsyncRead for ChunkReader { continue; } Ok(n) => { - buf.advance(n); return Poll::Ready(Ok(())); diff --git a/cli/src/commands/upload/interface.rs b/cli/src/commands/upload/interface.rs index b2244142..36e8fdf3 100644 --- a/cli/src/commands/upload/interface.rs +++ b/cli/src/commands/upload/interface.rs @@ -1,10 +1,14 @@ -use std::path::{Path, PathBuf}; +use std::path::Path; use crate::{ cli::UploadInfo, - commands::{connect::config::Config, upload::{chunk_reader::ChunkReader, uploadable::OperatorBuilder}}, + commands::{ + connect::config::Config, + upload::{chunk_reader::ChunkReader, uploadable::OperatorBuilder}, + }, manifest::generate_manifest, }; +use futures::AsyncWriteExt; use log::info; use tokio_util::compat::FuturesAsyncWriteCompatExt; @@ -13,20 +17,25 @@ pub async fn upload(info: &UploadInfo, config: Config) -> anyhow::Result<()> { let path = &info.path; let version_id = &info.version_id; - let manifest = generate_manifest(&Path::new(path)).await?; + let manifest = generate_manifest(Path::new(path)).await?; let operator = match info.upload_style { crate::cli::UploadStyle::S3 => config - .get_active_s3() - .ok_or(anyhow::Error::msg("Could not get active S3 value"))?.build()?, + .get_active_s3() + .ok_or(anyhow::Error::msg("Could not get active S3 value"))? + .build()?, }; info!("Uploading chunks"); for (id, data) in &manifest.chunks { info!("Uploading chunk id {id}"); - let mut reader = ChunkReader::new(&path, data); - let mut writer = operator.writer(&format!("{game_id}/{version_id}/{id}")).await?.into_futures_async_write().compat_write(); - tokio::io::copy(&mut reader, &mut writer); + let mut reader = ChunkReader::new(path, data); + let mut writer = operator + .writer(&format!("{game_id}/{version_id}/{id}")) + .await? + .into_futures_async_write() + .compat_write(); + tokio::io::copy(&mut reader, &mut writer).await?; + writer.into_inner().close().await?; } info!("Finished uploading chunks"); Ok(()) } - diff --git a/cli/src/commands/upload/mod.rs b/cli/src/commands/upload/mod.rs index 76fe819d..03bf694e 100644 --- a/cli/src/commands/upload/mod.rs +++ b/cli/src/commands/upload/mod.rs @@ -1,4 +1,3 @@ -pub mod interface; -pub mod speedtest; -pub mod uploadable; pub mod chunk_reader; +pub mod interface; +pub mod uploadable; diff --git a/cli/src/commands/upload/uploadable.rs b/cli/src/commands/upload/uploadable.rs index 268a5d0b..c623c9eb 100644 --- a/cli/src/commands/upload/uploadable.rs +++ b/cli/src/commands/upload/uploadable.rs @@ -1,7 +1,5 @@ -use std::path::PathBuf; use async_trait::async_trait; -use droplet_rs::manifest::{ChunkData, Manifest}; use opendal::Operator; #[async_trait] diff --git a/cli/src/manifest.rs b/cli/src/manifest.rs index 0ef40c0f..e5e736f7 100644 --- a/cli/src/manifest.rs +++ b/cli/src/manifest.rs @@ -25,7 +25,7 @@ impl DepotManifest { content: HashMap::new(), } } - pub fn add(&mut self, game_id: String, version_id: String, compression: CompressionOption) { + pub fn append(&mut self, game_id: String, version_id: String, compression: CompressionOption) { self.content.insert( game_id, DepotManifestGameData { @@ -37,12 +37,13 @@ impl DepotManifest { } pub async fn generate_manifest(dir: &Path) -> anyhow::Result { - let progress_bar = ProgressBar::new(100_00).with_style( + let progress_bar = ProgressBar::new(10_000).with_style( ProgressStyle::default_bar() .template("[{elapsed_precise}] [ETA {eta}] {bar} {percent_precise}%") .unwrap(), ); - let res = generate_manifest_rusty( + + generate_manifest_rusty( dir, |progress| { let progress_int = (progress * 100f32).round() as u64; @@ -50,6 +51,5 @@ pub async fn generate_manifest(dir: &Path) -> anyhow::Result { }, |log| progress_bar.println(log), ) - .await; - res + .await } From 820c1b06f9d6f60af5c853e5a42d14b1bd63ddec Mon Sep 17 00:00:00 2001 From: quexeky Date: Sun, 25 Jan 2026 22:32:23 +1100 Subject: [PATCH 19/22] feat: Use info! for progress logging Replaces existing progress_bar.println() --- cli/src/commands/connect/config_option.rs | 6 ++---- cli/src/commands/connect/s3.rs | 7 ++----- cli/src/commands/upload/interface.rs | 4 ++-- cli/src/commands/upload/mod.rs | 1 - cli/src/main.rs | 1 + cli/src/manifest.rs | 3 ++- .../{commands/upload/uploadable.rs => operator_builder.rs} | 3 --- 7 files changed, 9 insertions(+), 16 deletions(-) rename cli/src/{commands/upload/uploadable.rs => operator_builder.rs} (69%) diff --git a/cli/src/commands/connect/config_option.rs b/cli/src/commands/connect/config_option.rs index fd90453e..88ee6705 100644 --- a/cli/src/commands/connect/config_option.rs +++ b/cli/src/commands/connect/config_option.rs @@ -2,10 +2,7 @@ use clap::Subcommand; use opendal::{Operator, layers::LoggingLayer}; use serde::{Deserialize, Serialize}; -use crate::commands::{ - connect::s3::{S3Config, S3ConfigCli}, - upload::uploadable::OperatorBuilder, -}; +use crate::{commands::connect::s3::{S3Config, S3ConfigCli}, operator_builder::OperatorBuilder}; #[derive(Subcommand, Clone)] pub enum ConfigOptionCli { @@ -18,6 +15,7 @@ pub enum ConfigOption { impl ConfigOption { pub fn build(&self) -> anyhow::Result { + Ok(match self { ConfigOption::S3(s3_config) => s3_config.build()?, } diff --git a/cli/src/commands/connect/s3.rs b/cli/src/commands/connect/s3.rs index 1b95c9e3..e2f400ec 100644 --- a/cli/src/commands/connect/s3.rs +++ b/cli/src/commands/connect/s3.rs @@ -3,11 +3,8 @@ use opendal::Operator; use serde::{Deserialize, Serialize}; use crate::{ - commands::{ - connect::{config_option::ConfigOption, configurable::Configure}, - upload::uploadable::OperatorBuilder, - }, - interactive_variable, + commands::connect::{config_option::ConfigOption, configurable::Configure}, + interactive_variable, operator_builder::OperatorBuilder, }; #[derive(Args, Clone)] diff --git a/cli/src/commands/upload/interface.rs b/cli/src/commands/upload/interface.rs index 36e8fdf3..982b7ed7 100644 --- a/cli/src/commands/upload/interface.rs +++ b/cli/src/commands/upload/interface.rs @@ -4,9 +4,9 @@ use crate::{ cli::UploadInfo, commands::{ connect::config::Config, - upload::{chunk_reader::ChunkReader, uploadable::OperatorBuilder}, + upload::chunk_reader::ChunkReader, }, - manifest::generate_manifest, + manifest::generate_manifest, operator_builder::OperatorBuilder, }; use futures::AsyncWriteExt; use log::info; diff --git a/cli/src/commands/upload/mod.rs b/cli/src/commands/upload/mod.rs index 03bf694e..cdaa9e81 100644 --- a/cli/src/commands/upload/mod.rs +++ b/cli/src/commands/upload/mod.rs @@ -1,3 +1,2 @@ pub mod chunk_reader; pub mod interface; -pub mod uploadable; diff --git a/cli/src/main.rs b/cli/src/main.rs index e87e1969..627a1490 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -9,6 +9,7 @@ mod cli; mod commands; mod logging; mod manifest; +mod operator_builder; #[tokio::main] async fn main() -> anyhow::Result<()> { diff --git a/cli/src/manifest.rs b/cli/src/manifest.rs index e5e736f7..e6732233 100644 --- a/cli/src/manifest.rs +++ b/cli/src/manifest.rs @@ -2,6 +2,7 @@ use std::{collections::HashMap, path::Path}; use droplet_rs::manifest::{Manifest, generate_manifest_rusty}; use indicatif::{ProgressBar, ProgressStyle}; +use log::info; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize)] @@ -49,7 +50,7 @@ pub async fn generate_manifest(dir: &Path) -> anyhow::Result { let progress_int = (progress * 100f32).round() as u64; progress_bar.set_position(progress_int); }, - |log| progress_bar.println(log), + |log| progress_bar.suspend(|| info!("{}", log)), ) .await } diff --git a/cli/src/commands/upload/uploadable.rs b/cli/src/operator_builder.rs similarity index 69% rename from cli/src/commands/upload/uploadable.rs rename to cli/src/operator_builder.rs index c623c9eb..acc272e1 100644 --- a/cli/src/commands/upload/uploadable.rs +++ b/cli/src/operator_builder.rs @@ -1,8 +1,5 @@ - -use async_trait::async_trait; use opendal::Operator; -#[async_trait] pub trait OperatorBuilder { fn build(&self) -> anyhow::Result; } From a72cac72597e7cb02d09825c3bd8752396a331a7 Mon Sep 17 00:00:00 2001 From: quexeky Date: Mon, 26 Jan 2026 09:06:48 +1100 Subject: [PATCH 20/22] feat: Add name default and manual configuration --- cli/src/cli.rs | 36 +++++++++--- cli/src/commands/connect/config.rs | 70 ++++++++++------------- cli/src/commands/connect/config_option.rs | 7 ++- cli/src/commands/connect/configurable.rs | 2 +- cli/src/commands/connect/mod.rs | 2 +- cli/src/commands/connect/s3.rs | 8 ++- cli/src/commands/upload/interface.rs | 57 ++++++++++++++---- cli/src/main.rs | 7 ++- cli/src/manifest.rs | 4 +- 9 files changed, 123 insertions(+), 70 deletions(-) diff --git a/cli/src/cli.rs b/cli/src/cli.rs index 1ebd41e1..318fc457 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -1,6 +1,6 @@ use clap::{Args, Parser, Subcommand, ValueEnum}; -use crate::commands::connect::config_option::ConfigOptionCli; +use crate::{commands::connect::config_option::ConfigOptionCli, interactive_variable}; #[derive(Parser)] #[command(version, about, long_about = None)] @@ -18,27 +18,49 @@ pub enum Commands { /// Configures downpour endpoints Connect { #[arg(short, long)] - name: String, + name: Option, #[command(subcommand)] option: ConfigOptionCli, }, /// Uploads new game version to depot - Upload(UploadInfo), + Upload { + #[clap(flatten)] + info: UploadInfoCli, + #[arg(short, long)] + /// Alias of a given connection + name: Option, + }, } #[derive(Args)] pub struct UploadInfo { - /// Identifies the specific upload style that will be used for the set depot - pub upload_style: UploadStyle, + pub path: String, + pub game_id: String, + pub version_id: String, +} +#[derive(Args)] +pub struct UploadInfoCli { /// Relative path to new version files #[arg(short, long, default_value_t = String::from("."))] pub path: String, /// ID of game to attach to #[arg(short, long)] - pub game_id: String, + pub game_id: Option, /// Version ID to attach to #[arg(short, long)] - pub version_id: String, + pub version_id: Option, +} +impl UploadInfoCli { + pub fn interactive_configure(self) -> UploadInfo { + let path = self.path; + interactive_variable!(self, game_id, "Game ID"); + interactive_variable!(self, version_id, "Version ID"); + UploadInfo { + path, + game_id, + version_id, + } + } } #[derive(ValueEnum, Copy, Clone, Debug, PartialEq, Eq)] diff --git a/cli/src/commands/connect/config.rs b/cli/src/commands/connect/config.rs index 1f42f7db..3a0f5ce8 100644 --- a/cli/src/commands/connect/config.rs +++ b/cli/src/commands/connect/config.rs @@ -1,18 +1,15 @@ use crate::{ - commands::{ - connect::{ - config_option::{ConfigOption, ConfigOptionCli}, - configurable::Configure, - s3::S3Config, - speedtest::{SPEEDTEST_PATH, Speedtest} - }, + commands::connect::{ + config_option::{ConfigOption, ConfigOptionCli}, + configurable::Configure, + speedtest::{SPEEDTEST_PATH, Speedtest}, }, manifest::DepotManifest, }; use dialoguer::{Confirm, theme::ColorfulTheme}; use futures::AsyncWriteExt; use indicatif::{ProgressBar, ProgressStyle}; -use log::{debug, info, warn}; +use log::{debug, info}; use opendal::Operator; use serde::{Deserialize, Serialize}; use std::{collections::HashMap, fs, ops::Not}; @@ -23,13 +20,13 @@ const CONFIG_DIR: &str = "downpour/config.json"; #[derive(Serialize, Deserialize)] pub struct Config { configurations: HashMap, - active_s3: Option, + active: Option, } impl Config { pub fn new() -> Self { Self { configurations: HashMap::new(), - active_s3: None, + active: None, } } pub fn exists(&self, name: &String) -> bool { @@ -48,7 +45,9 @@ impl Config { let save_path = dirs::config_dir() .expect("Apparently your home directory doesn't exist") // Should probably formalise that error .join(CONFIG_DIR); - if fs::exists(&save_path).unwrap_or_else(|_| panic!("Could not read save path {:#?}", &save_path)) { + if fs::exists(&save_path) + .unwrap_or_else(|_| panic!("Could not read save path {:#?}", &save_path)) + { serde_json::from_str(&fs::read_to_string(save_path).unwrap()).unwrap() } else { Config::new() @@ -56,50 +55,37 @@ impl Config { } pub fn add_item(&mut self, name: String, object: ConfigOption) { if matches!(object, ConfigOption::S3(..)) { - self.active_s3 = Some(name.clone()) + self.active = Some(name.clone()) } self.configurations.insert(name, object); self.save().expect("Failed to save config"); } - pub fn get_active_s3(&self) -> Option { - if let Some(active_s3) = &self.active_s3 { - self.configurations - .iter() - .filter_map(|(name, option)| { - if *name == *active_s3 { - match option { - ConfigOption::S3(s3_config) => Some(s3_config), - _ => { - warn!("Name {} is not of type 'S3'", name); - None - } - } - } else { - None - } - }) - .next() - .cloned() + pub fn get_active(&self) -> Option<&ConfigOption> { + if let Some(active) = &self.active { + self.configurations.get(active) } else { None } } - pub fn get>(&self, name: T) -> Option<&ConfigOption> { + pub fn get>(&self, name: T) -> Option<&ConfigOption> { self.configurations.get(name.as_ref()) } } pub async fn manage_configuration( config: &mut Config, - name: &String, - option: &ConfigOptionCli, + name: Option, + option: ConfigOptionCli, ) -> anyhow::Result<()> { - if config.exists(name) { + let mut name = name; + if let Some(name) = &name + && config.exists(name) + { let confirm = Confirm::with_theme(&ColorfulTheme::default()) .with_prompt(format!( "An entry already exists with the name \"{}\". Would you like to overwrite it?", - &name + name )) .interact()?; if !confirm { @@ -107,9 +93,10 @@ pub async fn manage_configuration( } } let config_option = match option { - ConfigOptionCli::S3(s3_config_cli) => s3_config_cli.clone().configure().await?, + ConfigOptionCli::S3(s3_config_cli) => s3_config_cli.clone().configure(&mut name).await?, }; - config.add_item(name.clone(), config_option.clone()); + let name = name.expect("Default name was not provided by ConfigOption. This is a bug"); + config.add_item(name, config_option.clone()); let operator = config_option.build()?; generate_manifest(&operator).await?; @@ -138,14 +125,15 @@ async fn generate_speedtest(operator: &Operator) -> anyhow::Result<()> { ); let mut reader = Speedtest::new(|progress| { - let progress_int = (progress * 100f32).round() as u64; - progress_bar.set_position(progress_int); - }); + let progress_int = (progress * 100f32).round() as u64; + progress_bar.set_position(progress_int); + }); let written = tokio::io::copy(&mut reader, &mut writer).await?; debug!("Wrote {} bytes to {:?}", written, operator.info()); writer.into_inner().close().await?; Ok(()) } + async fn generate_manifest(operator: &Operator) -> anyhow::Result<()> { let lister = operator.list_with("manifest.json").limit(1).await?; if lister.is_empty().not() { diff --git a/cli/src/commands/connect/config_option.rs b/cli/src/commands/connect/config_option.rs index 88ee6705..d0257bbd 100644 --- a/cli/src/commands/connect/config_option.rs +++ b/cli/src/commands/connect/config_option.rs @@ -2,10 +2,14 @@ use clap::Subcommand; use opendal::{Operator, layers::LoggingLayer}; use serde::{Deserialize, Serialize}; -use crate::{commands::connect::s3::{S3Config, S3ConfigCli}, operator_builder::OperatorBuilder}; +use crate::{ + commands::connect::s3::{S3Config, S3ConfigCli}, + operator_builder::OperatorBuilder, +}; #[derive(Subcommand, Clone)] pub enum ConfigOptionCli { + // Connect to any S3-compatible endpoint S3(S3ConfigCli), } #[derive(Serialize, Deserialize, Clone)] @@ -15,7 +19,6 @@ pub enum ConfigOption { impl ConfigOption { pub fn build(&self) -> anyhow::Result { - Ok(match self { ConfigOption::S3(s3_config) => s3_config.build()?, } diff --git a/cli/src/commands/connect/configurable.rs b/cli/src/commands/connect/configurable.rs index ad7b4a61..d653be30 100644 --- a/cli/src/commands/connect/configurable.rs +++ b/cli/src/commands/connect/configurable.rs @@ -1,5 +1,5 @@ use crate::commands::connect::config_option::ConfigOption; pub trait Configure { - async fn configure(self) -> anyhow::Result; + async fn configure(self, name: &mut Option) -> anyhow::Result; } diff --git a/cli/src/commands/connect/mod.rs b/cli/src/commands/connect/mod.rs index 397bc110..37f13750 100644 --- a/cli/src/commands/connect/mod.rs +++ b/cli/src/commands/connect/mod.rs @@ -4,4 +4,4 @@ pub mod s3; #[macro_use] pub mod interactive; pub mod config_option; -pub mod speedtest; \ No newline at end of file +pub mod speedtest; diff --git a/cli/src/commands/connect/s3.rs b/cli/src/commands/connect/s3.rs index e2f400ec..5b30d101 100644 --- a/cli/src/commands/connect/s3.rs +++ b/cli/src/commands/connect/s3.rs @@ -4,7 +4,8 @@ use serde::{Deserialize, Serialize}; use crate::{ commands::connect::{config_option::ConfigOption, configurable::Configure}, - interactive_variable, operator_builder::OperatorBuilder, + interactive_variable, + operator_builder::OperatorBuilder, }; #[derive(Args, Clone)] @@ -28,12 +29,15 @@ pub struct S3Config { } impl Configure for S3ConfigCli { - async fn configure(self) -> anyhow::Result { + async fn configure(self, name: &mut Option) -> anyhow::Result { interactive_variable!(self, key_id, "S3 Key ID"); interactive_variable!(self, secret_key, "S3 Secret Key"); interactive_variable!(self, region, "S3 Region"); interactive_variable!(self, bucket_name, "S3 Bucket Name"); interactive_variable!(self, endpoint, "S3 Endpoint"); + if let None = name { + *name = Some(endpoint.clone()); + } Ok(ConfigOption::S3(S3Config { secret_key, key_id, diff --git a/cli/src/commands/upload/interface.rs b/cli/src/commands/upload/interface.rs index 982b7ed7..ca2c97ff 100644 --- a/cli/src/commands/upload/interface.rs +++ b/cli/src/commands/upload/interface.rs @@ -3,29 +3,35 @@ use std::path::Path; use crate::{ cli::UploadInfo, commands::{ - connect::config::Config, + connect::{config::Config, config_option::ConfigOption}, upload::chunk_reader::ChunkReader, }, - manifest::generate_manifest, operator_builder::OperatorBuilder, + manifest::{CompressionOption, DepotManifest, generate_v2_manifest}, + operator_builder::OperatorBuilder, }; use futures::AsyncWriteExt; use log::info; +use opendal::Operator; use tokio_util::compat::FuturesAsyncWriteCompatExt; -pub async fn upload(info: &UploadInfo, config: Config) -> anyhow::Result<()> { +pub async fn upload( + info: &UploadInfo, + config: Config, + name: &Option, +) -> anyhow::Result<()> { let game_id = &info.game_id; let path = &info.path; let version_id = &info.version_id; - let manifest = generate_manifest(Path::new(path)).await?; - let operator = match info.upload_style { - crate::cli::UploadStyle::S3 => config - .get_active_s3() - .ok_or(anyhow::Error::msg("Could not get active S3 value"))? - .build()?, - }; + let operator = get_operator(config, name)?; + + let mut existing_depot_manifest = get_depot_manifest(&operator).await?; + + let v2_manifest = generate_v2_manifest(Path::new(path)).await?; + info!("Uploading chunks"); - for (id, data) in &manifest.chunks { + + for (id, data) in &v2_manifest.chunks { info!("Uploading chunk id {id}"); let mut reader = ChunkReader::new(path, data); let mut writer = operator @@ -36,6 +42,35 @@ pub async fn upload(info: &UploadInfo, config: Config) -> anyhow::Result<()> { tokio::io::copy(&mut reader, &mut writer).await?; writer.into_inner().close().await?; } + info!("Finished uploading chunks"); + + existing_depot_manifest.append( + game_id.to_string(), + version_id.to_string(), + CompressionOption::None, + ); Ok(()) } + +async fn get_depot_manifest(operator: &Operator) -> Result { + let existing_depot_manifest = operator.read("manifest.json").await?.to_bytes(); + let existing_depot_manifest: DepotManifest = + serde_json::from_slice(existing_depot_manifest.as_ref())?; + Ok(existing_depot_manifest) +} + +fn get_operator(config: Config, name: &Option) -> anyhow::Result { + let operator = match if let Some(name) = name { + config + .get(name) + .ok_or(anyhow::anyhow!("Name does not exist"))? + } else { + config.get_active().ok_or(anyhow::anyhow!( + "No active connection set. Please specify with --name" + ))? + } { + ConfigOption::S3(s3_config) => s3_config.build()?, + }; + Ok(operator) +} diff --git a/cli/src/main.rs b/cli/src/main.rs index 627a1490..0a0be5c4 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -18,12 +18,13 @@ async fn main() -> anyhow::Result<()> { let cli = Cli::parse(); let mut config = Config::read(); - match &cli.command { + match cli.command { Commands::Connect { name, option } => { manage_configuration(&mut config, name, option).await? } - Commands::Upload(info) => { - upload::interface::upload(info, config).await?; + Commands::Upload { info, name } => { + let info = info.interactive_configure(); + upload::interface::upload(&info, config, &name).await?; } }; diff --git a/cli/src/manifest.rs b/cli/src/manifest.rs index e6732233..fe766f15 100644 --- a/cli/src/manifest.rs +++ b/cli/src/manifest.rs @@ -37,13 +37,13 @@ impl DepotManifest { } } -pub async fn generate_manifest(dir: &Path) -> anyhow::Result { +pub async fn generate_v2_manifest(dir: &Path) -> anyhow::Result { let progress_bar = ProgressBar::new(10_000).with_style( ProgressStyle::default_bar() .template("[{elapsed_precise}] [ETA {eta}] {bar} {percent_precise}%") .unwrap(), ); - + generate_manifest_rusty( dir, |progress| { From b7a429543aeac0b8ae8726a3d0810658016f2c38 Mon Sep 17 00:00:00 2001 From: quexeky Date: Mon, 26 Jan 2026 16:09:20 +1100 Subject: [PATCH 21/22] chore: Migrate to using ReaderStream instead of ChunkReader --- cli/src/commands/upload/chunk_reader.rs | 106 ------------------------ cli/src/commands/upload/interface.rs | 48 +++++++++-- cli/src/commands/upload/mod.rs | 1 - 3 files changed, 40 insertions(+), 115 deletions(-) delete mode 100644 cli/src/commands/upload/chunk_reader.rs diff --git a/cli/src/commands/upload/chunk_reader.rs b/cli/src/commands/upload/chunk_reader.rs deleted file mode 100644 index e51dc566..00000000 --- a/cli/src/commands/upload/chunk_reader.rs +++ /dev/null @@ -1,106 +0,0 @@ -use droplet_rs::manifest::ChunkData; -use std::{ - cmp::min, - fs::File, - io::{Read, Seek, SeekFrom}, - path::Path, - task::Poll, - vec::IntoIter, -}; -use tokio::io::AsyncRead; - -pub struct ChunkReader { - files: IntoIter, - active: Option, -} - -pub struct LimitedFileReader { - file: File, - to_read_remaining: usize, -} - -impl Read for LimitedFileReader { - fn read(&mut self, buf: &mut [u8]) -> std::io::Result { - let to_read = min(self.to_read_remaining, buf.len()); - let (to_read, _remaining) = buf.split_at_mut(to_read); - let read = self.file.read(to_read)?; - self.to_read_remaining -= read; - Ok(read) - } -} - -impl ChunkReader { - pub fn new(path: impl AsRef, chunk: &ChunkData) -> Self { - let files = chunk - .files - .iter() - .map(|f| { - let mut file = File::open(path.as_ref().join(&f.filename)).unwrap(); - file.seek(SeekFrom::Start(f.start as u64)).unwrap(); // TODO: Fix unwraps - LimitedFileReader { - file, - to_read_remaining: f.length, - } - }) - .collect::>() - .into_iter(); - Self { - files, - active: None, - } - } -} -impl AsyncRead for ChunkReader { - fn poll_read( - self: std::pin::Pin<&mut Self>, - _cx: &mut std::task::Context<'_>, - buf: &mut tokio::io::ReadBuf<'_>, - ) -> std::task::Poll> { - let mut s = self; - loop { - if let Some(active) = &mut s.active { - match active.read(buf.initialize_unfilled()) { - Ok(0) => { - s.active = None; - continue; - } - Ok(n) => { - buf.advance(n); - - return Poll::Ready(Ok(())); - } - Err(e) => return Poll::Ready(Err(e)), - } - } else { - if let Some(next) = s.files.next() { - s.active = Some(next); - } else { - return Poll::Ready(Ok(())); - } - } - } - } -} - -// impl Read for ChunkReader { -// fn read(&mut self, buf: &mut [u8]) -> std::io::Result { -// loop { -// if let Some(active) = &mut self.active { -// match active.read(buf) { -// Ok(0) => { -// self.active = None; -// continue; -// } -// Ok(n) => return Ok(n), -// Err(e) => return Err(e), -// } -// } else { -// if let Some(next) = self.files.next() { -// self.active = Some(next); -// } else { -// return Ok(0); -// } -// } -// } -// } -// } diff --git a/cli/src/commands/upload/interface.rs b/cli/src/commands/upload/interface.rs index ca2c97ff..bb74fee9 100644 --- a/cli/src/commands/upload/interface.rs +++ b/cli/src/commands/upload/interface.rs @@ -1,18 +1,24 @@ -use std::path::Path; +use std::{io::SeekFrom, path::Path, pin::Pin}; use crate::{ cli::UploadInfo, - commands::{ - connect::{config::Config, config_option::ConfigOption}, - upload::chunk_reader::ChunkReader, - }, + commands::connect::{config::Config, config_option::ConfigOption}, manifest::{CompressionOption, DepotManifest, generate_v2_manifest}, operator_builder::OperatorBuilder, }; -use futures::AsyncWriteExt; +use droplet_rs::manifest::ChunkData; +use futures::{AsyncWriteExt, StreamExt, TryStreamExt, future::join_all, stream}; use log::info; use opendal::Operator; -use tokio_util::compat::FuturesAsyncWriteCompatExt; +use tokio::{ + fs::File, + io::{AsyncRead, AsyncReadExt, AsyncSeekExt, Take}, +}; +use tokio_util::{ + bytes::Bytes, + compat::FuturesAsyncWriteCompatExt, + io::{ReaderStream, StreamReader}, +}; pub async fn upload( info: &UploadInfo, @@ -33,7 +39,7 @@ pub async fn upload( for (id, data) in &v2_manifest.chunks { info!("Uploading chunk id {id}"); - let mut reader = ChunkReader::new(path, data); + let mut reader = generate_chunk_readstream(path, data).await; let mut writer = operator .writer(&format!("{game_id}/{version_id}/{id}")) .await? @@ -53,6 +59,32 @@ pub async fn upload( Ok(()) } +// Black magic don't touch +/// Connects all of the files at the correct start and end points into a single, continuous AsyncRead object +pub async fn generate_chunk_readstream<'a, P: AsRef + 'a>( + path: P, + data: &'a ChunkData, +) -> Pin> { + let path = path.as_ref().to_path_buf(); + let files = data.files.clone(); + + let stream = stream::iter(files) + .map(move |f| { + let path = path.clone(); + // Lazy block to ensure that not too many files get opened at once + async move { + let mut file = File::open(path.join(f.filename)).await?; + file.seek(SeekFrom::Start(f.start as u64)).await?; + tokio::io::Result::Ok(file.take(f.length as u64)) + } + }) + .buffered(2) // Could also be 1. Just removes a bit of latency from opening files buy preparing the next one immediately + .map_ok(|file| ReaderStream::new(file)) + .try_flatten(); + let reader = StreamReader::new(stream); + Box::pin(reader) +} + async fn get_depot_manifest(operator: &Operator) -> Result { let existing_depot_manifest = operator.read("manifest.json").await?.to_bytes(); let existing_depot_manifest: DepotManifest = diff --git a/cli/src/commands/upload/mod.rs b/cli/src/commands/upload/mod.rs index cdaa9e81..8d3d626b 100644 --- a/cli/src/commands/upload/mod.rs +++ b/cli/src/commands/upload/mod.rs @@ -1,2 +1 @@ -pub mod chunk_reader; pub mod interface; From 9077a30bee03a0ba0f19a5be775028ad3d83d03a Mon Sep 17 00:00:00 2001 From: quexeky Date: Thu, 29 Jan 2026 08:52:21 +1100 Subject: [PATCH 22/22] Use updated droplet-rs (currently only local installation of droplet supported) --- cli/Cargo.lock | 32 ++++++------ cli/Cargo.toml | 2 +- cli/src/commands/connect/config.rs | 5 +- cli/src/commands/upload/interface.rs | 73 ++++++++-------------------- cli/src/manifest.rs | 16 ++++-- 5 files changed, 55 insertions(+), 73 deletions(-) diff --git a/cli/Cargo.lock b/cli/Cargo.lock index 50755aba..c7e11ca1 100644 --- a/cli/Cargo.lock +++ b/cli/Cargo.lock @@ -442,9 +442,9 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" [[package]] name = "der-parser" @@ -578,7 +578,6 @@ dependencies = [ [[package]] name = "droplet-rs" version = "0.14.1" -source = "git+https://github.com/Drop-OSS/droplet-rs.git#f17a585b563d874ef9a09c27be5169b7e728d148" dependencies = [ "anyhow", "async-trait", @@ -1270,9 +1269,9 @@ checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" [[package]] name = "libm" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" @@ -1375,9 +1374,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" [[package]] name = "num-integer" @@ -2151,10 +2150,11 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.7" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] @@ -2305,30 +2305,30 @@ dependencies = [ [[package]] name = "time" -version = "0.3.44" +version = "0.3.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +checksum = "9da98b7d9b7dad93488a84b8248efc35352b0b2657397d4167e7ad67e5d535e5" dependencies = [ "deranged", "itoa", "num-conv", "powerfmt", - "serde", + "serde_core", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "time-macros" -version = "0.2.24" +version = "0.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" +checksum = "78cc610bac2dcee56805c99642447d4c5dbde4d01f752ffea0199aee1f601dc4" dependencies = [ "num-conv", "time-core", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index cdfbd0fa..e506a0d7 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -11,7 +11,7 @@ clap = { version = "4.5.54", features = ["derive"] } console = "0.16.2" dialoguer = "0.12.0" dirs = "6.0.0" -droplet-rs = { git = "https://github.com/Drop-OSS/droplet-rs.git", version = "0.14" } +droplet-rs = { path = "../droplet-rs", version = "0.14" } fern = { version = "0.7.1", features = ["colored"] } futures = "0.3.31" indicatif = "0.18.3" diff --git a/cli/src/commands/connect/config.rs b/cli/src/commands/connect/config.rs index 3a0f5ce8..549109d9 100644 --- a/cli/src/commands/connect/config.rs +++ b/cli/src/commands/connect/config.rs @@ -100,8 +100,9 @@ pub async fn manage_configuration( let operator = config_option.build()?; generate_manifest(&operator).await?; + info!("Finished uploading manifest"); generate_speedtest(&operator).await?; - + info!("Finished uploading speedtest"); Ok(()) } @@ -129,8 +130,10 @@ async fn generate_speedtest(operator: &Operator) -> anyhow::Result<()> { progress_bar.set_position(progress_int); }); let written = tokio::io::copy(&mut reader, &mut writer).await?; + progress_bar.finish(); debug!("Wrote {} bytes to {:?}", written, operator.info()); writer.into_inner().close().await?; + debug!("Closed writer"); Ok(()) } diff --git a/cli/src/commands/upload/interface.rs b/cli/src/commands/upload/interface.rs index bb74fee9..2a16e552 100644 --- a/cli/src/commands/upload/interface.rs +++ b/cli/src/commands/upload/interface.rs @@ -1,4 +1,4 @@ -use std::{io::SeekFrom, path::Path, pin::Pin}; +use std::path::Path; use crate::{ cli::UploadInfo, @@ -6,19 +6,10 @@ use crate::{ manifest::{CompressionOption, DepotManifest, generate_v2_manifest}, operator_builder::OperatorBuilder, }; -use droplet_rs::manifest::ChunkData; -use futures::{AsyncWriteExt, StreamExt, TryStreamExt, future::join_all, stream}; +use futures::AsyncWriteExt; use log::info; -use opendal::Operator; -use tokio::{ - fs::File, - io::{AsyncRead, AsyncReadExt, AsyncSeekExt, Take}, -}; -use tokio_util::{ - bytes::Bytes, - compat::FuturesAsyncWriteCompatExt, - io::{ReaderStream, StreamReader}, -}; +use opendal::{FuturesAsyncWriter, Operator}; +use tokio_util::compat::{Compat, FuturesAsyncWriteCompatExt}; pub async fn upload( info: &UploadInfo, @@ -33,21 +24,25 @@ pub async fn upload( let mut existing_depot_manifest = get_depot_manifest(&operator).await?; - let v2_manifest = generate_v2_manifest(Path::new(path)).await?; - info!("Uploading chunks"); - for (id, data) in &v2_manifest.chunks { - info!("Uploading chunk id {id}"); - let mut reader = generate_chunk_readstream(path, data).await; - let mut writer = operator - .writer(&format!("{game_id}/{version_id}/{id}")) - .await? - .into_futures_async_write() - .compat_write(); - tokio::io::copy(&mut reader, &mut writer).await?; - writer.into_inner().close().await?; - } + let v2_manifest = generate_v2_manifest( + Path::new(path), + async |id: String| { + info!("Uploading chunk id {id}"); + let writer = operator + .writer(&format!("{game_id}/{version_id}/{id}")) + .await + .unwrap() + .into_futures_async_write() + .compat_write(); + writer + }, + |writer: Compat| async { + writer.into_inner().close().await.unwrap(); + }, + ) + .await?; info!("Finished uploading chunks"); @@ -59,32 +54,6 @@ pub async fn upload( Ok(()) } -// Black magic don't touch -/// Connects all of the files at the correct start and end points into a single, continuous AsyncRead object -pub async fn generate_chunk_readstream<'a, P: AsRef + 'a>( - path: P, - data: &'a ChunkData, -) -> Pin> { - let path = path.as_ref().to_path_buf(); - let files = data.files.clone(); - - let stream = stream::iter(files) - .map(move |f| { - let path = path.clone(); - // Lazy block to ensure that not too many files get opened at once - async move { - let mut file = File::open(path.join(f.filename)).await?; - file.seek(SeekFrom::Start(f.start as u64)).await?; - tokio::io::Result::Ok(file.take(f.length as u64)) - } - }) - .buffered(2) // Could also be 1. Just removes a bit of latency from opening files buy preparing the next one immediately - .map_ok(|file| ReaderStream::new(file)) - .try_flatten(); - let reader = StreamReader::new(stream); - Box::pin(reader) -} - async fn get_depot_manifest(operator: &Operator) -> Result { let existing_depot_manifest = operator.read("manifest.json").await?.to_bytes(); let existing_depot_manifest: DepotManifest = diff --git a/cli/src/manifest.rs b/cli/src/manifest.rs index fe766f15..b84884c2 100644 --- a/cli/src/manifest.rs +++ b/cli/src/manifest.rs @@ -1,9 +1,12 @@ use std::{collections::HashMap, path::Path}; -use droplet_rs::manifest::{Manifest, generate_manifest_rusty}; +use droplet_rs::manifest::{ + Manifest, generate_manifest_rusty, generate_manifest_rusty_v2, +}; use indicatif::{ProgressBar, ProgressStyle}; use log::info; use serde::{Deserialize, Serialize}; +use tokio::io::AsyncWrite; #[derive(Serialize, Deserialize)] pub struct DepotManifest { @@ -37,20 +40,27 @@ impl DepotManifest { } } -pub async fn generate_v2_manifest(dir: &Path) -> anyhow::Result { +pub async fn generate_v2_manifest(dir: &Path, factory: F, closer: CloseF) -> anyhow::Result +where + W: AsyncWrite + Unpin, + F: AsyncFn(String) -> W, + CloseF: AsyncFn(W) +{ let progress_bar = ProgressBar::new(10_000).with_style( ProgressStyle::default_bar() .template("[{elapsed_precise}] [ETA {eta}] {bar} {percent_precise}%") .unwrap(), ); - generate_manifest_rusty( + generate_manifest_rusty_v2( dir, |progress| { let progress_int = (progress * 100f32).round() as u64; progress_bar.set_position(progress_int); }, |log| progress_bar.suspend(|| info!("{}", log)), + factory, + closer ) .await }