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,6 +1,6 @@
use crate::sync::{PgAdmin, PgGroup, PgUser, PgUserGroupMapping};
use anyhow::Result;
use tokio_postgres::{NoTls, Client};
use crate::sync::{PgUser, PgGroup, PgUserGroupMapping, PgAdmin};
use tokio_postgres::{Client, NoTls};
pub struct PgClient {
host: String,
@@ -20,7 +20,7 @@ impl PgClient {
database: "sftpgo".to_string(),
}
}
pub fn from_env() -> Self {
Self {
host: std::env::var("PG_HOST").unwrap_or_else(|_| "127.0.0.1".to_string()),
@@ -31,39 +31,40 @@ impl PgClient {
user: std::env::var("PG_USER").unwrap_or_else(|_| "sftpgo".to_string()),
password: std::env::var("PG_PASSWORD")
.unwrap_or_else(|_| "sftpgo_pass_2026".to_string()),
database: std::env::var("PG_DATABASE")
.unwrap_or_else(|_| "sftpgo".to_string()),
database: std::env::var("PG_DATABASE").unwrap_or_else(|_| "sftpgo".to_string()),
}
}
pub async fn connect(&self) -> Result<Client> {
let config = format!(
"host={} port={} user={} password={} dbname={}",
self.host, self.port, self.user, self.password, self.database
);
let (client, connection) = tokio_postgres::connect(&config, NoTls).await?;
tokio::spawn(async move {
if let Err(e) = connection.await {
log::error!("PostgreSQL connection error: {}", e);
}
});
Ok(client)
}
pub async fn fetch_users(&self) -> Result<Vec<PgUser>> {
let client = self.connect().await?;
let rows = client.query(
"SELECT username, password, email, status, home_dir, permissions,
let rows = client
.query(
"SELECT username, password, email, status, home_dir, permissions,
uid, gid, last_login, created_at, updated_at
FROM users
WHERE status = 1 AND deleted_at = 0",
&[]
).await?;
&[],
)
.await?;
let users = rows
.into_iter()
.map(|row| PgUser {
@@ -80,18 +81,20 @@ impl PgClient {
updated_at: row.get::<_, i64>(10),
})
.collect();
Ok(users)
}
pub async fn fetch_groups(&self) -> Result<Vec<PgGroup>> {
let client = self.connect().await?;
let rows = client.query(
"SELECT name, description, created_at, updated_at FROM groups",
&[]
).await?;
let rows = client
.query(
"SELECT name, description, created_at, updated_at FROM groups",
&[],
)
.await?;
let groups = rows
.into_iter()
.map(|row| PgGroup {
@@ -101,13 +104,13 @@ impl PgClient {
updated_at: row.get::<_, i64>(3),
})
.collect();
Ok(groups)
}
pub async fn fetch_admins(&self) -> Result<Vec<PgAdmin>> {
let client = self.connect().await?;
let rows = client
.query(
"SELECT username, password, email, description, status,
@@ -117,7 +120,7 @@ impl PgClient {
&[],
)
.await?;
let admins = rows
.into_iter()
.map(|row| PgAdmin {
@@ -134,22 +137,24 @@ impl PgClient {
updated_at: row.get::<_, i64>(10),
})
.collect();
Ok(admins)
}
pub async fn fetch_mappings(&self) -> Result<Vec<PgUserGroupMapping>> {
let client = self.connect().await?;
let rows = client.query(
"SELECT u.username, g.name
let rows = client
.query(
"SELECT u.username, g.name
FROM users_groups_mapping ug
JOIN users u ON ug.user_id = u.id
JOIN groups g ON ug.group_id = g.id
WHERE u.status = 1",
&[]
).await?;
&[],
)
.await?;
let mappings = rows
.into_iter()
.map(|row| PgUserGroupMapping {
@@ -157,7 +162,7 @@ impl PgClient {
group_name: row.get::<_, String>(1),
})
.collect();
Ok(mappings)
}
}
@@ -174,14 +179,14 @@ impl SftpGoSync {
auth_db: crate::sync::AuthDb::new(auth_db_path)?,
})
}
pub async fn full_sync(&self) -> Result<crate::sync::SyncResult> {
let mut result = crate::sync::SyncResult::default();
result.sync_type = "full".to_string();
result.sync_time = chrono::Utc::now().timestamp();
log::info!("Starting full sync from SFTPGo PostgreSQL");
// 1. Sync users
match self.pg_client.fetch_users().await {
Ok(users) => {
@@ -191,7 +196,9 @@ impl SftpGoSync {
Ok(_) => result.users_synced += 1,
Err(e) => {
result.users_failed += 1;
result.errors.push(format!("User {} sync failed: {}", user.username, e));
result
.errors
.push(format!("User {} sync failed: {}", user.username, e));
log::error!("Failed to sync user {}: {}", user.username, e);
}
}
@@ -203,7 +210,7 @@ impl SftpGoSync {
result.users_failed = 1;
}
}
// 2. Sync groups
match self.pg_client.fetch_groups().await {
Ok(groups) => {
@@ -213,7 +220,9 @@ impl SftpGoSync {
Ok(_) => result.groups_synced += 1,
Err(e) => {
result.groups_failed += 1;
result.errors.push(format!("Group {} sync failed: {}", group.name, e));
result
.errors
.push(format!("Group {} sync failed: {}", group.name, e));
log::error!("Failed to sync group {}: {}", group.name, e);
}
}
@@ -225,7 +234,7 @@ impl SftpGoSync {
result.groups_failed = 1;
}
}
// 3. Sync mappings
match self.pg_client.fetch_mappings().await {
Ok(mappings) => {
@@ -241,7 +250,9 @@ impl SftpGoSync {
));
log::error!(
"Failed to sync mapping {}->{}: {}",
mapping.username, mapping.group_name, e
mapping.username,
mapping.group_name,
e
);
}
}
@@ -249,11 +260,13 @@ impl SftpGoSync {
}
Err(e) => {
log::error!("Failed to fetch mappings from PostgreSQL: {}", e);
result.errors.push(format!("PG mappings fetch failed: {}", e));
result
.errors
.push(format!("PG mappings fetch failed: {}", e));
result.mappings_failed = 1;
}
}
// 4. Sync admins
match self.pg_client.fetch_admins().await {
Ok(admins) => {
@@ -274,10 +287,18 @@ impl SftpGoSync {
result.admins_failed = 1;
}
}
// 5. Determine final status
if result.users_failed > 0 || result.groups_failed > 0 || result.mappings_failed > 0 || result.admins_failed > 0 {
if result.users_synced > 0 || result.groups_synced > 0 || result.mappings_synced > 0 || result.admins_synced > 0 {
if result.users_failed > 0
|| result.groups_failed > 0
|| result.mappings_failed > 0
|| result.admins_failed > 0
{
if result.users_synced > 0
|| result.groups_synced > 0
|| result.mappings_synced > 0
|| result.admins_synced > 0
{
result.status = "partial_success".to_string();
} else {
result.status = "cached".to_string();
@@ -285,10 +306,10 @@ impl SftpGoSync {
} else {
result.status = "success".to_string();
}
// 6. Save sync log
self.auth_db.save_sync_log(&result)?;
log::info!(
"Sync completed: users={}, groups={}, mappings={}, admins={}, status={}",
result.users_synced,
@@ -297,7 +318,7 @@ impl SftpGoSync {
result.admins_synced,
result.status
);
Ok(result)
}
}
}