Files
markbase/docs/SSH2_HYBRID_PHASE2_PLAN.md
T
Warren 1300a4e223
Test / test (push) Has been cancelled
Test / build (push) Has been cancelled
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)
2026-06-12 12:59:54 +08:00

301 lines
7.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ssh2混合方案Phase 2实施计划
**创建日期**: 2026-06-10
**状态**: ⚠️ 技术障碍分析
---
## 一、已完成工作(Phase 1)✅
### ssh2模块基础架构
**文件清单**
- `markbase-core/src/ssh2_mod/mod.rs`40行)
- `markbase-core/src/ssh2_mod/scp_handler.rs`174行)
- `markbase-core/src/ssh2_mod/rsync_receiver.rs`109行)
- 总计:323行代码
**功能实现**
- ✅ ScpHandlerhandle_scp_command, handle_scp_receive, handle_scp_send
- ✅ RsyncReceiverHandlerhandle_rsync_receiver, receive_checksums, receive_delta_data
- ✅ 编译成功
---
## 二、技术障碍 ⚠️
### 核心问题:Channel类型不兼容
**russh Channel** vs **ssh2 Channel**
```rust
// russh Channel(异步,无read方法)
pub struct Channel<Msg> {
async fn write(&mut self, data: &[u8]) -> Result<(), Error>;
// ❌ 无read方法
}
// ssh2 Channel(阻塞,完整双向)
pub struct Channel {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error>;
fn write_all(&mut self, buf: &[u8]) -> Result<(), Error>;
}
```
**exec_request接收的是russh Channel**
```rust
async fn exec_request(
&mut self,
channel: ChannelId, // ← russh Channel ID
data: &[u8],
session: &mut Session,
) -> Result<(), Self::Error> { ... }
```
**ssh2 Handler需要ssh2 Channel**
```rust
pub fn handle_scp_command(&self, channel: &mut ssh2::Channel, command: &str)
```
---
### 问题根源
**无法直接转换**
- russh Channel → ssh2 Channel(类型不兼容)
- russh不暴露底层TCP stream(无法创建ssh2 Session
---
## 三、解决方案分析
### 方案A:双SSH连接(复杂)⭐
**架构**
```
客户端SSH连接 → russh ServerSFTP + Auth
exec_request检测到SCP/rsync receiver
创建新SSH连接 → ssh2 Session(独立连接)
ssh2处理SCP/rsync receiver
```
**实现**
```rust
async fn exec_request(&mut self, channel: ChannelId, data: &[u8]) {
let command = String::from_utf8_lossy(data);
if command.contains("scp") || command.contains("rsync --receiver") {
// 问题:如何获取客户端信息(IP、Port)?
// 问题:客户端需要重新认证?
// 创建新的ssh2连接
let tcp_stream = TcpStream::connect(client_ip_port)?; // ← 无法获取
let ssh2_session = ssh2::Session::new()?;
ssh2_session.set_tcp_stream(tcp_stream);
ssh2_session.handshake()?;
ssh2_session.userauth_password(user, password)?;
// 使用ssh2处理
let channel = ssh2_session.channel_session()?;
let scp_handler = ScpHandler::new(...);
scp_handler.handle_scp_command(&mut channel, &command)?;
}
}
```
**问题**
- ❌ 无法获取客户端IP/Port(russh不暴露)
- ❌ 客户端需要重新认证(用户体验差)
- ⚠️ 两个独立连接(资源浪费)
---
### 方案B:完全切换到ssh2(重写)⭐⭐⭐
**架构**
```
客户端SSH连接 → ssh2 Server(完整功能)
├── SCP subsystem ✅
├── rsync receiver ✅
└── SFTP subsystem ✅(需重写)
```
**实现**
```rust
// ssh2 Server实现
use ssh2::Session;
let session = Session::new()?;
session.set_tcp_stream(tcp_stream);
session.handshake()?;
// Auth
session.userauth_password(user, password)?;
// 处理exec请求
let channel = session.channel_session()?;
channel.exec(true, &command)?;
// SCP完整支持(内置)
channel.exec(true, "scp -f /path/to/file")?;
let data = channel.read_string()?; // ✅ ssh2支持read
// rsync完整支持
channel.exec(true, "rsync --server --receiver . /path")?;
let checksums = channel.read_exact(4096)?; // ✅ ssh2支持read
```
**优势**
- ✅ SCP/rsync receiver完整支持
- ✅ Channel双向通信
- ✅ libssh2成熟稳定
**劣势**
- ❌ 需重写SFTP(14操作已完成的工作)
- ❌ 阻塞式API(需适配tokio)
- ⚠️ 3-5天工作量
---
### 方案Crussh + ssh2 TCP共享(理论)⭐⭐
**架构**
```
客户端TCP连接 → TcpStream
russh ServerSFTP
ssh2 Session(共享TCP ← 理论方案
```
**问题**
- ❌ russh不暴露底层TcpStream
- ❌ TCP stream已经被russh占用
- ⚠️ 无法共享同一个TCP连接
---
### 方案D:简化混合方案(推荐)⭐⭐⭐⭐⭐
**策略**
- russh继续处理SFTP + rsync senderwrite-only
- SCP/rsync receiver暂时使用placeholder(等待russh更新)
- 记录技术障碍,后续优化
**实现**
```rust
async fn exec_request(&mut self, channel: ChannelId, data: &[u8]) {
let command = String::from_utf8_lossy(data);
if command.starts_with("scp -f") {
// SCP sender → 可用russh实现(只write
self.handle_scp_sender(channel, &command).await?;
} else if command.starts_with("scp -t") {
// SCP receiver → placeholder(需channel.read
log::warn!("SCP receiver not supported (russh limitation)");
// 未来:等待russh更新或切换ssh2
} else if command.starts_with("rsync --server --sender") {
// rsync sender → 已实现(russh
self.handle_rsync_sender(channel, &command).await?;
} else if command.starts_with("rsync --server --receiver") {
// rsync receiver → placeholder(需channel.read
log::warn!("rsync receiver not supported (russh limitation)");
}
}
```
**优势**
- ✅ 保留现有russh SFTP实现(14操作)
- ✅ 立即可用SCP sender + rsync sender
- ✅ 最小改动(0工作量)
- ✅ 未来可切换ssh2(如果需要)
---
## 四、推荐决策
### 当前最优方案:方案D(简化混合)⭐⭐⭐⭐⭐
**理由**
1. MarkBase当前需求已满足(SFTP完整 + rsync sender
2. SCP receiver不是必需功能(SFTP可替代)
3. rsync receiver不是必需功能(sender已足够)
4. 等待russh更新(保持架构一致性)
5. 未来可切换ssh2(如果急需SCP/rsync receiver
---
### 实施步骤(方案D
**Phase 2-A(当前)**
1. 修改exec_request路由逻辑
2. SCP sender实现(russh write-only
3. SCP/rsync receiver placeholder
4. 测试SCP sender功能
**Phase 2-B(未来可选)**
- 等待russh发布channel.read()支持
- 或切换到ssh2(如果急需SCP/rsync receiver
---
## 五、SCP Sender实现(可行)
### russh-based SCP Sender
**原理**SCP sender只需要write文件数据,不需要read客户端输入
```rust
async fn handle_scp_sender(&mut self, channel: ChannelId, command: &str) {
// 解析路径
let path = parse_scp_path(command)?;
let file_path = self.base_path.join(&self.user_id).join(path);
// 读取文件
let file_content = std::fs::read(&file_path)?;
let metadata = std::fs::metadata(&file_path)?;
let size = metadata.len();
let filename = file_path.file_name()?;
// 发送SCP headerC0644 <size> <filename>)
let header = format!("C0644 {} {}\n", size, filename);
self.channel.write_all(header.as_bytes()).await?;
// 发送文件内容
self.channel.write_all(&file_content).await?;
// 发送结束标志
self.channel.write_all(&[0x00]).await?;
self.channel.write_all("E\n".as_bytes()).await?;
}
```
**优势**
- ✅ 可用russh实现(只write
- ✅ 立即可用
- ✅ 无需ssh2
---
## 六、最终建议
**推荐方案****方案D(简化混合)**
**实施优先级**
1. **立即实施**SCP senderrussh实现)
2. **记录障碍**SCP/rsync receiver placeholder
3. **未来可选**:切换ssh2(如果急需receiver功能)
**时间评估**
- Phase 2-ASCP sender):1-2小时
- Phase 2-B(切换ssh2):3-5天(如果需要)
---
**计划完成时间**: 2026-06-10 01:00
**文档版本**: 1.0