Fix code quality: trailing whitespace, unused imports, clippy warnings

- Fix trailing whitespace in kex.rs and s3.rs
- Add missing KexProposal import in kex_complete.rs
- Auto-fix clippy warnings across all crates
- All 153 tests pass
This commit is contained in:
Warren
2026-06-19 05:21:38 +08:00
parent 4b37e524cf
commit d94cb2df4c
135 changed files with 7256 additions and 4321 deletions

View File

@@ -25,7 +25,7 @@ pub async fn handle_iscsi_command(cmd: IscsiCommand) -> anyhow::Result<()> {
let binary = find_binary("markbase-iscsi");
let mut cmd_process = std::process::Command::new(&binary);
cmd_process.arg("iscsi");
match cmd {
IscsiCommand::Start {
user,
@@ -34,7 +34,8 @@ pub async fn handle_iscsi_command(cmd: IscsiCommand) -> anyhow::Result<()> {
force,
device,
} => {
cmd_process.arg("start")
cmd_process
.arg("start")
.args(["--user", &user])
.args(["--port", &port.to_string()])
.args(["--lun-size", &lun_size]);
@@ -52,7 +53,7 @@ pub async fn handle_iscsi_command(cmd: IscsiCommand) -> anyhow::Result<()> {
cmd_process.arg("status");
}
}
let status = cmd_process.status()?;
std::process::exit(status.code().unwrap_or(1));
}
@@ -61,4 +62,4 @@ fn find_binary(name: &str) -> std::path::PathBuf {
let exe = std::env::current_exe().unwrap();
let dir = exe.parent().unwrap();
dir.join(name)
}
}

View File

@@ -1,8 +1,8 @@
pub mod web;
pub mod ssh;
pub mod webdav;
pub mod iscsi;
pub mod ssh;
pub mod tree;
pub mod web;
pub mod webdav;
use clap::Subcommand;
@@ -29,4 +29,4 @@ pub async fn handle_interface_command(cmd: InterfaceCommands) -> anyhow::Result<
InterfaceCommands::Tree(c) => tree::handle_tree_command(c).await?,
}
Ok(())
}
}

View File

@@ -32,4 +32,4 @@ pub async fn handle_ssh_command(cmd: SshCommand) -> anyhow::Result<()> {
}
}
Ok(())
}
}

View File

