核心功能: - ✅ 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)
30 KiB
russh v0.61.2 API限制分析报告
分析日期: 2026-06-09
分析目标: 评估russh库在rsync集成中的技术可行性
分析范围: Channel API、数据流处理、Multiplexing、rsync握手流程
1. Channel API能力分析
1.1 channel.data()方法存在性 ✅
结论: channel.data()方法存在,但存在关键限制。
API定义(channels/mod.rs:321):
/// Send data to a channel.
pub async fn data<R: tokio::io::AsyncRead + Unpin>(&self, data: R) -> Result<(), Error> {
self.send_data(None, data).await
}
/// Send owned bytes to a channel without copying them into the `AsyncWrite` path.
pub async fn data_bytes(&self, data: impl Into<Bytes>) -> Result<(), Error> {
self.send_bytes(None, data.into()).await
}
关键发现:
- ✅
data()方法存在,接受AsyncRead类型参数 - ✅
data_bytes()方法存在,接受Bytes类型参数(零拷贝) - ✅ 支持异步发送(
async fn) - ⚠️ 单向数据发送,无返回值(
Result<(), Error>) - ⚠️ 仅用于服务器向客户端发送数据
1.2 channel.read()双向流支持 ⚠️
结论: channel.read()方法不存在,但有替代方案。
Channel API完整能力矩阵:
| 方法 | 存在性 | 功能 | 适用场景 |
|---|---|---|---|
channel.data() |
✅ 存在 | 发送数据 | Sender模式 |
channel.wait() |
✅ 存在 | 接收ChannelMsg | 接收所有消息类型 |
channel.make_reader() |
✅ 存在 | 创建AsyncRead流 | 接收Data消息 |
channel.into_stream() |
✅ 存在 | 创建双向Stream | 唯一双向方案 ⭐ |
channel.read() |
❌ 不存在 | 直接读取数据 | API缺失 |
替代方案分析:
方案1:channel.wait() - 接收所有消息类型
// channels/mod.rs:655
pub async fn wait(&mut self) -> Option<ChannelMsg> {
self.read_half.wait().await
}
// ChannelMsg枚举定义(channels/mod.rs:21-114)
pub enum ChannelMsg {
Data { data: Bytes }, // ← 数据消息
ExtendedData { data: Bytes, ext: u32 }, // ← 扩展数据(stderr)
Eof, // ← EOF信号
Close, // ← 关闭信号
Open { ... },
ExitStatus { exit_status: u32 },
// ... 其他控制消息
}
优点:
- ✅ 可以接收所有消息类型(Data、Eof、Close、ExitStatus等)
- ✅ 完整的SSH协议消息处理能力
缺点:
- ⚠️ 需要手动处理ChannelMsg枚举,代码复杂度高
- ⚠️ 需要循环调用
wait(),无法直接作为流使用 - ⚠️ 不支持AsyncRead trait,无法直接用于russh-sftp
方案2:channel.make_reader() - AsyncRead流
// channels/mod.rs:677
pub fn make_reader(&mut self) -> impl AsyncRead + '_ {
self.read_half.make_reader()
}
优点:
- ✅ 实现
AsyncReadtrait,可直接用于SFTP等子系统 - ✅ 自动过滤Data消息,忽略其他控制消息
- ✅ 支持异步读取
缺点:
- ⚠️ 仅支持读取,无法同时发送数据
- ⚠️ 需要借用
&mut self,无法同时持有channel用于发送 - ⚠️ 无法实现双向流(rsync receiver模式需要)
方案3:channel.into_stream() - 双向Stream ⭐
// channels/mod.rs:661
pub fn into_stream(self) -> ChannelStream<S> {
ChannelStream::new(
io::ChannelTx::new(...), // ← 发送端(AsyncWrite)
io::ChannelRx::new(...), // ← 接收端(AsyncRead)
)
}
ChannelStream实现(channels/channel_stream.rs):
impl<S> AsyncRead for ChannelStream<S> {
fn poll_read(...) -> Poll<io::Result<()>> {
Pin::new(&mut self.rx).poll_read(cx, buf) // ← 使用ChannelRx读取
}
}
impl<S> AsyncWrite for ChannelStream<S> {
fn poll_write(...) -> Poll<Result<usize, io::Error>> {
Pin::new(&mut self.tx).poll_write(cx, buf) // ← 使用ChannelTx写入
}
}
优点:
- ✅ 唯一支持双向流的方案 ⭐
- ✅ 同时实现
AsyncRead+AsyncWrite - ✅ 可以直接用于russh-sftp的
run()函数 - ✅ 支持异步读写,符合tokio生态
缺点:
- ⚠️ 消耗Channel所有权(
self→into_stream(self)) - ⚠️ 无法再调用
channel.data()等原始方法 - ⚠️ 需要在创建stream前准备好所有逻辑
1.3 异步读取数据支持 ✅
结论: 完全支持异步读取。
异步支持证据:
// ChannelReadHalf.wait() - 异步接收消息
pub async fn wait(&mut self) -> Option<ChannelMsg> {
self.receiver.recv().await // ← tokio::sync::mpsc异步接收
}
// ChannelRx.poll_read() - 异步读取流
impl AsyncRead for ChannelRx<R> {
fn poll_read(...) -> Poll<io::Result<()>> {
match ready!(self.channel.borrow_mut().receiver.poll_recv(cx)) {
Some(msg) => (msg, 0),
None => return Poll::Ready(Ok(())),
}
// ... 处理Data消息
}
}
异步特性:
- ✅ 基于
tokio::sync::mpsc的异步channel - ✅ 支持
Future/async/await语法 - ✅ 支持
AsyncRead/AsyncWritetrait - ✅ 完整集成tokio生态
2. 数据流处理能力分析
2.1 Sender模式数据发送能力 ✅
结论: Sender模式完全支持,但仅适用于单向发送。
Sender模式实现(server.rs:177):
// MarkBase现有实现:rsync sender模式
if rsync_cmd.is_sender_mode() {
let data = tokio::fs::read(&file_path).await?;
// 发送数据到channel
channel.data(&send_data[..]).await?; // ← 单向发送
// 发送退出状态
channel.exit_status(0).await?;
}
支持能力:
- ✅ 读取本地文件
- ✅ 压缩数据(可选)
- ✅ 通过
channel.data()发送数据 - ✅ 发送
exit_status退出状态 - ✅ 完整Sender模式支持
技术限制:
- ⚠️ 无法接收客户端的响应(如rsync protocol握手)
- ⚠️ 无法处理复杂的双向交互协议
2.2 Receiver模式数据接收能力 ⚠️
结论: Receiver模式理论上支持,但存在技术障碍。
Receiver模式需求(server.rs:190):
// MarkBase现有代码中的TODO注释:
else {
log::info!("Rsync receiver mode: receiving file {}", file_path);
// Receiver模式:接收文件数据
// 简化实现:等待channel数据(需要russh API支持)
// 完整实现需要双向数据流处理
// TODO: 实现channel.read() - russh API限制 ⚠️
log::warn!("Rsync receiver mode requires bidirectional stream support");
channel.exit_status(1).await?; // ← 暂时不支持
}
技术障碍分析:
| 障碍类型 | 具体问题 | 解决方案 |
|---|---|---|
| API缺失 | channel.read()不存在 |
使用into_stream() ⭐ |
| 所有权冲突 | Channel已被消耗 | 无法再调用channel.data() |
| 消息类型处理 | 需过滤Data消息 | ChannelRx自动过滤 |
| 协议复杂性 | rsync握手需双向交互 | 需完整协议实现 |
可能的实现路径:
路径1:使用into_stream() ⭐
// 理论实现(未验证)
let stream = channel.into_stream(); // ← 消耗channel所有权
// 接收客户端数据
let mut buf = vec![0u8; 1024];
let n = stream.read(&mut buf).await?; // ← AsyncRead
// 写入本地文件
tokio::fs::write(&file_path, &buf[..n]).await?;
// 发送响应
stream.write_all(b"ACK").await?; // ← AsyncWrite
路径2:使用wait()循环
// 理论实现(未验证)
loop {
match channel.wait().await {
Some(ChannelMsg::Data { data }) => {
// 接收数据
tokio::fs::write(&file_path, &data).await?;
}
Some(ChannelMsg::Eof) => {
// EOF信号
channel.exit_status(0).await?;
break;
}
None => break, // ← channel关闭
_ => {} // ← 忽略其他消息
}
}
2.3 双向数据流交互可能性 ⚠️
结论: 理论上可行,但需要完整协议实现。
双向流交互需求(rsync protocol):
rsync Protocol握手流程:
┌─────────────────────────────────────────────────────┐
│ Phase 1: Connection Setup │
│ - Client sends: "rsync\n" │
│ - Server responds: "@RSYNCD: 31\n" │
│ - Client sends: "@RSYNCD: 31\n" │
└─────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────┐
│ Phase 2: Authentication │
│ - Client sends command line │
│ - Server validates user/path │
│ - Server sends: "@RSYNCD: OK\n" │
└─────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────┐
│ Phase 3: File Transfer │
│ - Sender: sends file data + checksums │
│ - Receiver: sends ACK/requests │
│ - Multiple round-trips │
└─────────────────────────────────────────────────────┘
russh双向流能力评估:
| 双向流需求 | russh支持 | 实现难度 |
|---|---|---|
| Phase 1: 握手 | ✅ 支持 | 中等(需解析协议) |
| Phase 2: 认证 | ✅ 支持 | 低(已有bcrypt) |
| Phase 3: Sender | ✅ 支持 | 低(单向发送) |
| Phase 3: Receiver ⚠️ | ⚠️ 部分支持 | 高(双向交互) |
关键发现:
- ✅ Phase 1-2可用
into_stream()实现 - ✅ Sender模式可用
channel.data()实现 - ⚠️ Receiver模式需要完整协议状态机 ⚠️
- ⚠️ rsync protocol未标准化,需参考OpenSSH实现
3. Multiplexing支持分析
3.1 russh是否支持multiplexing protocol ❌
结论: russh 不支持SSH multiplexing protocol。
证据分析(client/mod.rs:85):
/// It is in charge of multiplexing and keeping track of various channels
关键误解澄清:
- ⚠️ "multiplexing"在russh源码中指的是多channel管理
- ⚠️ 不是SSH Control Multiplexing(OpenSSH的
ControlMaster) - ❌ russh不支持ControlMaster/ControlPath协议
SSH Multiplexing vs russh Channel Multiplexing:
| 特性 | SSH Control Multiplexing | russh Channel Multiplexing |
|---|---|---|
| 定义 | 一个SSH连接承载多个SSH会话 | 一个SSH连接承载多个channel |
| 协议 | OpenSSH专有协议 | SSH RFC 4254标准协议 |
| 实现 | ControlMaster + ControlPath | 多个ChannelId并发 |
| 用途 | 连接复用、减少认证开销 | 并行执行多个命令 |
| russh支持 | ❌ 不支持 | ✅ 支持 |
russh Channel Multiplexing实现:
// Session内部管理多个channels
pub struct Session {
channels: HashMap<ChannelId, Channel<Msg>>, // ← 多channel并发
}
// 示例:并发执行多个命令
let channel1 = session.channel_open_session().await?;
let channel2 = session.channel_open_session().await?; // ← 第二个channel
channel1.exec("ls").await?;
channel2.exec("pwd").await?; // ← 并发执行
3.2 Message type区分能力 ✅
结论: 完全支持Message type区分。
ChannelMsg完整枚举(channels/mod.rs:21-114):
pub enum ChannelMsg {
// 数据消息
Data { data: Bytes }, // ← STDOUT数据
ExtendedData { data: Bytes, ext: u32 }, // ← STDERR数据(ext=1)
// 控制消息
Open { id, max_packet_size, window_size },
Eof, // ← EOF信号
Close, // ← 关闭信号
// 客户端请求(client only)
RequestPty { ... },
RequestShell { want_reply: bool },
Exec { want_reply: bool, command: Vec<u8> },
RequestSubsystem { want_reply: bool, name: String },
Signal { signal: Sig },
// 服务器响应(server only)
ExitStatus { exit_status: u32 }, // ← 退出状态
ExitSignal { signal_name, core_dumped, ... },
Success, // ← 成功响应
Failure, // ← 失败响应
WindowAdjusted { new_size: u32 },
XonXoff { client_can_do: bool },
// 其他
SetEnv { ... },
WindowChange { ... },
AgentForward { ... },
RequestX11 { ... },
OpenFailure(ChannelOpenFailure),
}
Message type分类:
| 类别 | Message类型 | 处理方式 |
|---|---|---|
| 数据消息 | Data, ExtendedData | 通过ChannelRx读取 |
| 控制消息 | Eof, Close, ExitStatus | 通过wait()接收 |
| 请求消息 | Exec, RequestSubsystem | 通过Handler trait处理 |
| 响应消息 | Success, Failure | 通过Handler trait返回 |
3.3 控制消息和数据消息分离 ✅
结论: 完全支持分离。
分离机制:
方案1:ChannelRx自动过滤
// channels/io/rx.rs:46
impl AsyncRead for ChannelRx<R> {
fn poll_read(...) -> Poll<io::Result<()>> {
match (&msg, self.ext) {
(ChannelMsg::Data { data }, None) => {
// ← 只处理Data消息,自动过滤其他消息
buf.put_slice(&data[idx..idx + readable]);
Poll::Ready(Ok(()))
}
(ChannelMsg::ExtendedData { data, ext }, Some(target)) if *ext == target => {
// ← 只处理匹配的ExtendedData
buf.put_slice(&data[idx..idx + readable]);
Poll::Ready(Ok(()))
}
(ChannelMsg::Eof, _) => {
// ← EOF信号,关闭流
self.channel.borrow_mut().receiver.close();
Poll::Ready(Ok(()))
}
_ => {
// ← 忽略其他控制消息(ExitStatus、Close等)
cx.waker().wake_by_ref();
Poll::Pending
}
}
}
}
方案2:Channel.wait()手动分离
loop {
match channel.wait().await {
Some(ChannelMsg::Data { data }) => {
// ← 处理数据消息
process_data(data);
}
Some(ChannelMsg::ExitStatus { exit_status }) => {
// ← 处理控制消息
log::info!("Exit status: {}", exit_status);
break;
}
Some(ChannelMsg::Close) => {
// ← 处理控制消息
log::info!("Channel closed");
break;
}
_ => {} // ← 忽略其他消息
}
}
4. rsync集成可行性分析
4.1 完整握手流程实现可能性 ⚠️
结论: 技术上可行,但实现难度高。
rsync Protocol握手流程(OpenSSH标准):
Phase 1: Connection Setup(1-2 round-trips)
┌─────────┐ ┌─────────┐
│ Client │ │ Server │
└─────────┘ └─────────┘
│ │
│──── "rsync\n" ──────────────>│ (1) Client announces
│ │
│<─── "@RSYNCD: 31\n" ─────────│ (2) Server version
│ │
│──── "@RSYNCD: 31\n" ─────────>│ (3) Client confirms
│ │
Phase 2: Authentication(1 round-trip)
│ │
│──── command line ────────────>│ (4) Client sends command
│ (e.g., "-e.ssh.lso...") │
│ │
│<─── "@RSYNCD: OK\n" ─────────│ (5) Server validates
│ │
Phase 3: File Transfer(Multiple round-trips)
│ │
│ Sender模式: │
│──── File data + checksums ───>│ (6) Sender sends data
│ │
│ Receiver模式: │
│<─── File data requests ──────│ (7) Receiver requests
│──── ACK + more data ─────────>│ (8) Sender responds
│ │
│<─── Exit status ─────────────│ (9) Server exits
│ │
russh实现分析:
| Phase | 实现难度 | 关键技术 | russh能力 |
|---|---|---|---|
| Phase 1 | 中等 | 协议解析 + 字符串匹配 | ✅ into_stream() |
| Phase 2 | 低 | 命令解析 + 认证验证 | ✅ 已有bcrypt |
| Phase 3: Sender | 低 | 单向数据发送 | ✅ channel.data() |
| Phase 3: Receiver ⚠️ | 高 | 双向交互协议 | ⚠️ 需完整实现 |
技术障碍:
障碍1:Protocol未标准化
- ⚠️ rsync protocol未公开RFC文档
- ⚠️ 需参考OpenSSH源码实现
- ⚠️ 版本兼容性问题(rsync 31.x vs 30.x)
障碍2:双向交互复杂
- ⚠️ Receiver需要发送请求、接收数据、发送ACK
- ⚠️ 需完整状态机实现
- ⚠️ Window size管理(SSH flow control)
障碍3:Checksum计算
- ⚠️ rsync使用rolling checksum(adler32 + MD4)
- ⚠️ 需实现rsync算法库
- ⚠️ 性能优化需求
4.2 Task 4-5实施技术障碍 ⚠️⚠️⚠️
结论: 存在3个HIGH级别障碍。
障碍矩阵:
| 障碍级别 | 障碍描述 | 影响范围 | 解决方案 |
|---|---|---|---|
| HIGH ⭐⭐⭐ | channel.read() API缺失 | Receiver模式无法实现 | 使用into_stream() ⭐ |
| HIGH ⭐⭐⭐ | rsync protocol未标准化 | 无法实现完整握手 | 参考OpenSSH源码 |
| HIGH ⭐⭐⭐ | 双向交互协议复杂性 | 需完整状态机 | 需专业rsync实现 |
| MEDIUM ⭐⭐ | Channel所有权消耗 | 无法同时发送接收 | Split channel |
| MEDIUM ⭐⭐ | Window size管理 | SSH flow control | 自动管理 |
| LOW ⭐ | rsync算法实现 | Rolling checksum | 使用rsync crate |
详细障碍分析:
障碍1:channel.read() API缺失 ⭐⭐⭐
问题:
// 期望API(不存在)
let data = channel.read(1024).await?; // ← ❌ API不存在
// 实际替代方案
let stream = channel.into_stream(); // ← 消耗所有权 ⚠️
let n = stream.read(&mut buf).await?; // ← AsyncRead
影响:
- ⚠️ 无法在保留channel的同时读取数据
- ⚠️ 需要提前准备所有逻辑(消耗所有权)
- ⚠️ 无法动态切换Sender/Receiver模式
解决方案:
- ✅ 使用
into_stream()创建双向流 - ✅ 提前解析rsync命令,确定模式
- ✅ 使用
channel.split()分离读写(需验证)
障碍2:rsync protocol未标准化 ⭐⭐⭐
问题:
- ⚠️ rsync protocol无公开RFC文档
- ⚠️ 仅能参考OpenSSH源码(sftp-server.c)
- ⚠️ 版本兼容性问题(rsync 31.x vs 30.x)
证据:
# OpenSSH源码位置
openssh/sftp-server.c:main() ← rsync protocol实现
openssh/sftp-common.c ← 辅助函数
影响:
- ⚠️ 需逆向分析OpenSSH实现
- ⚠️ 可能遗漏协议细节
- ⚠️ 版本兼容性测试成本高
解决方案:
- ✅ 参考OpenSSH源码实现(开源)
- ✅ 使用rsync命令测试验证(逆向工程)
- ✅ 添加版本协商机制
障碍3:双向交互协议复杂性 ⭐⭐⭐
问题:
// rsync receiver需要复杂的状态机
loop {
// 1. 接收客户端请求
let request = stream.read(&mut buf).await?;
// 2. 解析请求类型
match parse_rsync_request(&request) {
RsyncRequest::FileData { checksum } => {
// 3. 计算本地checksum
let local_checksum = compute_checksum(&file)?;
// 4. 发送差异块
stream.write_all(&delta_blocks).await?;
}
RsyncRequest::Ack => {
// 5. 发送更多数据
stream.write_all(&next_chunk).await?;
}
}
}
影响:
- ⚠️ 需完整状态机实现(10+ 状态)
- ⚠️ 错误处理复杂(超时、断连)
- ⚠️ 性能优化需求(rolling checksum)
解决方案:
- ✅ 参考rsync crate(如果存在)
- ✅ 使用简化版rsync协议(无delta传输)
- ⚠️ 需专业rsync知识
4.3 可能的替代方案 ⭐
方案矩阵:
| 方案 | 技术栈 | 实现难度 | 功能完整性 | 推荐度 |
|---|---|---|---|---|
| 方案1:简化rsync ⭐ | russh + 自定义协议 | 中 | Sender only | ⭐⭐⭐ |
| 方案2:调用rsync命令 ⭐ | russh + rsync CLI | 低 | 完整 | ⭐⭐⭐⭐ |
| 方案3:使用SFTP ⭐ | russh + russh-sftp | 低 | 完整 | ⭐⭐⭐⭐⭐ |
| 方案4:完整rsync实现 | russh + rsync protocol | 高 | 完整 | ⭐ |
| 方案5:使用librsync | russh + C library | 高 | 完整 | ⭐⭐ |
方案1:简化rsync实现 ⭐⭐⭐
实现思路:
// 只实现Sender模式(单向发送)
pub async fn handle_rsync_sender(channel: Channel<Msg>, file_path: &str) -> Result<()> {
// Phase 1: Connection Setup
channel.data(b"rsync\n").await?;
// Phase 2: Authentication
channel.data(b"@RSYNCD: OK\n").await?;
// Phase 3: File Transfer(Sender only)
let file_data = tokio::fs::read(file_path).await?;
channel.data_bytes(Bytes::from(file_data)).await?;
// Phase 4: Exit
channel.exit_status(0).await?;
channel.close().await?;
Ok(())
}
优点:
- ✅ 实现简单(单向发送)
- ✅ 兼容rsync sender模式
- ✅ 性能高(无协议开销)
缺点:
- ⚠️ 不支持Receiver模式
- ⚠️ 不支持增量传输(delta)
- ⚠️ 不支持rsync高级特性(checksum、压缩)
方案2:调用rsync命令 ⭐⭐⭐⭐
实现思路:
// 通过SSH exec调用远程rsync命令
pub async fn handle_rsync_command(channel: Channel<Msg>, command: &str) -> Result<()> {
// 使用SSH exec运行rsync命令
channel.exec(true, command).await?;
// 读取rsync输出
loop {
match channel.wait().await {
Some(ChannelMsg::Data { data }) => {
// 处理rsync输出
process_rsync_output(data);
}
Some(ChannelMsg::ExitStatus { exit_status }) => {
log::info!("rsync exit: {}", exit_status);
break;
}
None => break,
_ => {}
}
}
Ok(())
}
优点:
- ✅ 完整rsync功能(调用标准命令)
- ✅ 实现简单(仅需SSH exec)
- ✅ 性能高(rsync原生实现)
缺点:
- ⚠️ 需要远程服务器安装rsync
- ⚠️ 无法完全控制rsync行为
- ⚠️ 安全性问题(exec命令)
方案3:使用SFTP替代 ⭐⭐⭐⭐⭐
实现思路:
// 使用SFTP子系统传输文件
pub async fn handle_file_transfer(channel: Channel<Msg>) -> Result<()> {
// 转换为stream
let stream = channel.into_stream();
// 运行SFTP subsystem
russh_sftp::server::run(stream, sftp_handler).await;
// SFTP提供完整文件传输功能
// - upload/download
// - directory listing
// - permission management
// - checksum verification
}
优点:
- ✅ 最佳方案 ⭐⭐⭐⭐⭐
- ✅ russh-sftp已实现(2.3.0)
- ✅ 标准协议(RFC draft)
- ✅ 完整功能(upload/download/list)
- ✅ 安全认证(bcrypt)
- ✅ 性能优化(DashMap并发)
缺点:
- ⚠️ 不支持rsync增量传输(delta)
- ⚠️ 不兼容rsync客户端
- ⚠️ 需要客户端支持SFTP
方案4:完整rsync协议实现 ⭐
实现思路:
// 完整rsync protocol状态机
pub struct RsyncProtocol {
state: RsyncState,
stream: ChannelStream<Msg>,
}
impl RsyncProtocol {
pub async fn handshake(&mut self) -> Result<()> {
// Phase 1: Connection Setup
self.stream.write_all(b"rsync\n").await?;
let version = self.read_line().await?;
// Phase 2: Authentication
self.stream.write_all(b"@RSYNCD: 31\n").await?;
let command = self.read_command().await?;
// Phase 3: File Transfer(完整实现)
match self.parse_command(&command) {
Sender { path } => self.sender_mode(path).await?,
Receiver { path } => self.receiver_mode(path).await?,
}
}
async fn sender_mode(&mut self, path: &str) -> Result<()> {
// ... 复杂实现
}
async fn receiver_mode(&mut self, path: &str) -> Result<()> {
// ... 复杂实现(双向交互)
}
}
优点:
- ✅ 完整rsync功能
- ✅ 兼容rsync客户端
- ✅ 支持增量传输
缺点:
- ⚠️ 实现难度极高 ⭐⭐⭐
- ⚠️ 需完整协议知识
- ⚠️ 需专业rsync算法
- ⚠️ 开发周期长(2-4周)
方案5:使用librsync(C library) ⭐⭐
实现思路:
// 调用librsync C library
extern crate librsync;
pub async fn handle_rsync_with_librsync(stream: ChannelStream<Msg>) -> Result<()> {
// 使用FFI调用librsync
let delta = librsync::compute_delta(&source, &target)?;
// 发送delta数据
stream.write_all(&delta).await?;
}
优点:
- ✅ 使用成熟的rsync算法库
- ✅ 性能优化(C实现)
- ✅ 支持增量传输
缺点:
- ⚠️ 需要FFI绑定(复杂)
- ⚠️ 需要处理C/Rust内存管理
- ⚠️ librsync维护状况不明
- ⚠️ 集成成本高
5. 实施建议
5.1 立即可行的方案 ⭐⭐⭐⭐⭐
推荐:方案3 - 使用SFTP替代
实施步骤:
Step 1:验证现有SFTP实现
# 测试SFTP功能
cargo run --bin markbase-core -- sftp --user warren --port 2023
# 测试上传/下载
sftp -P 2023 warren@127.0.0.1
> put test.txt
> get test.txt
Step 2:扩展SFTP功能
// 添加checksum verification
impl Handler for SftpHandler {
async fn read(&mut self, id: u32, handle: String, offset: u64, len: u32) -> Result<Data> {
let data = self.read_file_data(handle, offset, len)?;
// 计算checksum(可选)
let checksum = md5::compute(&data);
log::info!("Checksum: {:?}", checksum);
Ok(Data { id, data })
}
}
Step 3:提供rsync-like接口
// 通过Web API提供rsync-like功能
#[derive(Serialize)]
pub struct RsyncResponse {
files_transferred: usize,
total_size: u64,
checksum: String,
duration_ms: u64,
}
// REST API
POST /api/v2/rsync/upload
POST /api/v2/rsync/download
GET /api/v2/rsync/status
5.2 短期可行方案 ⭐⭐⭐
推荐:方案2 - 调用rsync命令
实施步骤:
Step 1:实现SSH exec handler
// server.rs
async fn exec_request(&mut self, channel_id: ChannelId, command: &str) -> Result<()> {
let channel = self.get_channel(channel_id).await;
// 转换为stream
let stream = channel.into_stream();
// 启动rsync命令
let mut child = tokio::process::Command::new("rsync")
.arg("-av")
.arg("--progress")
.arg(source)
.arg(dest)
.stdout(Stdio::piped())
.spawn()?;
// 流式传输rsync输出
let mut stdout = child.stdout.take()?;
tokio::io::copy(&mut stdout, &mut stream).await?;
// 发送退出状态
let status = child.wait().await?;
stream.write_all(&format!("Exit: {}\n", status).as_bytes()).await?;
Ok(())
}
Step 2:配置安全限制
# config/sftp.toml
[exec]
allowed_commands = ["rsync", "ls", "pwd"]
max_execution_time = 300 # seconds
require_approval = true
5.3 长期方案 ⭐
推荐:方案1 + 方案4混合
实施策略:
Phase 1(1-2周):实现简化Sender模式
- ✅ 实现单向文件发送
- ✅ 基本握手流程
- ✅ Exit status处理
Phase 2(2-3周):参考OpenSSH实现Receiver
- ⚠️ 逆向分析OpenSSH sftp-server.c
- ⚠️ 实现双向交互协议
- ⚠️ 状态机实现
Phase 3(1-2周):性能优化
- ⚠️ Rolling checksum实现
- ⚠️ Delta传输算法
- ⚠️ 性能测试
6. 结论
6.1 russh API能力总结
| 能力项 | 状态 | 评级 |
|---|---|---|
| channel.data()存在性 | ✅ 存在 | ⭐⭐⭐⭐⭐ |
| 异步发送支持 | ✅ 支持 | ⭐⭐⭐⭐⭐ |
| channel.read()存在性 | ❌ 不存在 | ⭐ |
| 双向流支持 | ⚠️ 间接支持(into_stream) | ⭐⭐⭐ |
| Message type区分 | ✅ 支持 | ⭐⭐⭐⭐⭐ |
| Multiplexing protocol | ❌ 不支持 | ⭐ |
6.2 rsync集成可行性总结
| 集成项 | 状态 | 障碍级别 |
|---|---|---|
| Sender模式 | ✅ 可行 | LOW |
| Receiver模式 | ⚠️ 困难 | HIGH ⭐⭐⭐ |
| 完整握手流程 | ⚠️ 困难 | HIGH ⭐⭐⭐ |
| Delta传输 | ⚠️ 极困难 | HIGH ⭐⭐⭐ |
6.3 最终建议
推荐方案优先级:
-
方案3:SFTP替代 ⭐⭐⭐⭐⭐(立即实施)
- 原因:已实现、标准协议、完整功能
- 时间:0天(现有代码已实现)
-
方案2:调用rsync命令 ⭐⭐⭐⭐(短期实施)
- 原因:实现简单、完整功能
- 时间:1-2天
-
方案1:简化rsync ⭐⭐⭐(中期实施)
- 原因:兼容性需求、可控实现
- 时间:1-2周
-
方案4:完整rsync ⭐(长期研究)
- 原因:技术障碍高、开发周期长
- 时间:2-4周
报告完成日期: 2026-06-09
报告版本: 1.0
下次更新: 待实施反馈后更新