Session修改:Mutex死锁修复+AGENTS更新
This commit is contained in:
@@ -142,12 +142,14 @@ mod warren_tests {
|
||||
fn test_warren_query_root() {
|
||||
let fs = MarkBaseFS::new("warren", "data/users/warren.sqlite");
|
||||
|
||||
let conn = fs.sqlite.lock().unwrap();
|
||||
let root_id: String = conn.query_row(
|
||||
"SELECT node_id FROM file_nodes WHERE parent_id IS NULL LIMIT 1",
|
||||
[],
|
||||
|row| row.get(0)
|
||||
).unwrap();
|
||||
let root_id: String = {
|
||||
let conn = fs.sqlite.lock().unwrap();
|
||||
conn.query_row(
|
||||
"SELECT node_id FROM file_nodes WHERE parent_id IS NULL LIMIT 1",
|
||||
[],
|
||||
|row| row.get(0)
|
||||
).unwrap()
|
||||
};
|
||||
|
||||
let root = fs.query_node(&root_id);
|
||||
assert!(root.is_some());
|
||||
@@ -161,12 +163,14 @@ mod warren_tests {
|
||||
fn test_warren_query_children() {
|
||||
let fs = MarkBaseFS::new("warren", "data/users/warren.sqlite");
|
||||
|
||||
let conn = fs.sqlite.lock().unwrap();
|
||||
let root_id: String = conn.query_row(
|
||||
"SELECT node_id FROM file_nodes WHERE parent_id IS NULL LIMIT 1",
|
||||
[],
|
||||
|row| row.get(0)
|
||||
).unwrap();
|
||||
let root_id: String = {
|
||||
let conn = fs.sqlite.lock().unwrap();
|
||||
conn.query_row(
|
||||
"SELECT node_id FROM file_nodes WHERE parent_id IS NULL LIMIT 1",
|
||||
[],
|
||||
|row| row.get(0)
|
||||
).unwrap()
|
||||
};
|
||||
|
||||
let children = fs.query_children(&root_id);
|
||||
|
||||
@@ -178,25 +182,26 @@ mod warren_tests {
|
||||
println!("Root children: {} folders, {} files", folders, files);
|
||||
|
||||
assert!(folders > 0);
|
||||
assert!(files >= 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_warren_read_text_file() {
|
||||
let fs = MarkBaseFS::new("warren", "data/users/warren.sqlite");
|
||||
|
||||
let conn = fs.sqlite.lock().unwrap();
|
||||
let result = conn.query_row(
|
||||
"SELECT node_id, aliases_json FROM file_nodes
|
||||
WHERE node_type = 'file'
|
||||
AND aliases_json IS NOT NULL
|
||||
AND file_size < 1000
|
||||
LIMIT 1",
|
||||
[],
|
||||
|row| Ok((row.get::<_, String>(0)?, row.get::<_, String>(1)?))
|
||||
);
|
||||
let result = {
|
||||
let conn = fs.sqlite.lock().unwrap();
|
||||
conn.query_row(
|
||||
"SELECT node_id, aliases_json FROM file_nodes
|
||||
WHERE node_type = 'file'
|
||||
AND aliases_json IS NOT NULL
|
||||
AND file_size < 1000
|
||||
LIMIT 1",
|
||||
[],
|
||||
|row| Ok((row.get::<_, String>(0)?, row.get::<_, String>(1)?))
|
||||
).ok()
|
||||
};
|
||||
|
||||
if let Ok((node_id, aliases_json)) = result {
|
||||
if let Some((node_id, aliases_json)) = result {
|
||||
let aliases: serde_json::Value = serde_json::from_str(&aliases_json).unwrap();
|
||||
let path = aliases["path"].as_str().unwrap_or_default();
|
||||
|
||||
|
||||
@@ -3,8 +3,15 @@ pub mod auth;
|
||||
pub mod command;
|
||||
pub mod config;
|
||||
pub mod filetree;
|
||||
pub mod fskit;
|
||||
pub mod fuse;
|
||||
pub mod nfs;
|
||||
pub mod pg_client;
|
||||
pub mod raid;
|
||||
pub mod render;
|
||||
pub mod scan;
|
||||
pub mod server;
|
||||
pub mod sync;
|
||||
pub mod webdav;
|
||||
|
||||
pub use filetree::node::FileNode;
|
||||
64
src/main.rs
64
src/main.rs
@@ -111,6 +111,9 @@ async fn main() -> anyhow::Result<()> {
|
||||
Commands::Hash { user, threads } => {
|
||||
markbase::scan::compute_hashes(&user, threads)?;
|
||||
}
|
||||
Commands::WebDAV { action } => {
|
||||
handle_webdav_command(action)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -208,3 +211,64 @@ fn show_section(config: &markbase::config::MarkBaseConfig, section: &str) {
|
||||
_ => println!("Invalid section: {}. Valid sections: server, postgresql, authentication, test, logging", section),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_webdav_command(action: WebDAVCommands) -> anyhow::Result<()> {
|
||||
match action {
|
||||
WebDAVCommands::Start { port, user } => {
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use markbase::webdav::MarkBaseWebDAV;
|
||||
use markbase::filetree::FileTree;
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
let db_path = PathBuf::from(FileTree::user_db_path(&user));
|
||||
|
||||
if !db_path.exists() {
|
||||
return Err(anyhow::anyhow!("User database not found: {}", db_path.display()));
|
||||
}
|
||||
|
||||
println!("=== MarkBase WebDAV Server ===");
|
||||
println!("User: {}", user);
|
||||
println!("Port: {}", port);
|
||||
println!("Database: {}", db_path.display());
|
||||
println!("");
|
||||
|
||||
let webdav = MarkBaseWebDAV::new(user.clone(), db_path);
|
||||
let dav_handler = webdav.create_handler();
|
||||
|
||||
let addr = format!("127.0.0.1:{}", port);
|
||||
|
||||
println!("Listening on: {}", addr);
|
||||
println!("Mount with Finder:");
|
||||
println!(" Connect to Server → http://localhost:{}/webdav", port);
|
||||
println!("");
|
||||
println!("Press Ctrl+C to stop...");
|
||||
|
||||
tokio::spawn(async move {
|
||||
use axum::{Router, Extension, routing::any};
|
||||
|
||||
let app = Router::new()
|
||||
.route("/webdav/*path", any(|req: axum::http::Request<axum::body::Body>, Extension(h): Extension<Arc<dav_server::DavHandler>>| async move {
|
||||
use http_body_util::BodyExt;
|
||||
let body = req.into_body().collect().await.unwrap().to_bytes();
|
||||
let req = http::Request::new(body);
|
||||
h.handle(req).await
|
||||
}))
|
||||
.route("/webdav", any(|req: axum::http::Request<axum::body::Body>, Extension(h): Extension<Arc<dav_server::DavHandler>>| async move {
|
||||
use http_body_util::BodyExt;
|
||||
let body = req.into_body().collect().await.unwrap().to_bytes();
|
||||
let req = http::Request::new(body);
|
||||
h.handle(req).await
|
||||
}))
|
||||
.layer(Extension(dav_handler));
|
||||
|
||||
let listener = TcpListener::bind(&addr).await.unwrap();
|
||||
axum::serve(listener, app).await.unwrap();
|
||||
});
|
||||
|
||||
tokio::signal::ctrl_c().await?;
|
||||
println!("\nShutting down...");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -377,7 +377,7 @@ fn compute_hashes_parallel(user_id: &str, file_info: Vec<(String, String)>, thre
|
||||
let file_info = Arc::clone(&file_info);
|
||||
let results = Arc::clone(&results);
|
||||
let processed = Arc::clone(&processed);
|
||||
let user_id = user_id.clone();
|
||||
let _user_id = user_id.clone();
|
||||
|
||||
let handle = thread::spawn(move || {
|
||||
let chunk_size = (file_info.len() / threads) + (if i < file_info.len() % threads { 1 } else { 0 });
|
||||
|
||||
@@ -1275,7 +1275,7 @@ async fn stream_file(
|
||||
}
|
||||
|
||||
async fn get_file_probe(
|
||||
Path((user_id, file_uuid)): Path<(String, String)>,
|
||||
Path((_user_id, file_uuid)): Path<(String, String)>,
|
||||
) -> impl IntoResponse {
|
||||
let result = tokio::task::spawn_blocking(move || -> anyhow::Result<serde_json::Value> {
|
||||
let conn = FileTree::open_user_db("demo")?;
|
||||
|
||||
Reference in New Issue
Block a user