@@ -1,6 +1,6 @@
use anyhow::Context;
use clap::Subcommand;
use rusqlite::Connection;
use anyhow::Context;
use uuid::Uuid;
#[derive(Subcommand)]
@@ -33,12 +33,12 @@ pub enum TreeCommand {
#[arg(short, long)]
name: String,
},
Folder {
#[command(subcommand)]
action: FolderCommand,
},
Ls {
#[arg(short, long)]
user: String,
@@ -47,7 +47,7 @@ pub enum TreeCommand {
#[arg(short, long)]
tree_type: String,
},
Cp {
#[arg(short, long)]
user: String,
@@ -58,7 +58,7 @@ pub enum TreeCommand {
#[arg(short, long)]
tree_type: String,
},
Mv {
#[arg(short, long)]
user: String,
@@ -113,44 +113,54 @@ pub enum FolderCommand {
pub async fn handle_tree_command(cmd: TreeCommand) -> anyhow::Result<()> {
match cmd {
TreeCommand::Create { name, user, tree_type } => {
TreeCommand::Create {
name,
user,
tree_type,
} => {
let db_path = format!("data/users/{}.sqlite", user);
let conn = Connection::open(&db_path)
.with_context(|| format!("Failed to open database: {}", db_path))?;
let node_id = Uuid::new_v4().to_string();
let created_at = chrono::Utc::now().to_rfc3339();
conn.execute(
"INSERT INTO file_nodes (node_id, label, node_type, tree_type, created_at, updated_at)
VALUES (?1, ?2, 'folder', ?3, ?4, ?4)",
rusqlite::params![node_id, name, tree_type, created_at]
).context("Failed to create tree")?;
println!("✓ Tree created: {} (type: {}) for user: {}", name, tree_type, user);
println!(
"✓ Tree created: {} (type: {}) for user: {}",
name, tree_type, user
);
println!("✓ Node ID: {}", node_id);
}
TreeCommand::List { user } => {
let db_path = format!("data/users/{}.sqlite", user);
let conn = Connection::open(&db_path)
.with_context(|| format!("Failed to open database: {}", db_path))?;
let mut stmt = conn.prepare(
"SELECT DISTINCT tree_type FROM file_nodes ORDER BY tree_type"
).context("Failed to prepare query")?;
let tree_types = stmt.query_map([], |row| row.get::<_, String>(0))
let mut stmt = conn
.prepare("SELECT DISTINCT tree_type FROM file_nodes ORDER BY tree_type")
.context("Failed to prepare query")?;
let tree_types = stmt
.query_map([], |row| row.get::<_, String>(0))
.context("Failed to query tree types")?;
println!("=== Trees for user: {} ===", user);
for tree_type in tree_types {
let tt = tree_type?;
let count: i64 = conn.query_row(
"SELECT COUNT(*) FROM file_nodes WHERE tree_type = ?1",
[&tt],
|row| row.get(0)
).unwrap_or(0);
let count: i64 = conn
.query_row(
"SELECT COUNT(*) FROM file_nodes WHERE tree_type = ?1",
[&tt],
|row| row.get(0),
)
.unwrap_or(0);
println!(" {} ({} nodes)", tt, count);
}
}
@@ -158,9 +168,9 @@ pub async fn handle_tree_command(cmd: TreeCommand) -> anyhow::Result<()> {
let db_path = format!("data/users/{}.sqlite", user);
let conn = Connection::open(&db_path)
.with_context(|| format!("Failed to open database: {}", db_path))?;
println!("Importing Markdown files to {} virtual tree...", tree_type);
if tree_type == "categories" {
crate::import_markdown::import_categories_to_db(&conn, &user, &tree_type)?;
println!("✓ Categories imported successfully!");
@@ -168,53 +178,66 @@ pub async fn handle_tree_command(cmd: TreeCommand) -> anyhow::Result<()> {
crate::import_markdown::import_series_to_db(&conn, &user, &tree_type)?;
println!("✓ Series imported successfully!");
} else {
eprintln!("Invalid tree_type: {}. Use 'categories' or 'series'", tree_type);
eprintln!(
"Invalid tree_type: {}. Use 'categories' or 'series'",
tree_type
);
}
}
TreeCommand::Delete { user, name } => {
let db_path = format!("data/users/{}.sqlite", user);
let conn = Connection::open(&db_path)
.with_context(|| format!("Failed to open database: {}", db_path))?;
conn.execute(
"DELETE FROM file_nodes WHERE label = ?1 AND node_type = 'folder'",
[&name]
).context("Failed to delete tree")?;
[&name],
)
.context("Failed to delete tree")?;
println!("✓ Tree deleted: {} for user: {}", name, user);
}
TreeCommand::Folder { action } => {
handle_folder_command(action)?;
}
TreeCommand::Ls { user, path, tree_type } => {
TreeCommand::Ls {
user,
path,
tree_type,
} => {
let db_path = format!("data/users/{}.sqlite", user);
let conn = Connection::open(&db_path)
.with_context(|| format!("Failed to open database: {}", db_path))?;
let parent_id = find_node_id(&conn, &path, &tree_type)?;
let mut stmt = conn.prepare(
"SELECT label, node_type, file_size FROM file_nodes
let mut stmt = conn
.prepare(
"SELECT label, node_type, file_size FROM file_nodes
WHERE parent_id = ?1 AND tree_type = ?2
ORDER BY node_type DESC, label ASC"
).context("Failed to prepare ls query")?;
let entries = stmt.query_map(
rusqlite::params![parent_id, tree_type],
|row| Ok((
row.get::<_, String>(0)?,
row.get::<_, String>(1)?,
row.get::<_, Option<i64>>(2)?
))
).context("Failed to query entries")?;
ORDER BY node_type DESC, label ASC",
)
.context("Failed to prepare ls query")?;
let entries = stmt
.query_map(rusqlite::params![parent_id, tree_type], |row| {
Ok((
row.get::<_, String>(0)?,
row.get::<_, String>(1)?,
row.get::<_, Option<i64>>(2)?,
))
})
.context("Failed to query entries")?;
println!("=== Contents of {} (tree_type: {}) ===", path, tree_type);
for entry in entries {
let (name, node_type, size) = entry?;
let size_str = size.map(|s| format!("{} bytes", s)).unwrap_or_else(|| "-".to_string());
let size_str = size
.map(|s| format!("{} bytes", s))
.unwrap_or_else(|| "-".to_string());
if node_type == "folder" {
println!(" 📁 {} ({})", name, size_str);
} else {
@@ -222,57 +245,72 @@ pub async fn handle_tree_command(cmd: TreeCommand) -> anyhow::Result<()> {
}
}
}
TreeCommand::Cp { user, source, target, tree_type } => {
TreeCommand::Cp {
user,
source,
target,
tree_type,
} => {
let db_path = format!("data/users/{}.sqlite", user);
let conn = Connection::open(&db_path)
.with_context(|| format!("Failed to open database: {}", db_path))?;
let source_id = find_node_id(&conn, &source, &tree_type)?;
let target_parent_id = find_node_id(&conn, &target, &tree_type)?;
let (label, node_type, aliases_json, file_uuid, sha256, file_size) = conn.query_row(
"SELECT label, node_type, aliases_json, file_uuid, sha256, file_size
let (label, node_type, aliases_json, file_uuid, sha256, file_size) = conn
.query_row(
"SELECT label, node_type, aliases_json, file_uuid, sha256, file_size
FROM file_nodes WHERE node_id = ?1",
[&source_id],
|row| Ok((
row.get::<_, String>(0)?,
row.get::<_, String>(1)?,
row.get::<_, String>(2)?,
row.get::<_, Option<String>>(3)?,
row.get::<_, Option<String>>(4)?,
row.get::<_, Option<i64>>(5)?
))
).context("Failed to get source node")?;
[&source_id],
|row| {
Ok((
row.get::<_, String>(0)?,
row.get::<_, String>(1)?,
row.get::<_, String>(2)?,
row.get::<_, Option<String>>(3)?,
row.get::<_, Option<String>>(4)?,
row.get::<_, Option<i64>>(5)?,
))
},
)
.context("Failed to get source node")?;
let new_id = Uuid::new_v4().to_string();
let created_at = chrono::Utc::now().to_rfc3339();
conn.execute(
"INSERT INTO file_nodes
(node_id, label, aliases_json, file_uuid, sha256, parent_id, node_type, file_size, tree_type, created_at, updated_at)
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?10)",
rusqlite::params![new_id, label, aliases_json, file_uuid, sha256, target_parent_id, node_type, file_size, tree_type, created_at]
).context("Failed to copy node")?;
println!("✓ Copied {} to {} (new ID: {})", source, target, new_id);
}
TreeCommand::Mv { user, source, target, tree_type } => {
TreeCommand::Mv {
user,
source,
target,
tree_type,
} => {
let db_path = format!("data/users/{}.sqlite", user);
let conn = Connection::open(&db_path)
.with_context(|| format!("Failed to open database: {}", db_path))?;
let source_id = find_node_id(&conn, &source, &tree_type)?;
let target_parent_id = find_node_id(&conn, &target, &tree_type)?;
let updated_at = chrono::Utc::now().to_rfc3339();
conn.execute(
"UPDATE file_nodes SET parent_id = ?1, updated_at = ?2 WHERE node_id = ?3",
rusqlite::params![target_parent_id, updated_at, source_id]
).context("Failed to move node")?;
rusqlite::params![target_parent_id, updated_at, source_id],
)
.context("Failed to move node")?;
println!("✓ Moved {} to {}", source, target);
}
}
@@ -281,104 +319,136 @@ pub async fn handle_tree_command(cmd: TreeCommand) -> anyhow::Result<()> {
fn handle_folder_command(cmd: FolderCommand) -> anyhow::Result<()> {
match cmd {
FolderCommand::Create { user, path, name, tree_type } => {
FolderCommand::Create {
user,
path,
name,
tree_type,
} => {
let db_path = format!("data/users/{}.sqlite", user);
let conn = Connection::open(&db_path)
.with_context(|| format!("Failed to open database: {}", db_path))?;
let parent_id = if path == "/" || path == "" {
let parent_id = if path == "/" || path.is_empty() {
None
} else {
Some(find_node_id(&conn, &path, &tree_type)?)
};
let node_id = Uuid::new_v4().to_string();
let created_at = chrono::Utc::now().to_rfc3339();
conn.execute(
"INSERT INTO file_nodes
(node_id, label, parent_id, node_type, tree_type, created_at, updated_at)
VALUES (?1, ?2, ?3, 'folder', ?4, ?5, ?5)",
rusqlite::params![node_id, name, parent_id, tree_type, created_at]
).context("Failed to create folder")?;
println!("✓ Folder created: {} in {} (tree_type: {})", name, path, tree_type);
rusqlite::params![node_id, name, parent_id, tree_type, created_at],
)
.context("Failed to create folder")?;
println!(
"✓ Folder created: {} in {} (tree_type: {})",
name, path, tree_type
);
println!("✓ Node ID: {}", node_id);
}
FolderCommand::Delete { user, path, name, tree_type } => {
FolderCommand::Delete {
user,
path,
name,
tree_type,
} => {
let db_path = format!("data/users/{}.sqlite", user);
let conn = Connection::open(&db_path)
.with_context(|| format!("Failed to open database: {}", db_path))?;
let folder_path = if path == "/" || path == "" {
let folder_path = if path == "/" || path.is_empty() {
name.clone()
} else {
format!("{}/{}", path, name)
};
let folder_id = find_node_id(&conn, &folder_path, &tree_type)?;
conn.execute(
"DELETE FROM file_nodes WHERE node_id = ?1 OR parent_id = ?1",
[&folder_id]
).context("Failed to delete folder and children")?;
println!("✓ Folder deleted: {} in {} (tree_type: {})", name, path, tree_type);
[&folder_id],
)
.context("Failed to delete folder and children")?;
println!(
"✓ Folder deleted: {} in {} (tree_type: {})",
name, path, tree_type
);
}
FolderCommand::Rename { user, path, old_name, new_name, tree_type } => {
FolderCommand::Rename {
user,
path,
old_name,
new_name,
tree_type,
} => {
let db_path = format!("data/users/{}.sqlite", user);
let conn = Connection::open(&db_path)
.with_context(|| format!("Failed to open database: {}", db_path))?;
let folder_path = if path == "/" || path == "" {
let folder_path = if path == "/" || path.is_empty() {
old_name.clone()
} else {
format!("{}/{}", path, old_name)
};
let folder_id = find_node_id(&conn, &folder_path, &tree_type)?;
let updated_at = chrono::Utc::now().to_rfc3339();
conn.execute(
"UPDATE file_nodes SET label = ?1, updated_at = ?2 WHERE node_id = ?3",
rusqlite::params![new_name, updated_at, folder_id]
).context("Failed to rename folder")?;
println!("✓ Folder renamed: {}{} in {} (tree_type: {})", old_name, new_name, path, tree_type);
rusqlite::params![new_name, updated_at, folder_id],
)
.context("Failed to rename folder")?;
println!(
"✓ Folder renamed: {}{} in {} (tree_type: {})",
old_name, new_name, path, tree_type
);
}
}
Ok(())
}
fn find_node_id(conn: &Connection, path: &str, tree_type: &str) -> anyhow::Result<String> {
if path == "/" || path == "" {
let node_id: String = conn.query_row(
"SELECT node_id FROM file_nodes
if path == "/" || path.is_empty() {
let node_id: String = conn
.query_row(
"SELECT node_id FROM file_nodes
WHERE parent_id IS NULL AND node_type = 'folder' AND tree_type = ?1
LIMIT 1",
[tree_type],
|row| row.get(0)
).context("Failed to find root folder")?;
[tree_type],
|row| row.get(0),
)
.context("Failed to find root folder")?;
return Ok(node_id);
}
let parts: Vec<&str> = path.split('/').filter(|s| !s.is_empty()).collect();
let mut current_parent: Option<String> = None;
for part in parts {
let node_id: String = conn.query_row(
"SELECT node_id FROM file_nodes
let node_id: String = conn
.query_row(
"SELECT node_id FROM file_nodes
WHERE label = ?1 AND tree_type = ?2 AND
(parent_id = ?3 OR (?3 IS NULL AND parent_id IS NULL))",
rusqlite::params![part, tree_type, current_parent],
|row| row.get(0)
).context(format!("Failed to find node: {}", part))?;
rusqlite::params![part, tree_type, current_parent],
|row| row.get(0),
)
.context(format!("Failed to find node: {}", part))?;
current_parent = Some(node_id);
}
current_parent.context("Failed to find node ID for path")
}
}

View File

@@ -18,4 +18,4 @@ pub async fn handle_web_command(cmd: WebCommand) -> anyhow::Result<()> {
}
}
Ok(())
}
}

View File

@@ -1,5 +1,5 @@
use clap::Subcommand;
use axum::{extract::Request, response::IntoResponse, Extension};
use clap::Subcommand;
#[derive(Subcommand)]
pub enum WebdavCommand {
@@ -28,7 +28,7 @@ pub async fn handle_webdav_command(cmd: WebdavCommand) -> anyhow::Result<()> {
println!("User: {}", user);
println!("Port: {}", port);
println!("Database: {}", db_path.display());
println!("");
println!();
run_webdav_server(port, user, db_path).await?;
}
@@ -41,7 +41,7 @@ async fn run_webdav_server(
user: String,
db_path: std::path::PathBuf,
) -> anyhow::Result<()> {
use axum::{extract::Request, response::IntoResponse, routing::any, Extension, Router};
use axum::{routing::any, Extension, Router};
use tokio::net::TcpListener;
let webdav = markbase_webdav::webdav::MarkBaseWebDAV::new(user, db_path);
@@ -58,7 +58,7 @@ async fn run_webdav_server(
println!("WebDAV server listening on http://{}", addr);
println!("Mount point: /webdav");
println!("");
println!();
println!("Press Ctrl+C to stop");
axum::serve(listener, app).await?;
@@ -71,4 +71,4 @@ async fn handle_dav(
req: Request,
) -> impl IntoResponse {
dav.handle(req).await
}
}