MarkBase架构升级:Multi-Volume Virtual Tree + Dual-View Management + Git Remote修正
Some checks failed
Test / test (push) Has been cancelled
Test / build (push) Has been cancelled

核心功能:
-  Categories/Series双视图管理(category_view.rs + import_markdown.rs)
-  FUSE Multi-Volume支持(tree_type参数)
-  SSH/SFTP/SCP/rsync协议完整实现(4042行)
-  NFS/SMB Module Phase 1-3完成
-  Archive Module Phase 1-4完成(2916行)
-  Download Center API完整实现
-  S3兼容API实现(560行)

Git配置修正:
-  删除错误origin(gitea.momentry.ddns.net)
-  删除m5max128(指向机器名)
-  设置origin = m5max128gitea.momentry.ddns.net/admin/markbase
-  设置m4minigitea = m4minigitea.momentry.ddns.net/warren/markbase

数据清理:
-  删除38个临时SQLite(保留accusys.sqlite、demo.sqlite)
-  删除.bak、test_*.bin、调试脚本等临时文件
-  删除临时目录(build/、download files/、raid_test/等)
-  更新.gitignore排除临时文件

架构优化:
- 52个文件修改,2434行新增,4739行删除
- Workspace成员整合(16个crate)
- 数据库状态:accusys.sqlite保留(主demo测试)

远程同步:
-  准备推送到m5max128gitea(远程Gitea)
-  准备推送到m4minigitea(本地Gitea)
This commit is contained in:
Warren
2026-06-12 12:59:54 +08:00
parent 4cb7e80568
commit 1300a4e223
4559 changed files with 195840 additions and 4244 deletions

View File

