diff --git a/.gitignore b/.gitignore index 94fd091d..81d415f6 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ /test /logs .devcontainer +rustfs/static/* diff --git a/Cargo.lock b/Cargo.lock index 2b12bad9..8522404f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2999,7 +2999,7 @@ dependencies = [ "crypto", "ecstore", "futures", - "ipnetwork", + "ipnetwork 0.21.1", "itertools", "jsonwebtoken", "lazy_static", @@ -3258,6 +3258,15 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +[[package]] +name = "ipnetwork" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e" +dependencies = [ + "serde", +] + [[package]] name = "ipnetwork" version = "0.21.1" @@ -3879,6 +3888,12 @@ dependencies = [ "memoffset", ] +[[package]] +name = "no-std-net" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" + [[package]] name = "nodrop" version = "0.1.14" @@ -4596,6 +4611,97 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +[[package]] +name = "pnet" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "682396b533413cc2e009fbb48aadf93619a149d3e57defba19ff50ce0201bd0d" +dependencies = [ + "ipnetwork 0.20.0", + "pnet_base", + "pnet_datalink", + "pnet_packet", + "pnet_sys", + "pnet_transport", +] + +[[package]] +name = "pnet_base" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffc190d4067df16af3aba49b3b74c469e611cad6314676eaf1157f31aa0fb2f7" +dependencies = [ + "no-std-net", +] + +[[package]] +name = "pnet_datalink" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79e70ec0be163102a332e1d2d5586d362ad76b01cec86f830241f2b6452a7b7" +dependencies = [ + "ipnetwork 0.20.0", + "libc", + "pnet_base", + "pnet_sys", + "winapi", +] + +[[package]] +name = "pnet_macros" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13325ac86ee1a80a480b0bc8e3d30c25d133616112bb16e86f712dcf8a71c863" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "syn 2.0.98", +] + +[[package]] +name = "pnet_macros_support" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eed67a952585d509dd0003049b1fc56b982ac665c8299b124b90ea2bdb3134ab" +dependencies = [ + "pnet_base", +] + +[[package]] +name = "pnet_packet" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c96ebadfab635fcc23036ba30a7d33a80c39e8461b8bd7dc7bb186acb96560f" +dependencies = [ + "glob", + "pnet_base", + "pnet_macros", + "pnet_macros_support", +] + +[[package]] +name = "pnet_sys" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d4643d3d4db6b08741050c2f3afa9a892c4244c085a72fcda93c9c2c9a00f4b" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "pnet_transport" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f604d98bc2a6591cf719b58d3203fd882bdd6bf1db696c4ac97978e9f4776bf" +dependencies = [ + "libc", + "pnet_base", + "pnet_packet", + "pnet_sys", +] + [[package]] name = "png" version = "0.17.16" @@ -5345,8 +5451,10 @@ dependencies = [ "madmin", "matchit 0.8.6", "mime", + "mime_guess", "netif", "pin-project-lite", + "pnet", "prost", "prost-build", "prost-types", diff --git a/rustfs/Cargo.toml b/rustfs/Cargo.toml index 5b3b89f4..c1bc6d6e 100644 --- a/rustfs/Cargo.toml +++ b/rustfs/Cargo.toml @@ -70,6 +70,8 @@ iam = { path = "../iam" } jsonwebtoken = "9.3.0" tower-http = { version = "0.6.2", features = ["cors"] } include_dir = "0.7.4" +pnet = "0.35.0" +mime_guess = "2.0.5" [build-dependencies] prost-build.workspace = true diff --git a/rustfs/src/console.rs b/rustfs/src/console.rs index 704a575e..6bc4ca99 100644 --- a/rustfs/src/console.rs +++ b/rustfs/src/console.rs @@ -7,15 +7,30 @@ use axum::{ }; use include_dir::{include_dir, Dir}; +use mime_guess::from_path; +use pnet::datalink::interfaces; use serde::Serialize; +use std::net::SocketAddr; static STATIC_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/static"); async fn static_handler(uri: axum::http::Uri) -> impl IntoResponse { - let path = uri.path().trim_start_matches('/'); + let mut path = uri.path().trim_start_matches('/'); + if path.is_empty() { + path = "index.html" + } if let Some(file) = STATIC_DIR.get_file(path) { + let mime_type = from_path(file.path().as_os_str()).first_or_octet_stream(); Response::builder() .status(StatusCode::OK) + .header("Content-Type", mime_type.to_string()) + .body(Body::from(file.contents())) + .unwrap() + } else if let Some(file) = STATIC_DIR.get_file("index.html") { + let mime_type = from_path(file.path().as_os_str()).first_or_octet_stream(); + Response::builder() + .status(StatusCode::OK) + .header("Content-Type", mime_type.to_string()) .body(Body::from(file.contents())) .unwrap() } else { @@ -26,13 +41,66 @@ async fn static_handler(uri: axum::http::Uri) -> impl IntoResponse { } } -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Serialize)] struct Config { - fs_addr: String, + api: Api, + s3: S3, + release: Release, + license: License, +} + +impl Config { + fn new(url: &str, version: &str, date: &str) -> Self { + Config { + api: Api { + base_url: format!("{}/rustfs/admin/v3", url), + }, + s3: S3 { + endpoint: url.to_owned(), + region: "cn-east-1".to_owned(), + }, + release: Release { + version: version.to_string(), + date: date.to_string(), + }, + license: License { + name: "Apache-2.0".to_string(), + url: "https://www.apache.org/licenses/LICENSE-2.0".to_string(), + }, + } + } + + fn to_json(&self) -> String { + serde_json::to_string(self).unwrap_or_default() + } +} + +#[derive(Debug, Serialize)] +struct Api { + #[serde(rename = "baseURL")] + base_url: String, +} + +#[derive(Debug, Serialize)] +struct S3 { + endpoint: String, + region: String, +} + +#[derive(Debug, Serialize)] +struct Release { + version: String, + date: String, +} + +#[derive(Debug, Serialize)] +struct License { + name: String, + url: String, } async fn config_handler(axum::extract::Extension(fs_addr): axum::extract::Extension) -> impl IntoResponse { - let cfg = serde_json::to_string(&Config { fs_addr }).unwrap_or_default(); + let cfg = Config::new(&fs_addr, "v0.0.1", "2025-01-01").to_json(); Response::builder() .header("content-type", "application/json") @@ -42,14 +110,37 @@ async fn config_handler(axum::extract::Extension(fs_addr): axum::extract::Extens } pub async fn start_static_file_server(addrs: &str, fs_addr: &str) { + // 将字符串解析为 SocketAddr + let socket_addr: SocketAddr = fs_addr.parse().unwrap(); + + // 提取 IP 地址和端口号 + let mut src_ip = socket_addr.ip(); + let port = socket_addr.port(); + + if src_ip.to_string() == "0.0.0.0" { + for iface in interfaces() { + if iface.is_loopback() || !iface.is_up() { + continue; + } + for ip in iface.ips { + if ip.is_ipv4() { + src_ip = ip.ip(); + } + } + } + } + + // FIXME: TODO: protocol from config + let s3_url = format!("http://{}:{}", src_ip, port); + // 创建路由 let app = Router::new() - .route("/config.json", get(config_handler).layer(axum::extract::Extension(fs_addr.to_string()))) - .route("/*file", get(static_handler)); + .route("/config.json", get(config_handler).layer(axum::extract::Extension(s3_url.clone()))) + .nest_service("/", get(static_handler)); let listener = tokio::net::TcpListener::bind(addrs).await.unwrap(); - println!("console listening on: {}", listener.local_addr().unwrap()); + println!("console running on: http://{} with s3 api {}", listener.local_addr().unwrap(), s3_url); axum::serve(listener, app).await.unwrap(); } diff --git a/rustfs/src/main.rs b/rustfs/src/main.rs index fd5d4079..0f770af1 100644 --- a/rustfs/src/main.rs +++ b/rustfs/src/main.rs @@ -234,7 +234,7 @@ async fn run(opt: config::Opt) -> Result<()> { if opt.console_enable { info!("console is enabled"); tokio::spawn(async move { - console::start_static_file_server(&opt.console_address, &opt.address).await; + console::start_static_file_server(&opt.console_address, server_address.as_str()).await; }); } diff --git a/rustfs/static/index.html b/rustfs/static/index.html deleted file mode 100644 index 612c5bbb..00000000 --- a/rustfs/static/index.html +++ /dev/null @@ -1 +0,0 @@ -static index \ No newline at end of file diff --git a/scripts/run.sh b/scripts/run.sh index 4aa012d7..2d4d7f85 100755 --- a/scripts/run.sh +++ b/scripts/run.sh @@ -7,13 +7,13 @@ fi current_dir=$(pwd) mkdir -p ./target/volume/test -mkdir -p ./target/volume/test{0..4} +# mkdir -p ./target/volume/test{0..4} -if [ -z "$RUST_LOG" ]; then -export RUST_BACKTRACE=1 - export RUST_LOG="rustfs=debug,ecstore=debug,s3s=debug,iam=debug" -fi +# if [ -z "$RUST_LOG" ]; then +# export RUST_BACKTRACE=1 +# export RUST_LOG="rustfs=debug,ecstore=debug,s3s=debug,iam=debug" +# fi # export RUSTFS_ERASURE_SET_DRIVE_COUNT=5