rclone bisync RC 接口详解:sync/bisync 调用参数、返回值与源码实现
本篇指南以 rclone 仓库中的 cmd/bisync/rc.md 为主体,完整解析 sync/bisync 这个 RC(Remote Control)调用的全部参数、默认值与返回值,并结合 rc.go、cmd.go、lockfile.go 等源码说明每个参数在 bisync 内部的实际作用。读完后你可以直接用 rclone rc sync/bisync 以 JSON 方式驱动双向云同步,并且清楚参数名(驼峰)、CLI flag(短横线)之间的映射关系、缺失参数的默认值行为,以及会话工作目录、列表文件等返回字段的来源。
一、sync/bisync 是什么:RC 调用的注册与帮助文档
sync/bisync 是 bisync 双向同步功能暴露给 rclone RC HTTP 接口的调用端点。bisync 本身定位为高级命令,会保留上一次运行时 Path1 与 Path2 两侧的目录列表,在后续每次运行中:
- 列举 Path1 和 Path2 的文件并检测各自的变化(新文件、更新、变旧、删除);
- 将 Path1 的变化传播到 Path2,反之亦然。
从源码结构看,该 RC 调用在包初始化时通过 rc.Add 注册,cmd/bisync/rc.go 中的关键代码为:
func addRC() {
rc.Add(rc.Call{
Path: "sync/bisync",
Fn: rcBisync,
Title: shortHelp,
Help: rcHelp,
})
}
//go:embed rc.md
var rcHelp string
两个值得注意的机制:
- 帮助文档由代码生成,禁止手改。cmd/bisync/rc.md 第一行声明了
Docs generated by help.go - use go generate to rebuild - DO NOT EDIT。它由 cmd/bisync/help.go 生成:GenerateParams()会遍历bisync命令注册的全部非隐藏 flag(commandDefinition.Flags().VisitAll),把 flag 名转成驼峰(如create-empty-src-dirs→createEmptySrcDirs),连同类型与 usage 文本写入文档。因此 rc.md 中的参数名就是 RC 参数名,与 CLI flag 一一对应。 - flag 与 RC 参数必须手动保持同步。cmd/bisync/cmd.go 的
init()中有明确注释:
// when adding new flags, remember to also update the rc params:
// cmd/bisync/rc.go cmd/bisync/help.go (not docs/content/rc.md)
// and the Command line syntax section of docs/content/bisync.md (it doesn't update automatically)
即新增 flag 后要同步更新 rc 参数解析与两处文档,这正是阅读 rc.md 时应有的意识:它是 RC 接口的契约清单。
二、调用方式
先启动 RC 服务(rclone rcd 或在任意命令上用 --rc 打开端口),然后以 JSON 参数调用:
rclone rc sync/bisync path1=drive:path1 path2=drive:path2 resync=true dryRun=true
或等价地 POST 到 RC 端口:
POST /sync/bisync
{"path1":"drive:path1","path2":"drive:path2","resync":true,"dryRun":true}
路径参数与 CLI 的 bisync remote1:path1 remote2:path2 对应,必须是已存在的目录——CLI 入口在 cmd/bisync/cmd.go 中会校验两个参数并拒绝非目录路径;RC 侧则通过 rc.GetFsNamed 解析(见下文第五节)。
三、完整参数清单(继承自 rc.md)
以下参数表完整继承自 cmd/bisync/rc.md,并在“实现佐证”列给出源码位置与默认值来源。path1/path2 为必填,其余均可选,缺失时走 Options 零值或显式默认值。
| 参数 | 类型 | 说明(rc.md 原文) | 实现佐证 |
|---|---|---|---|
| path1(必填) | string | 远端目录字符串,如 drive:path1 |
rc.go#L166-L169 经 rc.GetFsNamed(octx, in, "path1") 解析为 fs |
| path2(必填) | string | 远端目录字符串,如 drive:path2 |
rc.go#L171-L174 |
| dryRun | bool | dry-run 模式 | rc.go#L68-L73;同时写入 context 配置 ci.DryRun 与 opt.DryRun |
| maxDelete | int64 | (CLI 由 --max-delete 提供)删除比例上限,0–100 的百分比 |
rc.go#L75-L82 显式校验越界并报错;CLI 侧默认 50,见 DefaultMaxDelete cmd.go#L67-L70 |
| backupDir1 | string | Path1 的 --backup-dir。必须是同一 remote 上不重叠的路径 |
rc.go#L119-L124;兼容旧写法 backupdir1 |
| backupDir2 | string | Path2 的 --backup-dir。必须是同一 remote 上不重叠的路径 |
rc.go#L125-L130;兼容旧写法 backupdir2 |
| checkAccess | bool | 确认两侧文件系统上存在预期的 RCLONE_TEST 文件,否则中止 | rc.go#L87-L89 |
| checkFilename | string | --check-access 使用的文件名(默认: RCLONE_TEST) |
默认值常量 DefaultCheckFilename cmd.go#L69 |
| checkSync | string | 控制最终列表比对:true|false|only(默认: true) | 枚举 CheckSyncMode,解析见 cmd.go#L75-L110 |
| compare | string | bisync 专属比较选项的逗号分隔列表,如 'size,modtime,checksum'(默认: 'size,modtime') |
rc.go#L149-L151 存入 CompareFlag |
| conflictLoser | ConflictLoserAction | 冲突败方(有胜方时)或双方(无胜方时)的动作:空, num, pathname, delete(默认: num) | 枚举经 rc.go#L140-L142 setEnum 解析 |
| conflictResolve | string | 自动解决冲突时优先采用的版本:none, path1, path2, newer, older, larger, smaller(默认: none) | 枚举经 rc.go#L137-L139 setEnum 解析 |
| conflictSuffix | string | 重命名 --conflict-loser 时使用的后缀;可给一个字符串或两个逗号分隔字符串分别为 Path1/Path2 指定(默认: 'conflict') |
rc.go#L143-L145 |
| createEmptySrcDirs | bool | 同步空目录的创建与删除(与 --remove-empty-dirs 不兼容) | rc.go#L93-L95 |
| downloadHash | bool | 在无法直接获取哈希时通过下载计算(警告: 可能很慢且大量耗流量!) | rc.go#L158-L160 → Compare.DownloadHash |
| filtersFile | string | 从文件读取过滤模式 | rc.go#L112-L114;文件变更校验逻辑见 cmd.go#L229-L279 |
| force | bool | 绕过 --max-delete 安全检查继续同步(建议配合 --verbose 使用) |
rc.go#L90-L92 |
| ignoreListingChecksum | bool | 列举时不使用校验和(叠加 --ignore-checksum 可进一步跳过复制后的校验和检查) |
rc.go#L102-L104 |
| maxLock | Duration | 视旧于此时长的锁文件为已过期(默认: 0 即永不过期,最小: 2m) | rc.go#L161-L164;最小值钳制见 lockfile.go#L68-L75 |
| noCleanup | bool | 保留工作文件(便于排障与测试) | rc.go#L99-L101 |
| noSlowHash | bool | 仅在获取校验和很慢的后端上忽略列举校验和 | rc.go#L152-L154 → Compare.NoSlowHash |
| recover | bool | 中断后自动恢复,无需 --resync |
rc.go#L146-L148 |
| removeEmptyDirs | bool | 在最终清理步骤删除所有空目录 | rc.go#L96-L98 |
| resilient | bool | 允许后续运行在遇到某些较轻错误时重试,而不是要求 --resync |
rc.go#L105-L107 |
| resync | bool | 执行 resync 运行。等价于 --resync-mode path1。建议先 --verbose 或 --dry-run |
rc.go#L84-L86 |
| resyncMode | string | resync 时优先采用的版本:path1, path2, newer, older, larger, smaller(默认: 若 --resync 则 path1,否则 none 不 resync) | 枚举经 rc.go#L134-L136 setEnum 解析 |
| slowHashSyncOnly | bool | 列举与 delta 阶段忽略慢校验和,但在 sync 调用中仍然考虑 | rc.go#L155-L157 → Compare.SlowHashSyncOnly |
| workdir | string | 使用自定义工作目录(便于测试)(默认: /home/ncw/.cache/rclone/bisync) |
rc.go#L115-L118;文档中的示例路径由 MakeHelp 用 DefaultWorkdir 注入,见 rc.go#L54-L62 |
说明:rc.md 中
workdir的“默认: /home/ncw/.cache/rclone/bisync”是文档生成者机器上DefaultWorkdir的展开值。在任意机器上该默认值由 cmd/bisync/cmd.go 计算为缓存目录下的bisync子目录(filepath.Join(config.GetCacheDir(), "bisync")),即 Linux 常见为~/.cache/rclone/bisync、macOS 为~/Library/Caches/rclone/bisync、Windows 为%LocalAppData%\rclone\bisync。
另外,cmd/bisync/cmd.go 中还有两个被 MarkHidden 的 flag(debugname、localtime),因为它们不写入 RC 帮助,所以不出现在 rc.md 的参数清单中。
四、参数解析的实现细节
4.1 可选参数的“缺失即用默认值”模式
rc.go 中所有可选参数都遵循同一模式:尝试从 RC 参数中取值;如果错误是“参数不存在”(rc.NotErrParamNotFound(err) 为假),则记录 debug 日志并沿用 Options 的零值/默认值;如果是其他类型错误(如类型不匹配)则直接返回。以 resync 为例:
if opt.Resync, err = in.GetBool("resync"); rc.NotErrParamNotFound(err) {
fs.Debugf("resync", "optional parameter is missing. using default value: %v", opt.Resync)
}
枚举类型参数统一走 rc.go 的 setEnum 辅助函数:参数缺失或为空时回落到该枚举的当前字符串值(即 CLI flag 定义的默认值),再调用枚举的 Set 方法做合法性校验;Set 失败(如 checkSync 传了未知值)会返回错误、终止调用。
4.2 checkSync 的三态语义
checkSync 对应 cmd/bisync/cmd.go 中定义的 CheckSyncMode 枚举:
| 取值 | 常量 | 行为 |
|---|---|---|
| true(默认) | CheckSyncTrue |
同步完成后比对最终列表 |
| false | CheckSyncFalse |
禁用最终列表比对 |
| only | CheckSyncOnly |
只比对上一次运行的列表,不做同步 |
这为 RC 调用方提供了“只校验不变更”的观测入口,配合 dryRun=true 适合做巡检脚本。
4.3 比较策略与慢哈希参数族
compare 控制 bisync 判定文件“未变化”时依据哪些属性(默认 size,modtime)。围绕校验和开销还有三个互补的布尔参数,全部落在 CompareOpt 结构上(rc.go#L152-L160):
noSlowHash:仅在“慢哈希”后端(列举时取校验和代价高)忽略校验和;slowHashSyncOnly:列举与 delta 阶段忽略慢校验和,但真正 sync 调用时仍使用;downloadHash:无法直接取哈希时下载内容计算,代价高,rc.md 原文明确警告“may be slow and use lots of data!”。
在 Dropbox 等不提供通用哈希的后端上,CLI 入口还会主动提示建议加 --refresh-times(cmd/bisync/cmd.go),RC 场景下可参考该策略调整 compare 选项。
4.4 maxLock 与锁文件过期机制
maxLock 决定并发保护:bisync 用工作目录下的 .lck 锁文件防止同一对路径并发运行。从源码看(cmd/bisync/lockfile.go):
- 取值为 0 时视为“永不过期”,内部换算为约 200 年的哨兵值
basicallyforever; - 取值小于 2 分钟会被强制钳制为 2 分钟(因此 rc.md 标注 minimum: 2m);
- 运行期间按
maxLock - 1 分钟周期自动续期锁文件(lockfile.go#L133-L158),锁内容含 session、PID、续期与过期时间(JSON)。
若发现未过期锁,bisync 会中止并提示用 rclone deletefile "<lock>" 手动清除(lockfile.go#L29-L52);锁文件过期或不可读时,列表文件会被标记为失败(markFailed 重命名为 *.lst-err),迫使下一次运行在 --recover 或 --resync 下重建。这意味着 RC 长时任务若设置了 maxLock,中断恢复路径是明确且可预期的。
4.5 filtersFile 的变更校验
filtersFile 并非简单加载过滤规则。cmd/bisync/cmd.go 的 applyFilters 会对过滤文件计算 MD5,与旁边 <filtersFile>.md5 记录比对:文件被改过且未处于 resync 模式时,直接报错要求先跑 --resync;resync 模式下则把新哈希写回(dryRun 时跳过写入)。这保证了“过滤规则变更必须显式重新 resync”的安全语义,RC 调用方应把 resync 与 filtersFile 变更成对使用。
五、执行流程与返回值
参数解析完成后,rcBisync 依次:
- 用
rc.GetFsNamed(octx, in, "path1"/"path2")从 RC 参数中解析出两个文件系统(支持 remote 名与路径,等价于 CLI 的位置参数); - 通过
bilib.CaptureOutput捕获 stdout 后调用核心Bisync(octx, fs1, fs2, opt)(同步主流程在 cmd/bisync/operations.go),并把捕获的输出同时写到日志; - 解析工作目录:未指定
workdir时用DefaultWorkdir,否则取其绝对路径,再基于两侧 fs 生成会话的basePath。
最终返回的 JSON 字段(rc.go#L187-L195):
| 返回字段 | 含义 |
|---|---|
| output | 本次 bisync 运行捕获的完整控制台输出 |
| session | 由两侧 fs 计算出的会话名(bilib.SessionName),标识“这一对路径”的 bisync 会话 |
| workDir | 实际使用的工作目录(绝对路径) |
| basePath | 该会话在工作目录下的基础路径(列表/锁文件以其为前缀) |
| listing1 / listing2 | Path1 / Path2 的列表文件路径(basePath + ".path1.lst" / .path2.lst) |
| logFile | 当前 rclone 日志文件路径 |
这些字段让 RC 调用方无需解析 output 文本,就能直接定位 bisync 的会话状态文件(列表、*.lck 锁文件、*.lst-err 失败标记等),对做自动化运维面板非常有用。
六、典型 RC 调用示例
结合 rc.md 的参数与第二节的方式,一个安全的首次初始化调用可以是:
rclone rcd --rc-addr 127.0.0.1:5572 &
rclone rc sync/bisync path1=remote1:path1 path2=remote2:path2 \
resync=true dryRun=true compare=size,modtime,checksum \
slowHashSyncOnly=true checkSync=only
resync=true:首次运行建立两侧基线列表(等价 CLI--resync);dryRun=true:只推演不落盘,先检查output中的 diff 报告;compare/slowHashSyncOnly:在支持哈希的后端上用更严格的比较;- 确认无误后去掉
dryRun正式 resync;后续例行同步不再传resync(这与 docs/content/bisync.md “For successive sync runs, leave off the --resync flag” 的要求一致)。
若需要空目录与容错能力,可再叠加 createEmptySrcDirs=true resilient=true recover=true;若希望锁在异常中断后有界过期,追加 maxLock=30m 即可(内部会自动续期,见 4.4 节)。
七、相关文档与源码索引
- RC 参数契约(本文主体):cmd/bisync/rc.md
- RC 注册与参数解析实现:cmd/bisync/rc.go
- 文档生成器(rc.md 的来源):cmd/bisync/help.go
- flag 定义、
Options结构体与默认值:cmd/bisync/cmd.go - 锁文件创建/续期/过期:cmd/bisync/lockfile.go
- bisync 完整使用手册(操作细节、限制、排障、cron 用法):docs/content/bisync.md
- 全量 RC 接口文档中的 sync/bisync 章节:docs/content/rc.md
- 会话工作目录命名工具包:cmd/bisync/bilib
适用前提与限制:bisync 自 v1.58 引入(见 cmd/bisync/cmd.go 的 versionIntroduced 标注);本文所有参数名与默认值均以当前仓库源码为准,不同发行版本可能略有差异;bisync 属高级命令,生产使用请先通读 docs/content/bisync.md 的 Limitations 章节。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00