@leiyi-works/dsh-cloud-sync 0.1.10 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +25 -0
- package/package.json +2 -2
- package/sync.js +2 -0
package/index.js
CHANGED
|
@@ -74,6 +74,8 @@ export const Config = z.object({
|
|
|
74
74
|
.description('传输停滞判定(毫秒):连续这么久没有数据就断开重试'),
|
|
75
75
|
deviceMode: z.boolean().default(DEFAULTS.deviceMode)
|
|
76
76
|
.description('设备模式:默认每天一次、不带附件/插件源码、不自动整份恢复(手机端建议开)'),
|
|
77
|
+
bidirectional: z.boolean().default(DEFAULTS.bidirectional)
|
|
78
|
+
.description('双向同步:每次同步先把其它机器的新改动拉下来,再推送本机改动(多机使用建议开)'),
|
|
77
79
|
remoteRoot: z.string().default(DEFAULTS.remoteRoot).description('服务器上的备份根目录'),
|
|
78
80
|
machineId: z.string().default('').description('这台机器的槽位名,留空 = 主机名'),
|
|
79
81
|
localPluginRoot: z.string().default(DEFAULTS.localPluginRoot)
|
|
@@ -209,9 +211,32 @@ function createRunner(config) {
|
|
|
209
211
|
}
|
|
210
212
|
current = (async () => {
|
|
211
213
|
try {
|
|
214
|
+
// 双向收敛:先把「其它机器」比本机新的文件拉下来,再推自己的
|
|
215
|
+
let merged = null
|
|
216
|
+
if (kind === 'push' && config.bidirectional !== false && options.pullOthers !== false) {
|
|
217
|
+
try {
|
|
218
|
+
const selfMachine = config.machineId !== '' ? config.machineId : defaultMachineId()
|
|
219
|
+
const listing = await listMachines(config)
|
|
220
|
+
const others = listing.machines.filter((item) => item.id !== selfMachine && item.manifestBytes > 0)
|
|
221
|
+
if (others.length > 0) {
|
|
222
|
+
merged = { machines: [], restored: 0 }
|
|
223
|
+
for (const other of others) {
|
|
224
|
+
const got = await pull({ config, log: lines, from: other.id })
|
|
225
|
+
const restored = Number(got?.restored) || 0
|
|
226
|
+
merged.machines.push(other.id)
|
|
227
|
+
merged.restored += restored
|
|
228
|
+
lines(`已合并 ${other.id} 的改动:${restored} 个文件`)
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
} catch (error) {
|
|
232
|
+
merged = null
|
|
233
|
+
lines(`合并其它机器失败(继续推送本机改动):${error instanceof Error ? error.message : String(error)}`)
|
|
234
|
+
}
|
|
235
|
+
}
|
|
212
236
|
const result = kind === 'push'
|
|
213
237
|
? await push({ config, log: lines, onProgress, auto: options.auto === true })
|
|
214
238
|
: await pull({ config, log: lines, onProgress, from: options.from, force: options.force === true })
|
|
239
|
+
if (merged !== null && kind === 'push') result.mergedFromOthers = merged
|
|
215
240
|
job.result = clean(result)
|
|
216
241
|
job.phase = 'done'
|
|
217
242
|
const next = {
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leiyi-works/dsh-cloud-sync",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"title": "云端同步",
|
|
6
|
-
"description": "
|
|
6
|
+
"description": "云端同步:双向收敛(同步=先拉其它机器新改动再推本机)、subprocess 可移植执行层(手机可跑)、设备模式、dropbear 兼容、永久错误停止重试。",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"author": "leiyi-works",
|
|
9
9
|
"keywords": [
|
package/sync.js
CHANGED
|
@@ -44,6 +44,7 @@ export const DEFAULTS = {
|
|
|
44
44
|
commandTimeoutMs: 60000,
|
|
45
45
|
stallMs: 120000,
|
|
46
46
|
deviceMode: false,
|
|
47
|
+
bidirectional: true,
|
|
47
48
|
remoteRoot: '/opt/dsh-sync',
|
|
48
49
|
connectionFile: '',
|
|
49
50
|
machineId: '',
|
|
@@ -114,6 +115,7 @@ export function normalizeConfig(raw) {
|
|
|
114
115
|
commandTimeoutMs: number('commandTimeoutMs', 240000, 1000),
|
|
115
116
|
stallMs: number('stallMs', 300000, 5000),
|
|
116
117
|
deviceMode: device,
|
|
118
|
+
bidirectional: flag(pick('bidirectional'), DEFAULTS.bidirectional),
|
|
117
119
|
connectionFile: text(pick('connectionFile'), DEFAULTS.connectionFile),
|
|
118
120
|
remoteRoot: text(pick('remoteRoot'), DEFAULTS.remoteRoot).replace(/\/+$/, '') || DEFAULTS.remoteRoot,
|
|
119
121
|
machineId: sanitizeMachineId(text(pick('machineId'), '')),
|