Files
markbase/docs/SSH2_HYBRID_PHASE2_PLAN.md
Warren 1300a4e223
Some checks failed
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/Portrussh不暴露
- ❌ 客户端需要重新认证(用户体验差)
- ⚠️ 两个独立连接(资源浪费)
---
### 方案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成熟稳定
**劣势**
- ❌ 需重写SFTP14操作已完成的工作
- ❌ 阻塞式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 sender1-2小时
- Phase 2-B切换ssh23-5天如果需要
---
**计划完成时间**: 2026-06-10 01:00
**文档版本**: 1.0