diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 00000000..624d2724 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[target.x86_64-unknown-linux-gnu] +rustflags = ["-Clink-arg=-fuse-ld=lld"] diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index ae177cb9..4c7afb30 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -21,6 +21,7 @@ runs: run: | sudo apt update sudo apt install -y \ + lld \ libdbus-1-dev \ libwayland-dev \ libwebkit2gtk-4.1-dev \ diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b85c3f80..4db6750a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,6 +7,7 @@ on: push: branches: - main + tags: [ 'v*', '*' ] jobs: build-rustfs: @@ -15,9 +16,9 @@ jobs: strategy: matrix: variant: - - { profile: dev, target: x86_64-unknown-linux-gnu, glibc: "default" } - - { profile: release, target: x86_64-unknown-linux-gnu, glibc: "default" } - - { profile: release, target: x86_64-unknown-linux-gnu, glibc: "2.31" } + - { profile: dev, target: x86_64-unknown-linux-gnu, glibc: "default" } + - { profile: release, target: x86_64-unknown-linux-gnu, glibc: "default" } + - { profile: release, target: x86_64-unknown-linux-gnu, glibc: "2.31" } steps: - uses: actions/checkout@v4 @@ -25,6 +26,15 @@ jobs: with: cache-shared-key: rustfs.${{ matrix.variant.profile }}.${{ matrix.variant.target }}.${{ matrix.variant.glibc }} + - name: Download and Extract Static Assets + run: | + url="https://dl.rustfs.com/console/rustfs-console-latest.zip" + mkdir -p static + curl -L -o static_assets.zip "$url" + unzip -o static_assets.zip -d ./rustfs/static + rm static_assets.zip + ls -la ./rustfs/static + - name: Build run: | ./scripts/build.py \ @@ -32,16 +42,130 @@ jobs: --target ${{ matrix.variant.target }} \ --glibc ${{ matrix.variant.glibc }} + - name: Package Binary and Static Assets + id: package + run: | + # Create artifact filename + ARTIFACT_NAME="rustfs-${{ matrix.variant.profile }}-${{ matrix.variant.target }}" + if [ "${{ matrix.variant.glibc }}" != "default" ]; then + ARTIFACT_NAME="${ARTIFACT_NAME}-glibc${{ matrix.variant.glibc }}" + fi + echo "artifact_name=${ARTIFACT_NAME}" >> $GITHUB_OUTPUT + + # Determine binary path + bin_path="target/artifacts/rustfs.${{ matrix.variant.profile }}.${{ matrix.variant.target }}.bin" + if [ -f "target/artifacts/rustfs.${{ matrix.variant.profile }}.${{ matrix.variant.target }}.glibc${{ matrix.variant.glibc }}.bin" ]; then + bin_path="target/artifacts/rustfs.${{ matrix.variant.profile }}.${{ matrix.variant.target }}.glibc${{ matrix.variant.glibc }}.bin" + fi + + # Create package + mkdir -p ${ARTIFACT_NAME} + cp "$bin_path" ${ARTIFACT_NAME}/rustfs + zip -r ${ARTIFACT_NAME}.zip ${ARTIFACT_NAME} + ls -la + - uses: actions/upload-artifact@v4 with: - name: rustfs.${{ matrix.variant.profile }}.${{ matrix.variant.target }}.${{ matrix.variant.glibc }} - path: ./target/artifacts/* + name: ${{ steps.package.outputs.artifact_name }} + path: ${{ steps.package.outputs.artifact_name }}.zip + retention-days: 7 + + build-rustfs-gui: + runs-on: ubuntu-latest + needs: build-rustfs + + strategy: + matrix: + variant: + - { profile: release, target: x86_64-unknown-linux-gnu } + # - { profile: release, target: x86_64-apple-darwin } + if: startsWith(github.ref, 'refs/tags/') + steps: + - uses: actions/checkout@v4 + - name: Download artifact + uses: actions/download-artifact@v4 + with: + name: "rustfs-${{ matrix.variant.profile }}-${{ matrix.variant.target }}" + - name: Display structure of downloaded files + run: | + ls -R + unzip -o -j "rustfs-${{ matrix.variant.profile }}-${{ matrix.variant.target }}.zip" -d ./cli/rustfs-gui/embedded-rustfs/ + ls -la cli/rustfs-gui/embedded-rustfs + - name: Cache dioxus-cli + uses: actions/cache@v4 + with: + path: ~/.cargo/bin/dx + key: ${{ runner.os }}-dioxus-cli-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-dioxus-cli- + + - name: Install dioxus-cli + run: | + if [ ! -f ~/.cargo/bin/dx ]; then + cargo install dioxus-cli + fi + + - name: Build and Bundle rustfs-gui + run: | + ls -la + + release_path="target/${{ matrix.variant.target }}" + mkdir -p ${release_path} + cd cli/rustfs-gui + ls -la embedded-rustfs + + # Configure the linker based on the target + case "${{ matrix.target }}" in + "x86_64-unknown-linux-gnu") + # Default gcc + export CC_x86_64_unknown_linux_gnu=gcc + export CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=gcc + ;; + "aarch64-unknown-linux-gnu") + # AArch64 Cross-compiler + export CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc + export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc + ;; + "x86_64-apple-darwin") + # macOS default clang + export CC_x86_64_apple_darwin=clang + export CARGO_TARGET_X86_64_APPLE_DARWIN_LINKER=clang + ;; + "aarch64-apple-darwin") + # macOS ARM64 used clang + export CC_aarch64_apple_darwin=clang + export CARGO_TARGET_AARCH64_APPLE_DARWIN_LINKER=clang + ;; + esac + # Validating Environment Variables (for Debugging) + echo "CC for ${{ matrix.target }}: $CC_${{ matrix.target }}" + echo "Linker for ${{ matrix.target }}: $CARGO_TARGET_${{ matrix.target }}_LINKER" + + if [[ "${{ matrix.variant.target }}" == *"apple-darwin"* ]]; then + dx bundle --platform macos --package-types "macos" --package-types "dmg" --package-types "ios" --release --profile release --out-dir ../../${release_path} + elif [[ "${{ matrix.variant.target }}" == *"windows-msvc"* ]]; then + dx bundle --platform windows --package-types "msi" --release --profile release --out-dir ../../${release_path} + elif [[ "${{ matrix.variant.target }}" == *"unknown-linux-gnu"* ]]; then + dx bundle --platform linux --package-types "deb" --package-types "rpm" --package-types "appimage" --release --profile release --out-dir ../../${release_path} + fi + cd ../.. + GUI_ARTIFACT_NAME="rustfs-gui-${{ matrix.variant.profile }}-${{ matrix.variant.target }}" + zip -r ${GUI_ARTIFACT_NAME}.zip ${release_path}/* + echo "gui_artifact_name=${GUI_ARTIFACT_NAME}" >> $GITHUB_OUTPUT + ls -la ${release_path} + + - uses: actions/upload-artifact@v4 + with: + name: ${{ steps.package.outputs.gui_artifact_name }} + path: ${{ steps.package.outputs.gui_artifact_name }}.zip + retention-days: 7 merge: runs-on: ubuntu-latest - needs: build-rustfs + needs: [ build-rustfs, build-rustfs-gui ] steps: - uses: actions/upload-artifact/merge@v4 with: - name: rustfs + name: rustfs-packages + pattern: 'rustfs-*' delete-merged: true diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 09c54587..783f20ff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,13 +37,6 @@ jobs: steps: - uses: actions/checkout@v4 - uses: ./.github/actions/setup - with: - cache-shared-key: "develop" - - - name: Install s3s-e2e - run: | - cargo install s3s-e2e --git https://github.com/Nugine/s3s.git - s3s-e2e --version - name: Format run: cargo fmt --all --check @@ -52,41 +45,24 @@ jobs: run: cargo check --all-targets # TODO: cargo clippy + - name: Test + run: cargo test --all --exclude e2e_test + - name: Build debug run: | touch rustfs/build.rs cargo build -p rustfs --bins - - # - name: Build release - # run: | - # touch rustfs/build.rs - # cargo build -p rustfs --bins --release - - run: | + - name: Pack artifacts + run: | mkdir -p ./target/artifacts cp target/debug/rustfs ./target/artifacts/rustfs-debug - # cp target/release/rustfs ./target/artifacts/rustfs-release - uses: actions/upload-artifact@v4 with: name: rustfs path: ./target/artifacts/* - test: - name: Test - needs: - - skip-check - - develop - if: needs.skip-check.outputs.should_skip != 'true' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: ./.github/actions/setup - with: - cache-shared-key: "develop" - cache-save-if: "false" - - run: cargo test --all --exclude e2e_test - s3s-e2e: name: E2E (s3s-e2e) needs: @@ -96,10 +72,11 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: ./.github/actions/setup + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 with: - cache-shared-key: "develop" - cache-save-if: false + cache-on-failure: true + cache-all-crates: true - name: Install s3s-e2e run: | @@ -111,65 +88,12 @@ jobs: name: rustfs path: ./target/artifacts - - name: Run rustfs - run: | - ./scripts/e2e-run.sh ./target/artifacts/rustfs-debug /data/rustfs - sleep 10 - - name: Run s3s-e2e timeout-minutes: 10 run: | - export AWS_ACCESS_KEY_ID=rustfsadmin - export AWS_SECRET_ACCESS_KEY=rustfsadmin - export AWS_REGION=us-east-1 - export AWS_ENDPOINT_URL=http://localhost:9000 - export RUST_LOG="s3s_e2e=debug,s3s_test=info,s3s=debug" - export RUST_BACKTRACE=full - s3s-e2e - sudo killall rustfs-debug + ./scripts/e2e-run.sh ./target/artifacts/rustfs-debug /tmp/rustfs - uses: actions/upload-artifact@v4 with: name: s3s-e2e.logs path: /tmp/rustfs.log - - # mint: - # name: E2E (mint) - # needs: - # - skip-check - # - develop - # if: needs.skip-check.outputs.should_skip != 'true' - # runs-on: ubuntu-latest - # steps: - # - uses: actions/checkout@v4 - # - uses: ./.github/actions/setup - # with: - # cache-shared-key: "develop" - # cache-save-if: false - - # - uses: actions/download-artifact@v4 - # with: - # name: rustfs - # path: ./target/artifacts - - # - name: Run rustfs - # run: | - # ./scripts/e2e-run.sh ./target/artifacts/rustfs-release /data/rustfs - # sleep 10 - - # - name: Run mint - # timeout-minutes: 10 - # run: | - # docker run \ - # -e "SERVER_ENDPOINT=localhost:9000" \ - # -e "ACCESS_KEY=rustfsadmin" \ - # -e "SECRET_KEY=rustfsadmin" \ - # -e "ENABLE_HTTPS=0" \ - # --network host \ - # minio/mint:edge - # sudo killall rustfs-release - - # - uses: actions/upload-artifact@v4 - # with: - # name: mint.logs - # path: /tmp/rustfs.log diff --git a/.gitignore b/.gitignore index 81d415f6..45147d58 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ /logs .devcontainer rustfs/static/* +vendor +cli/rustfs-gui/embedded-rustfs/rustfs \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index d15b1ba1..a99f98d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -158,15 +158,6 @@ version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b964d184e89d9b6b67dd2715bc8e74cf3107fb2b529990c90cf517326150bf4" -[[package]] -name = "arbitrary" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" -dependencies = [ - "derive_arbitrary", -] - [[package]] name = "arc-swap" version = "1.7.1" @@ -525,9 +516,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" dependencies = [ "serde", ] @@ -629,34 +620,13 @@ dependencies = [ "bytes", ] -[[package]] -name = "bzip2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" -dependencies = [ - "bzip2-sys", - "libc", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.12+1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ebc2f1a417f01e1da30ef264ee86ae31d2dcd2d603ea283d3c244a883ca2a9" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - [[package]] name = "cairo-rs" version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "cairo-sys-rs", "glib", "libc", @@ -677,12 +647,10 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.15" +version = "1.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c736e259eea577f443d5c86c304f9f4ae0295c43f3ba05c21f1d66b5f06001af" +checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" dependencies = [ - "jobserver", - "libc", "shlex", ] @@ -751,9 +719,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.39" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" +checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" dependencies = [ "android-tzdata", "iana-time-zone", @@ -761,7 +729,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -804,9 +772,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.30" +version = "4.5.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92b7b18d71fad5313a1e320fa9897994228ce274b60faa4d694fe0ea89cd9e6d" +checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767" dependencies = [ "clap_builder", "clap_derive", @@ -814,9 +782,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.30" +version = "4.5.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a35db2071778a7344791a4fb4f95308b5673d219dee3ae348b86642574ecc90c" +checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863" dependencies = [ "anstream", "anstyle", @@ -864,7 +832,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f79398230a6e2c08f5c9760610eb6924b52aa9e7950a619602baba59dcbbdbb2" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "block", "cocoa-foundation 0.2.0", "core-foundation 0.10.0", @@ -894,7 +862,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e14045fb83be07b5acf1c0884b2180461635b433455fa35d1cd6f17f1450679d" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "block", "core-foundation 0.10.0", "core-graphics-types 0.2.0", @@ -951,9 +919,9 @@ dependencies = [ [[package]] name = "const-oid" -version = "0.10.0-rc.3" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ff6be19477a1bd5441f382916a89bc2a0b2c35db6d41e0f6e8538bf6d6463f" +checksum = "1cb3c4a0d3776f7535c32793be81d6d5fec0d48ac70955d9834e643aa249a52f" [[package]] name = "const-serialize" @@ -1016,12 +984,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "constant_time_eq" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" - [[package]] name = "convert_case" version = "0.4.0" @@ -1082,7 +1044,7 @@ version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "core-foundation 0.10.0", "core-graphics-types 0.2.0", "foreign-types", @@ -1106,7 +1068,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "core-foundation 0.10.0", "libc", ] @@ -1120,21 +1082,6 @@ dependencies = [ "libc", ] -[[package]] -name = "crc" -version = "3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" -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 = "crc32c" version = "0.6.8" @@ -1327,12 +1274,6 @@ dependencies = [ "rand 0.8.5", ] -[[package]] -name = "deflate64" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b" - [[package]] name = "deranged" version = "0.3.11" @@ -1343,17 +1284,6 @@ dependencies = [ "serde", ] -[[package]] -name = "derive_arbitrary" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.98", -] - [[package]] name = "derive_more" version = "0.99.19" @@ -1447,7 +1377,7 @@ dependencies = [ "futures-util", "generational-box", "longest-increasing-subsequence", - "rustc-hash 1.1.0", + "rustc-hash", "rustversion", "serde", "slab", @@ -1513,7 +1443,7 @@ dependencies = [ "objc_id", "once_cell", "rfd 0.14.1", - "rustc-hash 1.1.0", + "rustc-hash", "serde", "serde_json", "signal-hook", @@ -1674,7 +1604,7 @@ dependencies = [ "dioxus-html", "js-sys", "lazy-js-bundle", - "rustc-hash 1.1.0", + "rustc-hash", "serde", "sledgehammer_bindgen", "sledgehammer_utils", @@ -1780,7 +1710,7 @@ dependencies = [ "generational-box", "once_cell", "parking_lot 0.12.3", - "rustc-hash 1.1.0", + "rustc-hash", "tracing", "warnings", ] @@ -1807,7 +1737,7 @@ dependencies = [ "generational-box", "js-sys", "lazy-js-bundle", - "rustc-hash 1.1.0", + "rustc-hash", "serde", "serde-wasm-bindgen", "serde_json", @@ -2037,18 +1967,9 @@ dependencies = [ [[package]] name = "either" -version = "1.13.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" - -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] +checksum = "b7914353092ddf589ad78f25c5c1c21b7f80b0ff8621e7c814c3485b5306da9d" [[package]] name = "endi" @@ -2188,9 +2109,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.35" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" +checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc" dependencies = [ "crc32fast", "miniz_oxide", @@ -2568,7 +2489,7 @@ version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "futures-channel", "futures-core", "futures-executor", @@ -2621,7 +2542,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b436093d1598b05e3b7fddc097b2bad32763f53a1beb25ab6f9718c6a60acd09" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "cocoa 0.25.0", "crossbeam-channel", "keyboard-types", @@ -2960,24 +2881,6 @@ dependencies = [ "want", ] -[[package]] -name = "hyper-rustls" -version = "0.27.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" -dependencies = [ - "futures-util", - "http", - "hyper", - "hyper-util", - "rustls", - "rustls-pki-types", - "tokio", - "tokio-rustls", - "tower-service", - "webpki-roots", -] - [[package]] name = "hyper-timeout" version = "0.5.2" @@ -3347,15 +3250,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" -[[package]] -name = "jobserver" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" -dependencies = [ - "libc", -] - [[package]] name = "js-sys" version = "0.3.77" @@ -3387,16 +3281,16 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "serde", "unicode-segmentation", ] [[package]] name = "keyring" -version = "3.6.1" +version = "3.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f8fe839464d4e4b37d756d7e910063696af79a7e877282cb1825e4ec5f10833" +checksum = "1961983669d57bdfe6c0f3ef8e4c229b5ef751afcc7d87e4271d2f71f6ccfa8b" dependencies = [ "byteorder", "dbus-secret-service", @@ -3457,9 +3351,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.169" +version = "0.2.170" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" [[package]] name = "libdbus-sys" @@ -3502,7 +3396,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "libc", ] @@ -3545,9 +3439,21 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "litemap" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" +checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" + +[[package]] +name = "local-ip-address" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3669cf5561f8d27e8fc84cc15e58350e70f557d4d65f70e3154e54cd2f8e1782" +dependencies = [ + "libc", + "neli", + "thiserror 1.0.69", + "windows-sys 0.59.0", +] [[package]] name = "lock" @@ -3579,12 +3485,6 @@ dependencies = [ "scopeguard", ] -[[package]] -name = "lockfree-object-pool" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" - [[package]] name = "log" version = "0.4.26" @@ -3606,16 +3506,6 @@ dependencies = [ "hashbrown 0.12.3", ] -[[package]] -name = "lzma-rs" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e" -dependencies = [ - "byteorder", - "crc", -] - [[package]] name = "mac" version = "0.1.1" @@ -3840,7 +3730,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "jni-sys", "log", "ndk-sys", @@ -3864,6 +3754,31 @@ dependencies = [ "jni-sys", ] +[[package]] +name = "neli" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93062a0dce6da2517ea35f301dfc88184ce18d3601ec786a727a87bf535deca9" +dependencies = [ + "byteorder", + "libc", + "log", + "neli-proc-macros", +] + +[[package]] +name = "neli-proc-macros" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c8034b7fbb6f9455b2a96c19e6edf8dc9fc34c70449938d8ee3b4df363f61fe" +dependencies = [ + "either", + "proc-macro2", + "quote", + "serde", + "syn 1.0.109", +] + [[package]] name = "netif" version = "0.1.6" @@ -3886,7 +3801,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "cfg-if", "cfg_aliases", "libc", @@ -4105,7 +4020,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "block2 0.5.1", "libc", "objc2 0.5.2", @@ -4121,7 +4036,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5906f93257178e2f7ae069efb89fbd6ee94f0592740b5f8a1512ca498814d0fb" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "objc2 0.6.0", "objc2-core-foundation", "objc2-foundation 0.3.0", @@ -4133,7 +4048,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -4145,7 +4060,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daeaf60f25471d26948a1c2f840e3f7d86f4109e3af4e8e4b5cd70c39690d925" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "objc2 0.6.0", ] @@ -4155,7 +4070,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dca602628b65356b6513290a21a6405b4d4027b8b250f0b98dddbb28b7de02" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "objc2-core-foundation", ] @@ -4183,7 +4098,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "block2 0.5.1", "dispatch", "libc", @@ -4196,7 +4111,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a21c6c9014b82c39515db5b396f91645182611c97d24637cf56ac01e5f8d998" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "block2 0.6.0", "objc2 0.6.0", "objc2-core-foundation", @@ -4208,7 +4123,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -4220,7 +4135,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -4997,58 +4912,6 @@ dependencies = [ "serde", ] -[[package]] -name = "quinn" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" -dependencies = [ - "bytes", - "pin-project-lite", - "quinn-proto", - "quinn-udp", - "rustc-hash 2.1.1", - "rustls", - "socket2", - "thiserror 2.0.11", - "tokio", - "tracing", -] - -[[package]] -name = "quinn-proto" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" -dependencies = [ - "bytes", - "getrandom 0.2.15", - "rand 0.8.5", - "ring", - "rustc-hash 2.1.1", - "rustls", - "rustls-pki-types", - "slab", - "thiserror 2.0.11", - "tinyvec", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-udp" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e46f3055866785f6b92bc6164b76be02ca8f2eb4b002c0354b28cf4c119e5944" -dependencies = [ - "cfg_aliases", - "libc", - "once_cell", - "socket2", - "tracing", - "windows-sys 0.59.0", -] - [[package]] name = "quote" version = "1.0.38" @@ -5090,8 +4953,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.1", - "zerocopy 0.8.20", + "rand_core 0.9.3", + "zerocopy 0.8.21", ] [[package]] @@ -5121,7 +4984,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.1", + "rand_core 0.9.3", ] [[package]] @@ -5144,12 +5007,11 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.9.1" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a88e0da7a2c97baa202165137c158d0a2e824ac465d13d81046727b34cb247d3" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ "getrandom 0.3.1", - "zerocopy 0.8.20", ] [[package]] @@ -5243,7 +5105,7 @@ version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82b568323e98e49e2a0899dcee453dd679fae22d69adf9b11dd508d1549b7e2f" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", ] [[package]] @@ -5335,16 +5197,19 @@ checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" dependencies = [ "base64", "bytes", +<<<<<<< HEAD "encoding_rs", "futures-channel", +||||||| e65bee0 + "encoding_rs", +======= +>>>>>>> 1d58a07f296b9dedba832bb31b31eb9faf38b85c "futures-core", "futures-util", - "h2", "http", "http-body", "http-body-util", "hyper", - "hyper-rustls", "hyper-util", "ipnet", "js-sys", @@ -5354,17 +5219,11 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "quinn", - "rustls", - "rustls-pemfile", - "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", - "system-configuration", "tokio", - "tokio-rustls", "tokio-util", "tower 0.5.2", "tower-service", @@ -5373,7 +5232,6 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots", "windows-registry", ] @@ -5426,9 +5284,9 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.10" +version = "0.17.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34b5020fcdea098ef7d95e9f89ec15952123a4a039badd09fabebe9e963e839" +checksum = "da5349ae27d3887ca812fb375b45a4fbb36d8d12d2df394968cd86e35683fe73" dependencies = [ "cc", "cfg-if", @@ -5462,9 +5320,9 @@ dependencies = [ [[package]] name = "rust-embed" -version = "8.5.0" +version = "8.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa66af4a4fdd5e7ebc276f115e895611a34739a9c1c01028383d612d550953c0" +checksum = "0b3aba5104622db5c9fc61098de54708feb732e7763d7faa2fa625899f00bf6f" dependencies = [ "rust-embed-impl", "rust-embed-utils", @@ -5473,9 +5331,9 @@ dependencies = [ [[package]] name = "rust-embed-impl" -version = "8.5.0" +version = "8.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6125dbc8867951125eec87294137f4e9c2c96566e61bf72c45095a7c77761478" +checksum = "1f198c73be048d2c5aa8e12f7960ad08443e56fd39cc26336719fdb4ea0ebaae" dependencies = [ "proc-macro2", "quote", @@ -5487,9 +5345,9 @@ dependencies = [ [[package]] name = "rust-embed-utils" -version = "8.5.0" +version = "8.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e5347777e9aacb56039b0e1f28785929a8a3b709e87482e7442c72e7c12529d" +checksum = "5a2fcdc9f40c8dc2922842ca9add611ad19f332227fc651d015881ad1552bd9a" dependencies = [ "sha2 0.10.8", "walkdir", @@ -5507,12 +5365,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" -[[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" @@ -5531,6 +5383,7 @@ dependencies = [ "atoi", "axum", "bytes", + "chrono", "clap", "common", "const-str", @@ -5547,6 +5400,7 @@ dependencies = [ "iam", "jsonwebtoken", "lazy_static", + "local-ip-address", "lock", "log", "madmin", @@ -5592,15 +5446,17 @@ dependencies = [ "dioxus", "dirs 6.0.0", "futures-util", + "hex", "keyring", - "reqwest", + "lazy_static", "rfd 0.15.2", + "rust-embed", "serde", "serde_json", + "sha2 0.10.8", "tokio", "tracing-appender", "tracing-subscriber", - "zip", ] [[package]] @@ -5630,7 +5486,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "errno", "libc", "linux-raw-sys", @@ -5666,9 +5522,6 @@ name = "rustls-pki-types" version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" -dependencies = [ - "web-time", -] [[package]] name = "rustls-webpki" @@ -5778,7 +5631,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "core-foundation 0.9.4", "core-foundation-sys", "libc", @@ -5791,7 +5644,7 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "core-foundation 0.10.0", "core-foundation-sys", "libc", @@ -6171,7 +6024,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "debdd4b83524961983cea3c55383b3910fd2f24fd13a188f5b091d2d504a61ae" dependencies = [ - "rustc-hash 1.1.0", + "rustc-hash", ] [[package]] @@ -6287,18 +6140,18 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" -version = "0.26.3" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" -version = "0.26.4" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -6355,27 +6208,6 @@ dependencies = [ "syn 2.0.98", ] -[[package]] -name = "system-configuration" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" -dependencies = [ - "bitflags 2.8.0", - "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 = "system-deps" version = "6.2.2" @@ -6395,7 +6227,7 @@ version = "0.30.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6682a07cf5bab0b8a2bd20d0a542917ab928b5edb75ebd4eda6b05cbaab872da" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "cocoa 0.26.0", "core-foundation 0.10.0", "core-graphics 0.24.0", @@ -6603,21 +6435,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "tinyvec" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" -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.43.0" @@ -6650,9 +6467,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" dependencies = [ "rustls", "tokio", @@ -6841,7 +6658,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "403fa3b783d4b626a8ad51d766ab03cb6d2dbfc46b1c5d4448395e6628dc9697" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "bytes", "http", "pin-project-lite", @@ -7143,9 +6960,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.14.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d59ca99a559661b96bf898d8fce28ed87935fd2bea9f05983c1464dd6c71b1" +checksum = "e0f540e3240398cce6128b64ba83fdbdd86129c16a3aa1a3a252efd66eb3d587" dependencies = [ "getrandom 0.3.1", "rand 0.9.0", @@ -7155,9 +6972,9 @@ dependencies = [ [[package]] name = "uuid-macro-internal" -version = "1.14.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1be57878a5f7e409a1a82be6691922b11e59687a168205b1f21b087c4acdd194" +checksum = "9521621447c21497fac206ffe6e9f642f977c4f82eeba9201055f64884d9cb01" dependencies = [ "proc-macro2", "quote", @@ -7360,7 +7177,7 @@ version = "0.31.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2120de3d33638aaef5b9f4472bff75f07c56379cf76ea320bd3a3d65ecaf73f" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "rustix", "wayland-backend", "wayland-scanner", @@ -7372,7 +7189,7 @@ version = "0.32.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0781cf46869b37e36928f7b432273c0995aa8aed9552c556fb18754420541efc" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "wayland-backend", "wayland-client", "wayland-scanner", @@ -7410,16 +7227,6 @@ dependencies = [ "wasm-bindgen", ] -[[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 = "webbrowser" version = "0.8.15" @@ -7481,15 +7288,6 @@ dependencies = [ "system-deps", ] -[[package]] -name = "webpki-roots" -version = "0.26.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9" -dependencies = [ - "rustls-pki-types", -] - [[package]] name = "webview2-com" version = "0.33.0" @@ -7894,7 +7692,7 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", ] [[package]] @@ -8145,11 +7943,11 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde3bb8c68a8f3f1ed4ac9221aad6b10cece3e60a8e2ea54a6a2dec806d0084c" +checksum = "dcf01143b2dd5d134f11f545cf9f1431b13b749695cb33bcce051e7568f99478" dependencies = [ - "zerocopy-derive 0.8.20", + "zerocopy-derive 0.8.21", ] [[package]] @@ -8165,9 +7963,9 @@ dependencies = [ [[package]] name = "zerocopy-derive" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eea57037071898bf96a6da35fd626f4f27e9cee3ead2a6c703cf09d472b2e700" +checksum = "712c8386f4f4299382c9abee219bee7084f78fb939d88b6840fcc1320d5f6da2" dependencies = [ "proc-macro2", "quote", @@ -8176,18 +7974,18 @@ dependencies = [ [[package]] name = "zerofrom" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", @@ -8200,20 +7998,6 @@ name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.98", -] [[package]] name = "zerovec" @@ -8237,77 +8021,6 @@ dependencies = [ "syn 2.0.98", ] -[[package]] -name = "zip" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae9c1ea7b3a5e1f4b922ff856a129881167511563dc219869afe3787fc0c1a45" -dependencies = [ - "aes", - "arbitrary", - "bzip2", - "constant_time_eq", - "crc32fast", - "crossbeam-utils", - "deflate64", - "displaydoc", - "flate2", - "hmac 0.12.1", - "indexmap 2.7.1", - "lzma-rs", - "memchr", - "pbkdf2", - "rand 0.8.5", - "sha1 0.10.6", - "thiserror 2.0.11", - "time", - "zeroize", - "zopfli", - "zstd", -] - -[[package]] -name = "zopfli" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946" -dependencies = [ - "bumpalo", - "crc32fast", - "lockfree-object-pool", - "log", - "once_cell", - "simd-adler32", -] - -[[package]] -name = "zstd" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "7.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3051792fbdc2e1e143244dc28c60f73d8470e93f3f9cbd0ead44da5ed802722" -dependencies = [ - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.14+zstd.1.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fb060d4926e4ac3a3ad15d864e99ceb5f343c6b34f5bd6d81ae6ed417311be5" -dependencies = [ - "cc", - "pkg-config", -] - [[package]] name = "zvariant" version = "4.2.0" diff --git a/Cargo.toml b/Cargo.toml index 5bdc462a..6915a975 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,19 +1,19 @@ [workspace] members = [ - "madmin", - "rustfs", - "ecstore", - "e2e_test", - "common/common", - "common/lock", - "common/protos", - "api/admin", - "reader", - "common/workers", - "iam", - "crypto", - "cli/rustfs-gui", - "packages/logging", + "madmin", # Management dashboard and admin API interface + "rustfs", # Core file system implementation + "ecstore", # Erasure coding storage implementation + "e2e_test", # End-to-end test suite + "common/common", # Shared utilities and data structures + "common/lock", # Distributed locking implementation + "common/protos", # Protocol buffer definitions + "api/admin", # Admin HTTP API endpoints + "reader", # Object reading service + "common/workers", # Worker thread pools and task scheduling + "iam", # Identity and Access Management + "crypto", # Cryptography and security features + "cli/rustfs-gui", # Graphical user interface client + "packages/logging", # Logging utilities ] resolver = "2" @@ -36,8 +36,8 @@ async-trait = "0.1.86" backon = "1.3.0" bytes = "1.9.0" bytesize = "1.3.0" -chrono = { version = "0.4.39", features = ["serde"] } -clap = { version = "4.5.27", features = ["derive", "env"] } +chrono = { version = "0.4.40", features = ["serde"] } +clap = { version = "4.5.31", features = ["derive", "env"] } dioxus = { version = "0.6.3", features = ["router"] } dirs = "6.0.0" ecstore = { path = "./ecstore" } @@ -46,6 +46,7 @@ futures = "0.3.31" futures-util = "0.3.31" common = { path = "./common/common" } reader = { path = "./reader" } +hex = "0.4.3" hyper = "1.6.0" hyper-util = { version = "0.1.10", features = [ "tokio", @@ -58,6 +59,7 @@ humantime = "2.1.0" keyring = { version = "3.6.1", features = ["apple-native", "windows-native", "sync-secret-service"] } lock = { path = "./common/lock" } lazy_static = "1.5.0" +local-ip-address = "0.6.3" mime = "0.3.17" netif = "0.1.6" opentelemetry = { version = "0.28" } @@ -80,6 +82,7 @@ rfd = { version = "0.15.2", default-features = false, features = ["xdg-portal", rmp = "0.8.14" rmp-serde = "1.3.0" rustfs-logging = { path = "packages/logging", version = "0.0.1" } +rust-embed = "8.6.0" s3s = { git = "https://github.com/Nugine/s3s.git", rev = "ab139f72fe768fb9d8cecfe36269451da1ca9779", default-features = true, features = [ "tower", ] } @@ -87,6 +90,7 @@ s3s-policy = { git = "https://github.com/Nugine/s3s.git", rev = "ab139f72fe768fb shadow-rs = { version = "0.38.0", default-features = false } serde = { version = "1.0.217", features = ["derive"] } serde_json = "1.0.138" +sha2 = "0.10.8" tempfile = "3.16.0" thiserror = "2.0.11" time = { version = "0.3.37", features = [ @@ -109,7 +113,7 @@ tracing-appender = "0.2.3" tracing-opentelemetry = "0.29" transform-stream = "0.3.1" url = "2.5.4" -uuid = { version = "1.12.1", features = [ +uuid = { version = "1.15.1", features = [ "v4", "fast-rng", "macro-diagnostics", @@ -119,10 +123,7 @@ axum = "0.7.9" md-5 = "0.10.6" workers = { path = "./common/workers" } test-case = "3.3.1" -zip = "2.2.2" - - -[profile] +zip = "2.2.3" [profile.wasm-dev] inherits = "dev" @@ -137,4 +138,4 @@ inherits = "dev" [profile.release] opt-level = 3 # Optimization Level (0-3) lto = true # Optimize when linking -codegen-units = 1 # Reduce code generation units to improve optimization \ No newline at end of file +codegen-units = 1 # Reduce code generation units to improve optimization diff --git a/README.md b/README.md index 3bfa6b7a..1e4f16b5 100644 --- a/README.md +++ b/README.md @@ -1 +1,50 @@ -# s3-rustfs \ No newline at end of file +# How to compile RustFS + +| Must package | Version | +|--------------|---------| +| Rust | 1.8.5 | +| protoc | 27.0 | +| flatc | 24.0+ | + +Download Links: + +https://github.com/google/flatbuffers/releases/download/v24.3.25/Linux.flatc.binary.g++-13.zip + +https://github.com/protocolbuffers/protobuf/releases/download/v27.0/protoc-27.0-linux-x86_64.zip + +Or use Docker: + +- uses: arduino/setup-protoc@v3 + with: + version: "27.0" + +- uses: Nugine/setup-flatc@v1 + with: + version: "24.3.25" + +# How to add Console web + +1. wget [http://dl.rustfs.com/console/console.latest.tar.gz](https://dl.rustfs.com/console/rustfs-console-latest.zip) + +2. mkdir in this repos folder `./rustfs/static` + +3. Compile RustFS + +# Star RustFS + +Add Env infomation: + +``` +export RUST_LOG="rustfs=debug,ecstore=debug,s3s=debug,iam=debug" +export RUSTFS_VOLUMES="./target/volume/test" +export RUSTFS_ADDRESS="0.0.0.0:9000" +export RUSTFS_CONSOLE_ENABLE=true +export RUSTFS_CONSOLE_ADDRESS="0.0.0.0:9001" +export RUSTFS_SERVER_ENDPOINT="http://127.0.0.1:9000" +``` + +You need replace your real data folder: + +``` +./rustfs /data/rustfs +``` diff --git a/cli/rustfs-gui/Cargo.toml b/cli/rustfs-gui/Cargo.toml index 87bf7a87..c9af2fc3 100644 --- a/cli/rustfs-gui/Cargo.toml +++ b/cli/rustfs-gui/Cargo.toml @@ -11,17 +11,17 @@ chrono = { workspace = true } dioxus = { workspace = true, features = ["router"] } dirs = { workspace = true } futures-util = { workspace = true } +hex = { workspace = true } keyring = { workspace = true } -reqwest = { workspace = true } +lazy_static = { workspace = true } rfd = { workspace = true } +rust-embed = { workspace = true, features = ["interpolate-folder-path"] } serde = { workspace = true } serde_json = { workspace = true } +sha2 = { workspace = true } tokio = { workspace = true, features = ["io-util", "net", "process", "sync"] } tracing-subscriber = { workspace = true, features = ["fmt", "env-filter", "tracing-log", "time", "local-time", "json"] } tracing-appender = { workspace = true } -zip = { workspace = true } - - [features] default = ["desktop"] @@ -29,22 +29,5 @@ web = ["dioxus/web"] desktop = ["dioxus/desktop"] mobile = ["dioxus/mobile"] -[profile] - -[profile.wasm-dev] -inherits = "dev" -opt-level = 1 - -[profile.server-dev] -inherits = "dev" - -[profile.android-dev] -inherits = "dev" - -[profile.release] -opt-level = 3 # Optimization Level (0-3) -lto = true # Optimize when linking -codegen-units = 1 # Reduce code generation units to improve optimization - [lints] workspace = true diff --git a/cli/rustfs-gui/embedded-rustfs/README.md b/cli/rustfs-gui/embedded-rustfs/README.md new file mode 100644 index 00000000..190bfa36 --- /dev/null +++ b/cli/rustfs-gui/embedded-rustfs/README.md @@ -0,0 +1 @@ +rustfs bin path, do not delete \ No newline at end of file diff --git a/cli/rustfs-gui/src/components/home.rs b/cli/rustfs-gui/src/components/home.rs index 141f48d6..94b306e8 100644 --- a/cli/rustfs-gui/src/components/home.rs +++ b/cli/rustfs-gui/src/components/home.rs @@ -1,5 +1,5 @@ use crate::components::navbar::LoadingSpinner; -use crate::router::Route; +use crate::route::Route; use crate::utils::{RustFSConfig, ServiceManager}; use chrono::Datelike; use dioxus::logger::tracing::debug; diff --git a/cli/rustfs-gui/src/components/navbar.rs b/cli/rustfs-gui/src/components/navbar.rs index 6a23541b..98726b7a 100644 --- a/cli/rustfs-gui/src/components/navbar.rs +++ b/cli/rustfs-gui/src/components/navbar.rs @@ -1,4 +1,4 @@ -use crate::router::Route; +use crate::route::Route; use dioxus::logger::tracing::debug; use dioxus::prelude::*; diff --git a/cli/rustfs-gui/src/main.rs b/cli/rustfs-gui/src/main.rs index eba78337..6a8e1644 100644 --- a/cli/rustfs-gui/src/main.rs +++ b/cli/rustfs-gui/src/main.rs @@ -1,5 +1,5 @@ mod components; -mod router; +mod route; mod utils; mod views; diff --git a/cli/rustfs-gui/src/router/mod.rs b/cli/rustfs-gui/src/route/mod.rs similarity index 100% rename from cli/rustfs-gui/src/router/mod.rs rename to cli/rustfs-gui/src/route/mod.rs diff --git a/cli/rustfs-gui/src/router/router.rs b/cli/rustfs-gui/src/route/router.rs similarity index 100% rename from cli/rustfs-gui/src/router/router.rs rename to cli/rustfs-gui/src/route/router.rs diff --git a/cli/rustfs-gui/src/utils/helper.rs b/cli/rustfs-gui/src/utils/helper.rs index b597ef81..57c7f4ac 100644 --- a/cli/rustfs-gui/src/utils/helper.rs +++ b/cli/rustfs-gui/src/utils/helper.rs @@ -1,14 +1,31 @@ use crate::utils::RustFSConfig; use dioxus::logger::tracing::{debug, error, info}; -use futures_util::TryStreamExt; +use lazy_static::lazy_static; +use rust_embed::RustEmbed; +use sha2::{Digest, Sha256}; use std::error::Error; -use std::fs::File; use std::path::{Path, PathBuf}; use std::process::Command as StdCommand; use std::time::Duration; +use tokio::fs; +use tokio::fs::File; use tokio::io::AsyncWriteExt; use tokio::net::TcpStream; -use tokio::sync::mpsc; +use tokio::sync::{mpsc, Mutex}; + +#[derive(RustEmbed)] +#[folder = "$CARGO_MANIFEST_DIR/embedded-rustfs/"] +struct Asset; + +// Use `lazy_static` to cache the checksum of embedded resources +lazy_static! { + static ref RUSTFS_HASH: Mutex = { + let rustfs_file = if cfg!(windows) { "rustfs.exe" } else { "rustfs" }; + let rustfs_data = Asset::get(rustfs_file).expect("RustFs binary not embedded"); + let hash = hex::encode(Sha256::digest(&rustfs_data.data)); + Mutex::new(hash) + }; +} /// Service command /// This enum represents the commands that can be sent to the service manager @@ -159,107 +176,38 @@ impl ServiceManager { } } - let executable_path = if cfg!(windows) { - bin_dir.join("rustfs.exe") - } else { - bin_dir.join("rustfs") - }; + let rustfs_file = if cfg!(windows) { "rustfs.exe" } else { "rustfs" }; + let executable_path = bin_dir.join(rustfs_file); + let hash_path = bin_dir.join("embedded_rustfs.sha256"); - // If the executable file doesn't exist, download and unzip it - if !executable_path.exists() { - // download the file - let tmp_zip = rustfs_dir.join("rustfs.zip"); - let file_download_url = if cfg!(windows) { - "https://api.xmb.xyz/download/rustfs-win.zip" - } else { - "https://api.xmb.xyz/download/rustfs.zip" - }; - - let download_task = Self::download_file(file_download_url, &tmp_zip); - let unzip_task = async { - download_task.await?; - Self::unzip_file(&tmp_zip, &bin_dir)?; - tokio::fs::remove_file(&tmp_zip).await?; - Ok::<(), Box>(()) - }; - unzip_task.await?; - - // delete the temporary zip file - tokio::fs::remove_file(&tmp_zip).await?; - - // set execution permissions on unix systems - #[cfg(unix)] - { - use std::os::unix::fs::PermissionsExt; - let mut perms = std::fs::metadata(&executable_path)?.permissions(); - perms.set_mode(0o755); - std::fs::set_permissions(&executable_path, perms)?; + if executable_path.exists() && hash_path.exists() { + let cached_hash = fs::read_to_string(&hash_path).await?; + let expected_hash = RUSTFS_HASH.lock().await; + if cached_hash == *expected_hash { + println!("Use cached rustfs: {:?}", executable_path); + return Ok(executable_path); } - Self::show_info("服务程序已成功下载并准备就绪"); + } + + // Extract and write files + let rustfs_data = Asset::get(rustfs_file).expect("RustFS binary not embedded"); + let mut file = File::create(&executable_path).await?; + file.write_all(&rustfs_data.data).await?; + let expected_hash = hex::encode(Sha256::digest(&rustfs_data.data)); + fs::write(&hash_path, expected_hash).await?; + + // set execution permissions on unix systems + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + let mut perms = std::fs::metadata(&executable_path)?.permissions(); + perms.set_mode(0o755); + std::fs::set_permissions(&executable_path, perms)?; } Ok(executable_path) } - /// Download the file - /// This function is a modified version of the example from the `reqwest` crate documentation - /// - /// # Example - /// ``` - /// let url = "https://api.xmb.xyz/download/rustfs.zip"; - /// let path = Path::new("rustfs.zip"); - /// download_file(url, path).await; - /// ``` - async fn download_file(url: &str, path: &Path) -> Result<(), Box> { - let client = reqwest::Client::new(); - let res = client.get(url).send().await?; - - if !res.status().is_success() { - return Err(format!("下载失败:{}", res.status()).into()); - } - - let mut file = tokio::fs::File::create(path).await?; - let mut stream = res.bytes_stream(); - while let Ok(Some(chunk)) = stream.try_next().await { - file.write_all(&chunk).await?; - } - - Ok(()) - } - - /// unzip the file - /// This function is a modified version of the example from the `zip` crate documentation - /// - /// # Example - /// ``` - /// let zip_path = Path::new("rustfs.zip"); - /// let extract_path = Path::new("rustfs"); - /// unzip_file(zip_path, extract_path); - /// ``` - fn unzip_file(zip_path: &Path, extract_path: &Path) -> Result<(), Box> { - let file = File::open(zip_path)?; - let mut archive = zip::ZipArchive::new(file)?; - - for i in 0..archive.len() { - let mut file = archive.by_index(i)?; - let out_path = extract_path.join(file.name()); - - if file.name().ends_with('/') { - std::fs::create_dir_all(&out_path)?; - } else { - if let Some(p) = out_path.parent() { - if !p.exists() { - std::fs::create_dir_all(p)?; - } - } - let mut outfile = File::create(&out_path)?; - std::io::copy(&mut file, &mut outfile)?; - } - } - - Ok(()) - } - /// Helper function: Extracts the port from the address string /// /// # Example diff --git a/cli/rustfs-gui/src/views/app.rs b/cli/rustfs-gui/src/views/app.rs index 1523eb0b..708a8974 100644 --- a/cli/rustfs-gui/src/views/app.rs +++ b/cli/rustfs-gui/src/views/app.rs @@ -1,4 +1,4 @@ -use crate::router::Route; +use crate::route::Route; use dioxus::logger::tracing::info; use dioxus::prelude::*; diff --git a/ecstore/Cargo.toml b/ecstore/Cargo.toml index d332c904..cacafa49 100644 --- a/ecstore/Cargo.toml +++ b/ecstore/Cargo.toml @@ -32,7 +32,7 @@ s3s.workspace = true http.workspace = true highway = "1.3.0" url.workspace = true -uuid = { version = "1.12.1", features = ["v4", "fast-rng", "serde"] } +uuid = { version = "1.15.1", features = ["v4", "fast-rng", "serde"] } reed-solomon-erasure = { version = "6.0.0", features = ["simd-accel"] } transform-stream = "0.3.1" lazy_static.workspace = true diff --git a/ecstore/src/disk/endpoint.rs b/ecstore/src/disk/endpoint.rs index 254a1213..6e1ac442 100644 --- a/ecstore/src/disk/endpoint.rs +++ b/ecstore/src/disk/endpoint.rs @@ -1,7 +1,6 @@ use crate::error::{Error, Result}; use crate::utils::net; use path_absolutize::Absolutize; -use path_clean::PathClean; use std::{fmt::Display, path::Path}; use url::{ParseError, Url}; @@ -29,7 +28,7 @@ pub struct Endpoint { impl Display for Endpoint { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if self.url.scheme() == "file" { - write!(f, "{}", self.url.path()) + write!(f, "{}", self.get_file_path()) } else { write!(f, "{}", self.url) } @@ -42,12 +41,8 @@ impl TryFrom<&str> for Endpoint { /// Performs the conversion. fn try_from(value: &str) -> Result { - /// check whether given path is not empty. - fn is_empty_path(path: impl AsRef) -> bool { - ["", "/", "\\"].iter().any(|&v| Path::new(v).eq(path.as_ref())) - } - - if is_empty_path(value) { + // check whether given path is not empty. + if ["", "/", "\\"].iter().any(|&v| v.eq(value)) { return Err(Error::from_string("empty or root endpoint is not supported")); } @@ -67,35 +62,26 @@ impl TryFrom<&str> for Endpoint { return Err(Error::from_string("invalid URL endpoint format")); } - let path = Path::new(url.path()).clean(); - if is_empty_path(&path) { - return Err(Error::from_string("empty or root path is not supported in URL endpoint")); - } + let path = url.path().to_string(); - if let Some(v) = path.to_str() { - url.set_path(v) - } + #[cfg(not(windows))] + let path = Path::new(&path).absolutize()?; // On windows having a preceding SlashSeparator will cause problems, if the // command line already has C:/ url.set_path(v), + None => return Err(Error::from_string("invalid path")), } url @@ -182,6 +168,15 @@ impl Endpoint { _ => String::new(), } } + + pub fn get_file_path(&self) -> &str { + let path = self.url.path(); + + #[cfg(windows)] + let path = &path[1..]; + + path + } } /// parse a file path into an URL. diff --git a/ecstore/src/disk/local.rs b/ecstore/src/disk/local.rs index 8a559477..7f8bd1cc 100644 --- a/ecstore/src/disk/local.rs +++ b/ecstore/src/disk/local.rs @@ -114,7 +114,7 @@ impl Debug for LocalDisk { impl LocalDisk { pub async fn new(ep: &Endpoint, cleanup: bool) -> Result { - let root = fs::canonicalize(ep.url.path()).await?; + let root = fs::canonicalize(ep.get_file_path()).await?; if cleanup { // TODO: 删除tmp数据 diff --git a/ecstore/src/disk/remote.rs b/ecstore/src/disk/remote.rs index 9b6597d6..68a5ab31 100644 --- a/ecstore/src/disk/remote.rs +++ b/ecstore/src/disk/remote.rs @@ -52,7 +52,7 @@ pub struct RemoteDisk { impl RemoteDisk { pub async fn new(ep: &Endpoint, _opt: &DiskOption) -> Result { // let root = fs::canonicalize(ep.url.path()).await?; - let root = PathBuf::from(ep.url.path()); + let root = PathBuf::from(ep.get_file_path()); let addr = format!("{}://{}:{}", ep.url.scheme(), ep.url.host_str().unwrap(), ep.url.port().unwrap()); Ok(Self { id: Mutex::new(None), diff --git a/ecstore/src/endpoints.rs b/ecstore/src/endpoints.rs index 5a0cac5c..8dbee992 100644 --- a/ecstore/src/endpoints.rs +++ b/ecstore/src/endpoints.rs @@ -231,7 +231,7 @@ impl PoolEndpointList { .map_err(|e| Error::from_string(format!("host '{}' cannot resolve: {}", host, e)))? }); - let path = ep.url.path(); + let path = ep.get_file_path(); match path_ip_map.entry(path) { Entry::Occupied(mut e) => { if e.get().intersection(host_ip_set).count() > 0 { @@ -255,7 +255,7 @@ impl PoolEndpointList { continue; } - let path = ep.url.path(); + let path = ep.get_file_path(); if local_path_set.contains(path) { return Err(Error::from_string(format!( "path '{}' cannot be served by different address on same server", @@ -272,7 +272,7 @@ impl PoolEndpointList { let mut local_endpoint_count = 0; for ep in endpoints.as_ref() { - ep_path_set.insert(ep.url.path()); + ep_path_set.insert(ep.get_file_path()); if ep.is_local && ep.url.has_host() { local_server_host_set.insert(ep.url.host()); local_port_set.insert(ep.url.port()); diff --git a/iam/Cargo.toml b/iam/Cargo.toml index e6e47259..6c66d8f6 100644 --- a/iam/Cargo.toml +++ b/iam/Cargo.toml @@ -18,7 +18,7 @@ ecstore = { path = "../ecstore" } serde_json.workspace = true async-trait.workspace = true thiserror.workspace = true -strum = { version = "0.26.3", features = ["derive"] } +strum = { version = "0.27.1", features = ["derive"] } arc-swap = "1.7.1" crypto = { path = "../crypto" } ipnetwork = { version = "0.21.1", features = ["serde"] } diff --git a/iam/src/auth/credentials.rs b/iam/src/auth/credentials.rs index 01e832b4..905c1771 100644 --- a/iam/src/auth/credentials.rs +++ b/iam/src/auth/credentials.rs @@ -152,10 +152,7 @@ impl Credentials { const IAM_POLICY_CLAIM_NAME_SA: &str = "sa-policy"; self.claims .as_ref() - .map(|x| { - x.get(IAM_POLICY_CLAIM_NAME_SA) - .map_or(false, |_| !self.parent_user.is_empty()) - }) + .map(|x| x.get(IAM_POLICY_CLAIM_NAME_SA).is_some_and(|_| !self.parent_user.is_empty())) .unwrap_or_default() } @@ -164,10 +161,7 @@ impl Credentials { return self .claims .as_ref() - .map(|x| { - x.get(&iam_policy_claim_name_sa()) - .map_or(false, |v| v == INHERITED_POLICY_TYPE) - }) + .map(|x| x.get(&iam_policy_claim_name_sa()).is_some_and(|v| v == INHERITED_POLICY_TYPE)) .unwrap_or_default(); } diff --git a/iam/src/error.rs b/iam/src/error.rs index f99cf89d..4c4ff0a6 100644 --- a/iam/src/error.rs +++ b/iam/src/error.rs @@ -79,6 +79,9 @@ pub enum Error { #[error("action not allowed")] IAMActionNotAllowed, + #[error("invalid expiration")] + InvalidExpiration, + #[error("no secret key with access key")] NoSecretKeyWithAccessKey, diff --git a/iam/src/policy/function.rs b/iam/src/policy/function.rs index 03a020dc..54313fb7 100644 --- a/iam/src/policy/function.rs +++ b/iam/src/policy/function.rs @@ -131,9 +131,9 @@ impl<'de> Deserialize<'de> for Functions { } } - if inner_data.is_empty() { + /* if inner_data.is_empty() { return Err(Error::custom("has no condition element")); - } + } */ Ok(inner_data) } @@ -180,7 +180,7 @@ mod tests { "s3:x-amz-server-side-encryption-customer-algorithm": "true" } }"# => false; "1")] - #[test_case(r#"{}"# => false; "2")] + #[test_case(r#"{}"# => true; "2")] #[test_case( r#"{ "StringLike": { diff --git a/iam/src/store/object.rs b/iam/src/store/object.rs index 99bf40db..8b11ae15 100644 --- a/iam/src/store/object.rs +++ b/iam/src/store/object.rs @@ -846,7 +846,9 @@ impl Store for ObjectStore { let name = ecstore::utils::path::dir(item); info!("load svc user: {}", name); if let Err(err) = self.load_user(&name, UserType::Svc, &mut items_cache).await { - return Err(Error::msg(std::format!("load_user failed: {}", err))); + if !is_err_no_such_user(&err) { + return Err(Error::msg(std::format!("load svc user failed: {}", err))); + } }; } diff --git a/iam/src/sys.rs b/iam/src/sys.rs index 6a016708..c22a9d56 100644 --- a/iam/src/sys.rs +++ b/iam/src/sys.rs @@ -197,6 +197,10 @@ impl IamSys { return Err(IamError::IAMActionNotAllowed.into()); } + if opts.expiration.is_none() { + return Err(IamError::InvalidExpiration.into()); + } + // TODO: check allow_site_replicator_account let policy_buf = if let Some(policy) = opts.session_policy { @@ -229,9 +233,13 @@ impl IamSys { } } + // set expiration time default to 1 hour m.insert( "exp".to_string(), - serde_json::Value::Number(serde_json::Number::from(opts.expiration.map_or(0, |t| t.unix_timestamp()))), + serde_json::Value::Number(serde_json::Number::from( + opts.expiration + .map_or(OffsetDateTime::now_utc().unix_timestamp() + 3600, |t| t.unix_timestamp()), + )), ); let (access_key, secret_key) = if !opts.access_key.is_empty() || !opts.secret_key.is_empty() { @@ -385,7 +393,7 @@ impl IamSys { return Ok(()); }; - if u.credentials.is_service_account() { + if !u.credentials.is_service_account() { return Ok(()); } diff --git a/iam/src/utils.rs b/iam/src/utils.rs index 00448fdd..2d301bb9 100644 --- a/iam/src/utils.rs +++ b/iam/src/utils.rs @@ -1,5 +1,5 @@ use ecstore::error::{Error, Result}; -use jsonwebtoken::{encode, Algorithm, DecodingKey, EncodingKey, Header}; +use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey, Header}; use rand::{Rng, RngCore}; use serde::{de::DeserializeOwned, Serialize}; @@ -42,7 +42,7 @@ pub fn gen_secret_key(length: usize) -> crate::Result { pub fn generate_jwt(claims: &T, secret: &str) -> Result { let header = Header::new(Algorithm::HS512); - encode(&header, &claims, &EncodingKey::from_secret(secret.as_bytes())) + jsonwebtoken::encode(&header, &claims, &EncodingKey::from_secret(secret.as_bytes())) } pub fn extract_claims( @@ -58,7 +58,8 @@ pub fn extract_claims( #[cfg(test)] mod tests { - use super::{gen_access_key, gen_secret_key}; + use super::{gen_access_key, gen_secret_key, generate_jwt}; + use serde::{Deserialize, Serialize}; #[test] fn test_gen_access_key() { @@ -76,4 +77,34 @@ mod tests { let b = gen_secret_key(10).unwrap(); assert_ne!(a, b); } + + #[derive(Debug, Serialize, Deserialize, PartialEq)] + struct Claims { + sub: String, + company: String, + } + + #[test] + fn test_generate_jwt() { + let claims = Claims { + sub: "user1".to_string(), + company: "example".to_string(), + }; + let secret = "my_secret"; + let token = generate_jwt(&claims, secret).unwrap(); + + assert!(!token.is_empty()); + } + + // #[test] + // fn test_extract_claims() { + // let claims = Claims { + // sub: "user1".to_string(), + // company: "example".to_string(), + // }; + // let secret = "my_secret"; + // let token = generate_jwt(&claims, secret).unwrap(); + // let decoded_claims = extract_claims::(&token, secret).unwrap(); + // assert_eq!(decoded_claims.claims, claims); + // } } diff --git a/madmin/src/user.rs b/madmin/src/user.rs index 7de50f5b..3a398c51 100644 --- a/madmin/src/user.rs +++ b/madmin/src/user.rs @@ -211,6 +211,7 @@ pub struct UpdateServiceAccountReq { pub new_description: Option, #[serde(rename = "newExpiration", skip_serializing_if = "Option::is_none")] + #[serde(with = "time::serde::rfc3339::option")] pub new_expiration: Option, } diff --git a/rustfs/Cargo.toml b/rustfs/Cargo.toml index 4097167a..e27c5957 100644 --- a/rustfs/Cargo.toml +++ b/rustfs/Cargo.toml @@ -59,7 +59,7 @@ tower.workspace = true tracing-error.workspace = true tracing-subscriber.workspace = true transform-stream.workspace = true -uuid = "1.12.1" +uuid = "1.15.1" url.workspace = true admin = { path = "../api/admin" } axum.workspace = true @@ -73,7 +73,9 @@ iam = { path = "../iam" } jsonwebtoken = "9.3.0" tower-http = { version = "0.6.2", features = ["cors"] } mime_guess = "2.0.5" -rust-embed = { version = "8.5.0", features = ["interpolate-folder-path"] } +rust-embed = { workspace = true, features = ["interpolate-folder-path"] } +local-ip-address = { workspace = true } +chrono = { workspace = true } [build-dependencies] prost-build.workspace = true @@ -85,7 +87,7 @@ futures-util.workspace = true # uuid = { version = "1.8.0", features = ["v4", "fast-rng", "serde"] } ecstore = { path = "../ecstore" } s3s.workspace = true -clap = { version = "4.5.27", features = ["derive","env"] } +clap = { version = "4.5.31", features = ["derive", "env"] } tracing-subscriber = { version = "0.3.19", features = ["env-filter", "time"] } hyper-util = { version = "0.1.10", features = [ "tokio", diff --git a/rustfs/src/admin/handlers/service_account.rs b/rustfs/src/admin/handlers/service_account.rs index 0af420bd..fbc2e73d 100644 --- a/rustfs/src/admin/handlers/service_account.rs +++ b/rustfs/src/admin/handlers/service_account.rs @@ -53,6 +53,16 @@ impl Operation for AddServiceAccount { .validate() .map_err(|e| S3Error::with_message(InvalidRequest, e.to_string()))?; + let session_policy = if let Some(policy) = &create_req.policy { + let p = Policy::parse_config(policy.as_bytes()).map_err(|e| { + debug!("parse policy failed, e: {:?}", e); + s3_error!(InvalidArgument, "parse policy failed") + })?; + Some(p) + } else { + None + }; + let Some(sys_cred) = get_global_action_cred() else { return Err(s3_error!(InvalidRequest, "get sys cred failed")); }; @@ -95,7 +105,7 @@ impl Operation for AddServiceAccount { name: create_req.name, description: create_req.description, expiration: create_req.expiration, - session_policy: create_req.policy.and_then(|p| Policy::parse_config(p.as_bytes()).ok()), + session_policy, ..Default::default() }; diff --git a/rustfs/src/config/mod.rs b/rustfs/src/config/mod.rs index 663dd03e..cd8f238f 100644 --- a/rustfs/src/config/mod.rs +++ b/rustfs/src/config/mod.rs @@ -60,6 +60,6 @@ pub struct Opt { #[arg(long, default_value_t = false, env = "RUSTFS_CONSOLE_ENABLE")] pub console_enable: bool, - #[arg(long, default_value_t = format!("127.0.0.1:{}", 0), env = "RUSTFS_CONSOLE_ADDRESS")] + #[arg(long, default_value_t = format!("127.0.0.1:{}", 9002), env = "RUSTFS_CONSOLE_ADDRESS")] pub console_address: String, } diff --git a/rustfs/src/console.rs b/rustfs/src/console.rs index 5af9f534..81c109d0 100644 --- a/rustfs/src/console.rs +++ b/rustfs/src/console.rs @@ -9,6 +9,12 @@ use axum::{ use mime_guess::from_path; use rust_embed::RustEmbed; use serde::Serialize; +use shadow_rs::shadow; +use std::net::Ipv4Addr; +use std::sync::OnceLock; +use tracing::info; + +shadow!(build); #[derive(RustEmbed)] #[folder = "$CARGO_MANIFEST_DIR/static"] @@ -42,11 +48,12 @@ async fn static_handler(uri: axum::http::Uri) -> impl IntoResponse { } #[derive(Debug, Serialize)] -struct Config { +pub(crate) struct Config { api: Api, s3: S3, release: Release, license: License, + doc: String, } impl Config { @@ -67,12 +74,30 @@ impl Config { name: "Apache-2.0".to_string(), url: "https://www.apache.org/licenses/LICENSE-2.0".to_string(), }, + doc: "https://rustfs.com/docs/".to_string(), } } fn to_json(&self) -> String { serde_json::to_string(self).unwrap_or_default() } + + pub(crate) fn version(&self) -> String { + format!( + "RELEASE.{} (rust {} {})", + self.release.date.clone(), + build::RUST_VERSION, + build::BUILD_TARGET + ) + } + + pub(crate) fn license(&self) -> String { + format!("{} {}", self.license.name.clone(), self.license.url.clone()) + } + + pub(crate) fn doc(&self) -> String { + self.doc.clone() + } } #[derive(Debug, Serialize)] @@ -99,8 +124,27 @@ struct License { url: String, } -async fn config_handler(axum::extract::Extension(fs_addr): axum::extract::Extension) -> impl IntoResponse { - let cfg = Config::new(&fs_addr, "v0.0.1", "2025-01-01").to_json(); +pub(crate) static CONSOLE_CONFIG: OnceLock = OnceLock::new(); + +pub(crate) fn init_console_cfg(fs_addr: &str) { + CONSOLE_CONFIG.get_or_init(|| { + let ver = { + if !build::TAG.is_empty() { + build::TAG.to_string() + } else if !build::SHORT_COMMIT.is_empty() { + format!("@{}", build::SHORT_COMMIT) + } else { + build::PKG_VERSION.to_string() + } + }; + + Config::new(fs_addr, ver.as_str(), build::COMMIT_DATE_3339) + }); +} + +#[allow(clippy::const_is_empty)] +async fn config_handler() -> impl IntoResponse { + let cfg = CONSOLE_CONFIG.get().unwrap().to_json(); Response::builder() .header("content-type", "application/json") @@ -109,15 +153,18 @@ async fn config_handler(axum::extract::Extension(fs_addr): axum::extract::Extens .unwrap() } -pub async fn start_static_file_server(addrs: &str, fs_addr: &str) { +pub async fn start_static_file_server(addrs: &str, local_ip: Ipv4Addr, access_key: &str, secret_key: &str) { // 创建路由 let app = Router::new() - .route("/config.json", get(config_handler).layer(axum::extract::Extension(fs_addr.to_owned()))) + .route("/config.json", get(config_handler)) .nest_service("/", get(static_handler)); let listener = tokio::net::TcpListener::bind(addrs).await.unwrap(); + let local_addr = listener.local_addr().unwrap(); - println!("console running on: http://{} with s3 api {}", listener.local_addr().unwrap(), fs_addr); + info!("WebUI: http://{}:{} http://127.0.0.1:{}", local_ip, local_addr.port(), local_addr.port()); + info!(" RootUser: {}", access_key); + info!(" RootPass: {}", secret_key); axum::serve(listener, app).await.unwrap(); } diff --git a/rustfs/src/main.rs b/rustfs/src/main.rs index 2e6a7ab2..ab61a713 100644 --- a/rustfs/src/main.rs +++ b/rustfs/src/main.rs @@ -6,13 +6,17 @@ mod grpc; mod logging; mod service; mod storage; +mod utils; use crate::auth::IAMAuth; +use crate::console::{init_console_cfg, CONSOLE_CONFIG}; +use chrono::Datelike; use clap::Parser; use common::{ error::{Error, Result}, globals::set_global_addr, }; +use config::{DEFAULT_ACCESS_KEY, DEFAULT_SECRET_KEY}; use ecstore::heal::background_heal_ops::init_auto_heal; use ecstore::utils::net::{self, get_available_port}; use ecstore::{ @@ -39,18 +43,20 @@ use tonic::{metadata::MetadataValue, Request, Status}; use tower_http::cors::CorsLayer; use tracing::{debug, error, info, warn}; use tracing_error::ErrorLayer; -use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt}; +use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; fn setup_tracing() { use tracing_subscriber::EnvFilter; - let env_filter = EnvFilter::from_default_env(); + let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")); let enable_color = std::io::stdout().is_terminal(); - let subscriber = fmt() + let subscriber = tracing_subscriber::fmt::fmt() .pretty() .with_env_filter(env_filter) .with_ansi(enable_color) + .with_file(true) + .with_line_number(true) .finish() .with(ErrorLayer::default()); @@ -66,6 +72,18 @@ fn check_auth(req: Request<()>) -> Result, Status> { } } +fn print_server_info() { + let cfg = CONSOLE_CONFIG.get().unwrap(); + let current_year = chrono::Utc::now().year(); + + // 使用自定义宏打印服务器信息 + info!("RustFS Object Storage Server"); + info!("Copyright: 2024-{} RustFS, Inc", current_year); + info!("License: {}", cfg.license()); + info!("Version: {}", cfg.version()); + info!("Docs: {}", cfg.doc()); +} + fn main() -> Result<()> { //解析获得到的参数 let opt = config::Opt::parse(); @@ -102,13 +120,39 @@ async fn run(opt: config::Opt) -> Result<()> { let listener = TcpListener::bind(server_address.clone()).await?; //获取监听地址 let local_addr: SocketAddr = listener.local_addr()?; + let local_ip = utils::get_local_ip().ok_or(local_addr.ip()).unwrap(); // 用于 rpc let (endpoint_pools, setup_type) = EndpointServerPools::from_volumes(server_address.clone().as_str(), opt.volumes.clone()) .map_err(|err| Error::from_string(err.to_string()))?; + // Print RustFS-style logging for pool formatting for (i, eps) in endpoint_pools.as_ref().iter().enumerate() { - debug!( + info!( + "Formatting {}st pool, {} set(s), {} drives per set.", + i + 1, + eps.set_count, + eps.drives_per_set + ); + + // Add warning for host with multiple drives in a set (similar to RustFS) + if eps.drives_per_set > 1 { + warn!("WARNING: Host local has more than 0 drives of set. A host failure will result in data becoming unavailable."); + } + } + + // Detailed endpoint information (showing all API endpoints) + let api_endpoints = format!("http://{}:{}", local_ip, server_port); + let localhost_endpoint = format!("http://127.0.0.1:{}", server_port); + info!("API: {} {}", api_endpoints, localhost_endpoint); + info!(" RootUser: {}", opt.access_key.clone()); + info!(" RootPass: {}", opt.secret_key.clone()); + if DEFAULT_ACCESS_KEY.eq(&opt.access_key) && DEFAULT_SECRET_KEY.eq(&opt.secret_key) { + warn!("Detected default credentials '{}:{}', we recommend that you change these values with 'RUSTFS_ACCESS_KEY' and 'RUSTFS_SECRET_KEY' environment variables", DEFAULT_ACCESS_KEY, DEFAULT_SECRET_KEY); + } + + for (i, eps) in endpoint_pools.as_ref().iter().enumerate() { + info!( "created endpoints {}, set_count:{}, drives_per_set: {}, cmd: {:?}", i, eps.set_count, eps.drives_per_set, eps.cmd_line ); @@ -131,9 +175,12 @@ async fn run(opt: config::Opt) -> Result<()> { // let mut b = S3ServiceBuilder::new(storage::ecfs::FS::new(server_address.clone(), endpoint_pools).await?); let mut b = S3ServiceBuilder::new(store.clone()); + let access_key = opt.access_key.clone(); + let secret_key = opt.secret_key.clone(); //显示 info 信息 - info!("authentication is enabled {}, {}", &opt.access_key, &opt.secret_key); - b.set_auth(IAMAuth::new(opt.access_key, opt.secret_key)); + debug!("authentication is enabled {}, {}", &access_key, &secret_key); + + b.set_auth(IAMAuth::new(access_key, secret_key)); b.set_access(store.clone()); @@ -175,11 +222,10 @@ async fn run(opt: config::Opt) -> Result<()> { let http_server = ConnBuilder::new(TokioExecutor::new()); let mut ctrl_c = std::pin::pin!(tokio::signal::ctrl_c()); let graceful = hyper_util::server::graceful::GracefulShutdown::new(); - println!("server is running at http://{local_addr}"); loop { let (socket, _) = tokio::select! { - res = listener.accept() => { + res = listener.accept() => { match res { Ok(conn) => conn, Err(err) => { @@ -222,7 +268,7 @@ async fn run(opt: config::Opt) -> Result<()> { error!("ECStore init faild {:?}", &err); Error::from_string(err.to_string()) })?; - warn!(" init store success!"); + debug!("init store success!"); init_iam_sys(store.clone()).await.unwrap(); @@ -236,18 +282,17 @@ async fn run(opt: config::Opt) -> Result<()> { // init auto heal init_auto_heal().await; - info!("server was started"); + let srv_addr = format!("http://{}:{}", local_ip, server_port); + init_console_cfg(&srv_addr); + print_server_info(); if opt.console_enable { - info!("console is enabled"); + debug!("console is enabled"); + let access_key = opt.access_key.clone(); + let secret_key = opt.secret_key.clone(); + let console_address = opt.console_address.clone(); tokio::spawn(async move { - let ep = if !opt.server_domains.is_empty() { - format!("http://{}", opt.server_domains[0].clone()) - } else { - format!("http://127.0.0.1:{}", server_port) - }; - - console::start_static_file_server(&opt.console_address, &ep).await; + console::start_static_file_server(&console_address, local_ip, &access_key, &secret_key).await; }); } diff --git a/rustfs/src/utils.rs b/rustfs/src/utils.rs new file mode 100644 index 00000000..24afba86 --- /dev/null +++ b/rustfs/src/utils.rs @@ -0,0 +1,10 @@ +use local_ip_address; +use std::net::IpAddr; + +pub(crate) fn get_local_ip() -> Option { + match local_ip_address::local_ip() { + Ok(IpAddr::V4(ip)) => Some(ip), + Err(_) => None, + Ok(IpAddr::V6(_)) => todo!(), + } +} diff --git a/scripts/e2e-run.sh b/scripts/e2e-run.sh index 26e3d9c6..9b4392e8 100755 --- a/scripts/e2e-run.sh +++ b/scripts/e2e-run.sh @@ -3,9 +3,20 @@ BIN=$1 VOLUME=$2 chmod +x $BIN -sudo mkdir -p $VOLUME +mkdir -p $VOLUME export RUST_LOG="rustfs=debug,ecstore=debug,s3s=debug,iam=debug" export RUST_BACKTRACE=full +$BIN $VOLUME > /tmp/rustfs.log 2>&1 & -sudo nohup $BIN $VOLUME > /tmp/rustfs.log 2>&1 & +sleep 10 + +export AWS_ACCESS_KEY_ID=rustfsadmin +export AWS_SECRET_ACCESS_KEY=rustfsadmin +export AWS_REGION=us-east-1 +export AWS_ENDPOINT_URL=http://localhost:9000 +export RUST_LOG="s3s_e2e=debug,s3s_test=info,s3s=debug" +export RUST_BACKTRACE=full +s3s-e2e + +killall $BIN diff --git a/scripts/run.bat b/scripts/run.bat new file mode 100644 index 00000000..e0ec7dc5 --- /dev/null +++ b/scripts/run.bat @@ -0,0 +1,32 @@ +@echo off +rem filepath: run.bat + +if not defined SKIP_BUILD ( + cargo build -p rustfs --bins +) + +set current_dir=%cd% + +if not exist .\target\volume\test mkdir .\target\volume\test + +if not defined RUST_LOG ( + set RUST_BACKTRACE=1 + set RUST_LOG=rustfs=debug,ecstore=debug,s3s=debug,iam=debug +) + +rem set RUSTFS_ERASURE_SET_DRIVE_COUNT=5 + +rem set RUSTFS_STORAGE_CLASS_INLINE_BLOCK=512 KB + +rem set RUSTFS_VOLUMES=.\target\volume\test{0...4} +set RUSTFS_VOLUMES=.\target\volume\test +set RUSTFS_ADDRESS=0.0.0.0:9000 +set RUSTFS_CONSOLE_ENABLE=true +set RUSTFS_CONSOLE_ADDRESS=0.0.0.0:9002 +rem set RUSTFS_SERVER_DOMAINS=localhost:9000 + +if not "%~1"=="" ( + set RUSTFS_VOLUMES=%~1 +) + +cargo run --bin rustfs \ No newline at end of file diff --git a/scripts/static.sh b/scripts/static.sh new file mode 100755 index 00000000..9fd7469d --- /dev/null +++ b/scripts/static.sh @@ -0,0 +1 @@ +curl -L "https://dl.rustfs.com/console/rustfs-console-latest.zip" -o tempfile.zip && unzip -o tempfile.zip -d ./rustfs/static && rm tempfile.zip \ No newline at end of file