MarkBase架构升级:Multi-Volume Virtual Tree + Dual-View Management + Git Remote修正
核心功能: - ✅ 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:
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user