@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.
Files changed (3) hide show
  1. package/index.js +25 -0
  2. package/package.json +2 -2
  3. 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.1.10",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
5
  "title": "云端同步",
6
- "description": "云端同步:subprocess 通道自动用 shell 包壳(HarmonyOS/DSHM 可跑)、设备模式默认值、dropbear 兼容、永久错误停止重试、传输诊断。",
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'), '')),