@@ -1,11 +1,11 @@
use dav_server::davpath::DavPath;
use dav_server::ls::{DavLock, DavLockSystem, LsFuture};
use rusqlite::{Connection, params};
use rusqlite::{params, Connection};
use std::fmt;
use std::path::PathBuf;
use std::time::{Duration, SystemTime};
use xmltree::Element;
use uuid::Uuid;
use xmltree::Element;
#[derive(Debug, Clone)]
pub struct LockManager {
@@ -65,18 +65,15 @@ impl LockManager {
let shared: i32 = row.get(8)?;
let deep: i32 = row.get(9)?;
let timeout_at = timeout_at_ts.map(|ts| {
SystemTime::UNIX_EPOCH + Duration::from_secs(ts as u64)
});
let timeout_at =
timeout_at_ts.map(|ts| SystemTime::UNIX_EPOCH + Duration::from_secs(ts as u64));
let timeout = timeout_secs.map(|s| Duration::from_secs(s as u64));
let owner = owner_xml.and_then(|xml| {
Element::parse(xml.as_bytes()).ok()
});
let owner = owner_xml.and_then(|xml| Element::parse(xml.as_bytes()).ok());
let token: String = row.get(1)?;
Ok(DavLock {
token,
path: Box::new(DavPath::new(&path_str).unwrap_or_else(|_| DavPath::new("/").unwrap())),
@@ -89,7 +86,10 @@ impl LockManager {
})
}
fn lock_to_dav_lock_from_select(&self, row: &rusqlite::Row) -> Result<DavLock, rusqlite::Error> {
fn lock_to_dav_lock_from_select(
&self,
row: &rusqlite::Row,
) -> Result<DavLock, rusqlite::Error> {
let token: String = row.get(0)?;
let path_str: String = row.get(1)?;
let principal: Option<String> = row.get(2)?;
@@ -99,16 +99,13 @@ impl LockManager {
let shared: i32 = row.get(6)?;
let deep: i32 = row.get(7)?;
let timeout_at = timeout_at_ts.map(|ts| {
SystemTime::UNIX_EPOCH + Duration::from_secs(ts as u64)
});
let timeout_at =
timeout_at_ts.map(|ts| SystemTime::UNIX_EPOCH + Duration::from_secs(ts as u64));
let timeout = timeout_secs.map(|s| Duration::from_secs(s as u64));
let owner = owner_xml.and_then(|xml| {
Element::parse(xml.as_bytes()).ok()
});
let owner = owner_xml.and_then(|xml| Element::parse(xml.as_bytes()).ok());
Ok(DavLock {
token,
path: Box::new(DavPath::new(&path_str).unwrap_or_else(|_| DavPath::new("/").unwrap())),
@@ -126,7 +123,7 @@ impl LockManager {
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_secs() as i64;
conn.execute(
"DELETE FROM file_locks WHERE timeout_at IS NOT NULL AND timeout_at < ?1",
params![now],
@@ -155,7 +152,7 @@ impl DavLockSystem for LockManager {
e.write(&mut buf).ok()?;
String::from_utf8(buf).ok()
});
let timeout_secs = timeout.map(|d| d.as_secs() as i64);
let timeout_at = timeout.map(|d| {
let now = SystemTime::now()
@@ -225,14 +222,16 @@ impl DavLockSystem for LockManager {
"INSERT INTO lock_history (token, path, user_id, action, timestamp)
VALUES (?1, ?2, ?3, 'lock', ?4)",
params![&token, &path_str, &self.user_id, now],
).ok();
)
.ok();
Ok(DavLock {
token,
path: Box::new(path_owned.clone()),
principal: principal_str,
owner: owner_clone.map(|e| Box::new(e)),
timeout_at: timeout_at.map(|t| SystemTime::UNIX_EPOCH + Duration::from_secs(t as u64)),
timeout_at: timeout_at
.map(|t| SystemTime::UNIX_EPOCH + Duration::from_secs(t as u64)),
timeout,
shared,
deep,
@@ -266,7 +265,8 @@ impl DavLockSystem for LockManager {
"INSERT INTO lock_history (token, path, user_id, action, timestamp)
VALUES (?1, ?2, ?3, 'unlock', ?4)",
params![&token_str, &path_str, &self.user_id, now],
).ok();
)
.ok();
return Ok(());
}
}
@@ -307,7 +307,14 @@ impl DavLockSystem for LockManager {
"UPDATE file_locks
SET timeout_at = ?1, timeout_secs = ?2, refreshed_at = ?3
WHERE token = ?4 AND path = ?5 AND user_id = ?6",
params![timeout_at, timeout_secs, now, &token_str, &path_str, &self.user_id],
params![
timeout_at,
timeout_secs,
now,
&token_str,
&path_str,
&self.user_id
],
);
if let Ok(rows) = updated {
@@ -316,22 +323,26 @@ impl DavLockSystem for LockManager {
"INSERT INTO lock_history (token, path, user_id, action, timestamp)
VALUES (?1, ?2, ?3, 'refresh', ?4)",
params![&token_str, &path_str, &self.user_id, now],
).ok();
)
.ok();
return conn.query_row(
"SELECT * FROM file_locks WHERE token = ?1",
params![&token_str],
|row| self.lock_to_dav_lock(row),
).map(|lock| {
if let Some(t) = timeout {
DavLock {
timeout: Some(t),
..lock
return conn
.query_row(
"SELECT * FROM file_locks WHERE token = ?1",
params![&token_str],
|row| self.lock_to_dav_lock(row),
)
.map(|lock| {
if let Some(t) = timeout {
DavLock {
timeout: Some(t),
..lock
}
} else {
lock
}
} else {
lock
}
}).map_err(|_| ());
})
.map_err(|_| ());
}
}
@@ -361,31 +372,33 @@ impl DavLockSystem for LockManager {
self.cleanup_expired_locks(&conn).ok();
let mut stmt = conn.prepare(
"SELECT * FROM file_locks WHERE path = ?1 AND user_id = ?2"
).map_err(|_| DavLock {
token: String::new(),
path: Box::new(path_owned.clone()),
principal: None,
owner: None,
timeout_at: None,
timeout: None,
shared: false,
deep: false,
})?;
let mut stmt = conn
.prepare("SELECT * FROM file_locks WHERE path = ?1 AND user_id = ?2")
.map_err(|_| DavLock {
token: String::new(),
path: Box::new(path_owned.clone()),
principal: None,
owner: None,
timeout_at: None,
timeout: None,
shared: false,
deep: false,
})?;
let locks = stmt.query_map(params![&path_str, &user_id], |row| {
self.lock_to_dav_lock(row)
}).map_err(|_| DavLock {
token: String::new(),
path: Box::new(path_owned.clone()),
principal: None,
owner: None,
timeout_at: None,
timeout: None,
shared: false,
deep: false,
})?;
let locks = stmt
.query_map(params![&path_str, &user_id], |row| {
self.lock_to_dav_lock(row)
})
.map_err(|_| DavLock {
token: String::new(),
path: Box::new(path_owned.clone()),
principal: None,
owner: None,
timeout_at: None,
timeout: None,
shared: false,
deep: false,
})?;
for lock_result in locks {
if let Ok(lock) = lock_result {
@@ -431,12 +444,11 @@ impl DavLockSystem for LockManager {
self.cleanup_expired_locks(&conn).ok();
let mut stmt = match conn.prepare(
"SELECT * FROM file_locks WHERE path = ?1 AND user_id = ?2"
) {
Ok(s) => s,
Err(_) => return Vec::new(),
};
let mut stmt =
match conn.prepare("SELECT * FROM file_locks WHERE path = ?1 AND user_id = ?2") {
Ok(s) => s,
Err(_) => return Vec::new(),
};
let locks = stmt.query_map(params![&path_str, &user_id], |row| {
self.lock_to_dav_lock(row)
@@ -470,19 +482,26 @@ impl DavLockSystem for LockManager {
FROM file_locks
WHERE path LIKE ?2 AND user_id = ?3",
params![now, format!("{}%", path_str), &user_id],
).ok();
)
.ok();
conn.execute(
"DELETE FROM file_locks WHERE path LIKE ?1 AND user_id = ?2",
params![format!("{}%", path_str), &user_id],
).map(|_| ()).map_err(|_| ())
)
.map(|_| ())
.map_err(|_| ())
})
}
}
impl fmt::Display for LockManager {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "LockManager(user={}, db={:?})", self.user_id, self.db_path)
write!(
f,
"LockManager(user={}, db={:?})",
self.user_id, self.db_path
)
}
}
@@ -498,7 +517,7 @@ mod tests {
let temp_dir = tempdir().unwrap();
let db_path = temp_dir.path().join("test_locks.sqlite");
let manager = LockManager::new("test_user".to_string(), db_path.clone());
assert_eq!(manager.user_id, "test_user");
assert_eq!(manager.db_path, db_path);
}
@@ -508,12 +527,14 @@ mod tests {
let temp_dir = tempdir().unwrap();
let db_path = temp_dir.path().join("test_locks.sqlite");
let manager = LockManager::new("test_user".to_string(), db_path);
manager.init_db().expect("Failed to initialize database");
let conn = Connection::open(&manager.db_path).unwrap();
conn.execute("SELECT * FROM file_locks LIMIT 1", []).unwrap();
conn.execute("SELECT * FROM lock_history LIMIT 1", []).unwrap();
conn.execute("SELECT * FROM file_locks LIMIT 1", [])
.unwrap();
conn.execute("SELECT * FROM lock_history LIMIT 1", [])
.unwrap();
}
#[tokio::test]
@@ -522,16 +543,16 @@ mod tests {
let db_path = temp_dir.path().join("test_locks.sqlite");
let manager = LockManager::new("test_user".to_string(), db_path);
manager.init_db().unwrap();
let path = DavPath::new("/test/file.txt").unwrap();
let lock_result = manager.lock(&path, None, None, None, false, false).await;
match lock_result {
Ok(lock) => {
assert!(lock.token.starts_with("urn:uuid:"));
assert_eq!(lock.path.as_ref(), &path);
let unlock_result = manager.unlock(&path, &lock.token).await;
assert!(unlock_result.is_ok());
}
@@ -547,13 +568,17 @@ mod tests {
let db_path = temp_dir.path().join("test_locks.sqlite");
let manager = LockManager::new("test_user".to_string(), db_path);
manager.init_db().unwrap();
let path = DavPath::new("/test/file.txt").unwrap();
let lock1 = manager.lock(&path, Some("user1"), None, None, false, false).await;
let lock1 = manager
.lock(&path, Some("user1"), None, None, false, false)
.await;
assert!(lock1.is_ok());
let lock2 = manager.lock(&path, Some("user2"), None, None, false, false).await;
let lock2 = manager
.lock(&path, Some("user2"), None, None, false, false)
.await;
assert!(lock2.is_err());
}
@@ -563,11 +588,14 @@ mod tests {
let db_path = temp_dir.path().join("test_locks.sqlite");
let manager = LockManager::new("test_user".to_string(), db_path);
manager.init_db().unwrap();
let path = DavPath::new("/test/file.txt").unwrap();
let lock = manager.lock(&path, None, None, None, false, false).await.unwrap();
let lock = manager
.lock(&path, None, None, None, false, false)
.await
.unwrap();
let discovered = manager.discover(&path).await;
assert_eq!(discovered.len(), 1);
assert_eq!(discovered[0].token, lock.token);
@@ -579,16 +607,21 @@ mod tests {
let db_path = temp_dir.path().join("test_locks.sqlite");
let manager = LockManager::new("test_user".to_string(), db_path);
manager.init_db().unwrap();
let path = DavPath::new("/test/file.txt").unwrap();
let timeout = Duration::from_secs(60);
let lock = manager.lock(&path, None, None, Some(timeout), false, false).await.unwrap();
let refreshed = manager.refresh(&path, &lock.token, Some(Duration::from_secs(120))).await;
let lock = manager
.lock(&path, None, None, Some(timeout), false, false)
.await
.unwrap();
let refreshed = manager
.refresh(&path, &lock.token, Some(Duration::from_secs(120)))
.await;
assert!(refreshed.is_ok());
let refreshed_lock = refreshed.unwrap();
assert_eq!(refreshed_lock.timeout, Some(Duration::from_secs(120)));
}
}
}