Files
markbase/src/bin/raid_webdav_auto.rs
Warren 71fa48a626 System Extension注册完成 + FSKit Driver待办事项
已完成:
 App ID(6770506571)
 Bundle ID(com.momentry.markbase.fskit)
 Developer ID Application证书导入
 .app Bundle创建(build/MarkBaseFSKit.app)
 entitlements.plist配置

限制:
- binary未实现FSKit driver(占位符)
- 无法通过systemextensionsctl install安装
- 需要完整FSKit接口实现

策略:
- 短期:WebDAV(500 MB/s)
- 长期:FSKit Driver完整实现(650 MB/s)

文档:
- SYSTEM_EXTENSION_MANUAL_INSTALL.md
- FSKIT_DRIVER_TODO.md(未来待办)
2026-05-18 20:45:50 +08:00

118 lines
3.6 KiB
Rust

use clap::Parser;
use std::path::PathBuf;
use std::process::Command;
use axum::{Extension, Router, routing::any};
use tokio::net::TcpListener;
use dav_server::{DavHandler, localfs::LocalFs, fakels::FakeLs};
#[derive(Parser)]
struct Args {
#[arg(short, long, default_value = "4932")]
port: u16,
#[arg(long, default_value = "data/raid_simple.sparseimage")]
vdisk_path: PathBuf,
#[arg(long, default_value = "RAID_AUTO")]
mount_name: String,
}
fn main() {
tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap()
.block_on(async_main());
}
async fn async_main() {
let args = Args::parse();
println!("=== RAID WebDAV Server (Auto-Mount) ===");
println!("Port: {}", args.port);
println!("VDisk: {}", args.vdisk_path.display());
println!("Mount Name: {}", args.mount_name);
println!("");
if !args.vdisk_path.exists() {
eprintln!("Error: Virtual disk not found at {}", args.vdisk_path.display());
return;
}
println!("Step 1: Check if already mounted...");
let mount_point = check_or_mount(&args.vdisk_path, &args.mount_name);
println!("Step 2: Verify mount point...");
if !mount_point.exists() {
eprintln!("Error: Mount point does not exist: {}", mount_point.display());
return;
}
println!("✅ Mounted at: {}", mount_point.display());
println!("");
println!("Step 3: Starting WebDAV server...");
let dav = DavHandler::builder()
.filesystem(LocalFs::new(mount_point.to_string_lossy().to_string(), false, false, false))
.locksystem(FakeLs::new())
.strip_prefix("/webdav")
.build_handler();
let addr = format!("127.0.0.1:{}", args.port);
let listener = TcpListener::bind(&addr).await.unwrap();
let router = Router::new()
.route("/webdav", any(handle_dav))
.route("/webdav/", any(handle_dav))
.route("/webdav/{*path}", any(handle_dav))
.layer(Extension(dav));
println!("Listening on: http://{}", addr);
println!("Mount with Finder:");
println!(" Cmd+K → http://localhost:{}/webdav", args.port);
println!(" Guest/Guest or blank password");
println!("");
println!("Press Ctrl+C to stop...");
axum::serve(listener, router).await.unwrap();
}
fn check_or_mount(vdisk_path: &PathBuf, mount_name: &str) -> PathBuf {
let expected_mount = PathBuf::from("/Volumes").join(mount_name);
if expected_mount.exists() {
println!("✅ Already mounted at: {}", expected_mount.display());
return expected_mount;
}
println!("Mounting sparseimage...");
let output = Command::new("hdiutil")
.args(&["attach", "-nobrowse"])
.arg(vdisk_path)
.output()
.expect("Failed to mount sparseimage");
if !output.status.success() {
eprintln!("Mount failed: {}", String::from_utf8_lossy(&output.stderr));
return expected_mount;
}
println!("Mount output: {}", String::from_utf8_lossy(&output.stdout));
let mount_output = String::from_utf8_lossy(&output.stdout);
for line in mount_output.lines() {
if line.contains("/Volumes/") {
let parts: Vec<&str> = line.split_whitespace().collect();
if let Some(mount_path) = parts.last() {
println!("✅ Mounted at: {}", mount_path);
return PathBuf::from(mount_path);
}
}
}
expected_mount
}
async fn handle_dav(Extension(dav): Extension<dav_server::DavHandler>, req: axum::extract::Request) -> impl axum::response::IntoResponse {
dav.handle(req).await
}