feat: add build-rustfs-gui process and optimize utils/helper.rs

1. Added a new build process `build-rustfs-gui` in `build.yaml` to streamline the build operations for the RustFS GUI.
2. Optimized `cli/rustfs-gui/utils/helper.rs` by using `rust-embed` to embed the `rustfs` resources directly into the binary.
This commit is contained in:
houseme
2025-03-05 18:47:21 +08:00
parent 220ac24bce
commit 9b77084ffe
8 changed files with 115 additions and 57 deletions
+37 -2
View File
@@ -7,6 +7,7 @@ on:
push: push:
branches: branches:
- main - main
tags: [ 'v*', '*' ]
jobs: jobs:
build-rustfs: build-rustfs:
@@ -60,19 +61,53 @@ jobs:
# Create package # Create package
mkdir -p ${ARTIFACT_NAME} mkdir -p ${ARTIFACT_NAME}
cp "$bin_path" ${ARTIFACT_NAME}/rustfs cp "$bin_path" ${ARTIFACT_NAME}/rustfs
# cp -r static ${ARTIFACT_NAME}/
zip -r ${ARTIFACT_NAME}.zip ${ARTIFACT_NAME} zip -r ${ARTIFACT_NAME}.zip ${ARTIFACT_NAME}
ls -la ls -la
# Copy files to the specified directory
mkdir -p cli/rustfs-gui/embedded-rustfs
cp -r ${ARTIFACT_NAME}/rustfs cli/rustfs-gui/embedded-rustfs/
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
with: with:
name: ${{ steps.package.outputs.artifact_name }} name: ${{ steps.package.outputs.artifact_name }}
path: ${{ steps.package.outputs.artifact_name }}.zip path: ${{ steps.package.outputs.artifact_name }}.zip
retention-days: 7 retention-days: 7
merge: build-rustfs-gui:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: build-rustfs needs: build-rustfs
if: startsWith(github.ref, 'refs/tags/')
steps:
- uses: actions/checkout@v4
- name: Install dioxus-cli
run: cargo install dioxus-cli
- name: Build and Bundle rustfs-gui
run: |
relaese_path = "target/${{ matrix.variant.target }}"
mkdir -p ${relaese_path}
cd cli/rustfs-gui
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 ../../${relaese_path}
elif [[ "${{ matrix.variant.target }}" == *"windows-msvc"* ]]; then
dx bundle --platform windows --package-types "msi" --release --profile release --out-dir ../../target/${relaese_path}
fi
cd ../..
GUI_ARTIFACT_NAME="rustfs-gui-${{ matrix.variant.profile }}-${{ matrix.variant.target }}"
zip -r ${GUI_ARTIFACT_NAME}.zip target/${{ matrix.variant.target }}/rustfs-gui
echo "gui_artifact_name=${GUI_ARTIFACT_NAME}" >> $GITHUB_OUTPUT
ls -la
- 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, build-rustfs-gui ]
steps: steps:
- uses: actions/upload-artifact/merge@v4 - uses: actions/upload-artifact/merge@v4
with: with:
+1
View File
@@ -6,3 +6,4 @@
/logs /logs
.devcontainer .devcontainer
rustfs/static/* rustfs/static/*
vendor
Generated
+3
View File
@@ -5468,11 +5468,14 @@ dependencies = [
"dioxus", "dioxus",
"dirs 6.0.0", "dirs 6.0.0",
"futures-util", "futures-util",
"hex",
"keyring", "keyring",
"reqwest", "reqwest",
"rfd 0.15.2", "rfd 0.15.2",
"rust-embed",
"serde", "serde",
"serde_json", "serde_json",
"sha2 0.10.8",
"tokio", "tokio",
"tracing-appender", "tracing-appender",
"tracing-subscriber", "tracing-subscriber",
+17 -13
View File
@@ -1,18 +1,18 @@
[workspace] [workspace]
members = [ members = [
"madmin", # Management dashboard and admin API interface "madmin", # Management dashboard and admin API interface
"rustfs", # Core file system implementation "rustfs", # Core file system implementation
"ecstore", # Erasure coding storage implementation "ecstore", # Erasure coding storage implementation
"e2e_test", # End-to-end test suite "e2e_test", # End-to-end test suite
"common/common", # Shared utilities and data structures "common/common", # Shared utilities and data structures
"common/lock", # Distributed locking implementation "common/lock", # Distributed locking implementation
"common/protos", # Protocol buffer definitions "common/protos", # Protocol buffer definitions
"api/admin", # Admin HTTP API endpoints "api/admin", # Admin HTTP API endpoints
"reader", # Object reading service "reader", # Object reading service
"common/workers", # Worker thread pools and task scheduling "common/workers", # Worker thread pools and task scheduling
"iam", # Identity and Access Management "iam", # Identity and Access Management
"crypto", # Cryptography and security features "crypto", # Cryptography and security features
"cli/rustfs-gui", # Graphical user interface client "cli/rustfs-gui", # Graphical user interface client
] ]
resolver = "2" resolver = "2"
@@ -45,6 +45,7 @@ futures = "0.3.31"
futures-util = "0.3.31" futures-util = "0.3.31"
common = { path = "./common/common" } common = { path = "./common/common" }
reader = { path = "./reader" } reader = { path = "./reader" }
hex = "0.4.3"
hyper = "1.6.0" hyper = "1.6.0"
hyper-util = { version = "0.1.10", features = [ hyper-util = { version = "0.1.10", features = [
"tokio", "tokio",
@@ -57,6 +58,7 @@ humantime = "2.1.0"
keyring = { version = "3.6.1", features = ["apple-native", "windows-native", "sync-secret-service"] } keyring = { version = "3.6.1", features = ["apple-native", "windows-native", "sync-secret-service"] }
lock = { path = "./common/lock" } lock = { path = "./common/lock" }
lazy_static = "1.5.0" lazy_static = "1.5.0"
local-ip-address = "0.6.3"
mime = "0.3.17" mime = "0.3.17"
netif = "0.1.6" netif = "0.1.6"
pin-project-lite = "0.2" pin-project-lite = "0.2"
@@ -71,6 +73,7 @@ reqwest = { version = "0.12.12", default-features = false, features = ["rustls-t
rfd = { version = "0.15.2", default-features = false, features = ["xdg-portal", "tokio"] } rfd = { version = "0.15.2", default-features = false, features = ["xdg-portal", "tokio"] }
rmp = "0.8.14" rmp = "0.8.14"
rmp-serde = "1.3.0" rmp-serde = "1.3.0"
rust-embed = "8.6.0"
s3s = { git = "https://github.com/Nugine/s3s.git", rev = "ab139f72fe768fb9d8cecfe36269451da1ca9779", default-features = true, features = [ s3s = { git = "https://github.com/Nugine/s3s.git", rev = "ab139f72fe768fb9d8cecfe36269451da1ca9779", default-features = true, features = [
"tower", "tower",
] } ] }
@@ -78,6 +81,7 @@ s3s-policy = { git = "https://github.com/Nugine/s3s.git", rev = "ab139f72fe768fb
shadow-rs = { version = "0.38.0", default-features = false } shadow-rs = { version = "0.38.0", default-features = false }
serde = { version = "1.0.217", features = ["derive"] } serde = { version = "1.0.217", features = ["derive"] }
serde_json = "1.0.138" serde_json = "1.0.138"
sha2 = "0.10.8"
tempfile = "3.16.0" tempfile = "3.16.0"
thiserror = "2.0.11" thiserror = "2.0.11"
time = { version = "0.3.37", features = [ time = { version = "0.3.37", features = [
+3
View File
@@ -11,11 +11,14 @@ chrono = { workspace = true }
dioxus = { workspace = true, features = ["router"] } dioxus = { workspace = true, features = ["router"] }
dirs = { workspace = true } dirs = { workspace = true }
futures-util = { workspace = true } futures-util = { workspace = true }
hex = { workspace = true }
keyring = { workspace = true } keyring = { workspace = true }
reqwest = { workspace = true } reqwest = { workspace = true }
rfd = { workspace = true } rfd = { workspace = true }
rust-embed = { workspace = true }
serde = { workspace = true } serde = { workspace = true }
serde_json = { workspace = true } serde_json = { workspace = true }
sha2 = { workspace = true }
tokio = { workspace = true, features = ["io-util", "net", "process", "sync"] } tokio = { workspace = true, features = ["io-util", "net", "process", "sync"] }
tracing-subscriber = { workspace = true, features = ["fmt", "env-filter", "tracing-log", "time", "local-time", "json"] } tracing-subscriber = { workspace = true, features = ["fmt", "env-filter", "tracing-log", "time", "local-time", "json"] }
tracing-appender = { workspace = true } tracing-appender = { workspace = true }
+1
View File
@@ -0,0 +1 @@
rustfs bin path, do not delete
+49 -38
View File
@@ -1,14 +1,32 @@
use crate::utils::RustFSConfig; use crate::utils::RustFSConfig;
use dioxus::logger::tracing::{debug, error, info}; use dioxus::logger::tracing::{debug, error, info};
use futures_util::TryStreamExt; use futures_util::TryStreamExt;
use lazy_static::lazy_static;
use rust_embed::RustEmbed;
use sha2::{Digest, Sha256};
use std::error::Error; use std::error::Error;
use std::fs::File;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process::Command as StdCommand; use std::process::Command as StdCommand;
use std::time::Duration; use std::time::Duration;
use tokio::fs;
use tokio::fs::File;
use tokio::io::AsyncWriteExt; use tokio::io::AsyncWriteExt;
use tokio::net::TcpStream; 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<String> = {
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 /// Service command
/// This enum represents the commands that can be sent to the service manager /// This enum represents the commands that can be sent to the service manager
@@ -159,45 +177,37 @@ impl ServiceManager {
} }
} }
let executable_path = if cfg!(windows) { let rustfs_file = if cfg!(windows) { "rustfs.exe" } else { "rustfs" };
bin_dir.join("rustfs.exe") let executable_path = bin_dir.join(rustfs_file);
} else { let hash_path = bin_dir.join("embedded_rustfs.sha256");
bin_dir.join("rustfs")
};
// If the executable file doesn't exist, download and unzip it if executable_path.exists() && hash_path.exists() {
if !executable_path.exists() { let cached_hash = fs::read_to_string(&hash_path).await?;
// download the file let expected_hash = RUSTFS_HASH.lock().await;
let tmp_zip = rustfs_dir.join("rustfs.zip"); if cached_hash == *expected_hash {
let file_download_url = if cfg!(windows) { println!("Use cached rustfs: {:?}", executable_path);
"https://api.xmb.xyz/download/rustfs-win.zip" return Ok(executable_path);
} 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<dyn Error>>(())
};
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)?;
} }
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)?;
}
// Self::show_info("服务程序已成功下载并准备就绪");
// }
Ok(executable_path) Ok(executable_path)
} }
@@ -236,7 +246,8 @@ impl ServiceManager {
/// let extract_path = Path::new("rustfs"); /// let extract_path = Path::new("rustfs");
/// unzip_file(zip_path, extract_path); /// unzip_file(zip_path, extract_path);
/// ``` /// ```
fn unzip_file(zip_path: &Path, extract_path: &Path) -> Result<(), Box<dyn Error>> { async fn unzip_file(zip_path: &Path, extract_path: &Path) -> Result<(), Box<dyn Error>> {
use std::fs::File;
let file = File::open(zip_path)?; let file = File::open(zip_path)?;
let mut archive = zip::ZipArchive::new(file)?; let mut archive = zip::ZipArchive::new(file)?;
+4 -4
View File
@@ -73,9 +73,9 @@ iam = { path = "../iam" }
jsonwebtoken = "9.3.0" jsonwebtoken = "9.3.0"
tower-http = { version = "0.6.2", features = ["cors"] } tower-http = { version = "0.6.2", features = ["cors"] }
mime_guess = "2.0.5" mime_guess = "2.0.5"
rust-embed = { version = "8.6.0", features = ["interpolate-folder-path"] } rust-embed = { workspace = true, features = ["interpolate-folder-path"] }
local-ip-address = "0.6.3" local-ip-address = { workspace = true }
chrono = "0.4" chrono = { workspace = true }
[build-dependencies] [build-dependencies]
prost-build.workspace = true prost-build.workspace = true
@@ -87,7 +87,7 @@ futures-util.workspace = true
# uuid = { version = "1.8.0", features = ["v4", "fast-rng", "serde"] } # uuid = { version = "1.8.0", features = ["v4", "fast-rng", "serde"] }
ecstore = { path = "../ecstore" } ecstore = { path = "../ecstore" }
s3s.workspace = true s3s.workspace = true
clap = { version = "4.5.31", features = ["derive","env"] } clap = { version = "4.5.31", features = ["derive", "env"] }
tracing-subscriber = { version = "0.3.19", features = ["env-filter", "time"] } tracing-subscriber = { version = "0.3.19", features = ["env-filter", "time"] }
hyper-util = { version = "0.1.10", features = [ hyper-util = { version = "0.1.10", features = [
"tokio", "tokio",