sync fixes:

- file counter
- popup text
- default settings not syncing
This commit is contained in:
olcxja 2026-10-01 20:57:45 +02:00
commit b087db1b4d
4 changed files with 69 additions and 38 deletions

View file

@ -297,31 +297,45 @@ function createPusher(api) {
// show "1.2 GB / 3.4 GB" instead of only what has already arrived
let plannedBytes = 0
let itemsSeen = 0
// files uploaded/announced in PREVIOUS units: the popup's file counter is
// cumulative across the whole sync (a per-unit counter resets with every
// next app, which reads like progress going backwards)
let allDone = 0
let allTotal = 0
// the bar tracks the PHASE being worked on (its own bytes), never a
// leftover from the phase before: hashing starts from an empty bar
let barBytes = 0
let barTotal = 0
const snapshot = (phase, unit, done, total) => ({
stage: phase,
phase,
kind: (unit && unit.kind) || '',
id: (unit && unit.id) || '',
key: (unit && unit.key) || '',
unit: (unit && unit.label) || '',
label: (unit && unit.label) || '',
name: (unit && unit.label) || '',
done,
total,
bytes: summary.bytes,
totalBytes: plannedBytes,
units: summary.units,
unitsDone: itemsSeen,
items: { ...summary.items },
itemsDone: { ...finished },
totals: { ...totals },
barBytes,
barTotalBytes: barTotal
})
const snapshot = (phase, unit, done, total) => {
const data = {
stage: phase,
phase,
kind: (unit && unit.kind) || '',
id: (unit && unit.id) || '',
key: (unit && unit.key) || '',
unit: (unit && unit.label) || '',
label: (unit && unit.label) || '',
name: (unit && unit.label) || '',
bytes: summary.bytes,
totalBytes: plannedBytes,
units: summary.units,
unitsDone: itemsSeen,
items: { ...summary.items },
itemsDone: { ...finished },
totals: { ...totals },
barBytes,
barTotalBytes: barTotal
}
// only phases that actually move the file counter carry one (the copy
// phase passes absolute, cumulative values); the rest omit it, so the
// popup freezes the last count instead of jumping backwards while this
// unit is still being scanned or compared
if (Number.isFinite(done) && Number.isFinite(total)) {
data.done = done
data.total = total
}
return data
}
// hashing and copying walk thousands of files: the state is snapshotted on
// every file but forwarded a few times per second (phase changes always
// go through, so nothing on screen ever jumps backwards)
@ -342,13 +356,15 @@ function createPusher(api) {
itemsSeen += 1
barBytes = 0
barTotal = 0
emit('scan', unit, 0, 0, true)
emit('scan', unit, null, null, true)
const entries = await buildManifest(roots, !!force, (done, total, hashedBytes, totalBytes) => {
barBytes = hashedBytes
barTotal = totalBytes
emit('hash', unit, done, total)
// the file counter is not touched here: until the plan comes back
// nobody knows how many of this unit's files will actually move
emit('hash', unit, null, null)
})
emit('plan', unit, 0, 0, true)
emit('plan', unit, null, null, true)
const plan = await planUnit(device, token, { ...unit, roots }, entries, !!force, { totals })
if (!plan.data || !plan.data.ok) throw new Error((plan.data && plan.data.error) || `http-${plan.status}`)
const upload = new Set(plan.data.upload || [])
@ -365,6 +381,7 @@ function createPusher(api) {
pending.push(entry)
plannedBytes += entry.size || 0
}
allTotal += pending.length
// a few files in flight at once: with thousands of small ones the
// round trip to the other machine costs more than the bytes do
// the files that were already identical never move, so the bar counts
@ -372,7 +389,7 @@ function createPusher(api) {
if (pending.length) {
barBytes = 0
barTotal = pending.reduce((sum, entry) => sum + (entry.size || 0), 0)
emit('copy', unit, 0, pending.length, true)
emit('copy', unit, allDone, allTotal + pending.length, true)
}
let failed = null
let done = 0
@ -387,12 +404,17 @@ function createPusher(api) {
summary.uploaded++
summary.bytes += entry.size || 0
barBytes += entry.size || 0
emit('copy', unit, done, pending.length)
emit('copy', unit, allDone + done, allTotal + pending.length)
}
if (typeof api.mapLimit === 'function') await api.mapLimit(pending, UPLOAD_CONCURRENCY, send)
else for (const entry of pending) await send(entry)
if (failed) throw failed
emit('copy', unit, done, pending.length, true)
emit('copy', unit, allDone + done, allTotal + pending.length, true)
// this unit's files count towards the running totals only once they
// are really on the wire - the counter holds there while the receiver
// prunes and the next unit is scanned/compared
allDone += pending.length
allTotal += pending.length
const commit = await httpJson(device, 'POST', `/plwl/unit/commit?token=${encodeURIComponent(token)}&unit=${encodeURIComponent(unit.key)}`, { json: {} })
if (commit.data && commit.data.deleted) {
summary.deleted += commit.data.deleted
@ -402,9 +424,9 @@ function createPusher(api) {
// a finished unit leaves a finished bar behind, even one that sent none
barTotal = barTotal || 1
barBytes = barTotal
emit('commit', unit, 0, 0, true)
emit('commit', unit, null, null, true)
}
emit('registry', null, 0, 0, true)
emit('registry', null, null, null, true)
const applied = await httpJson(device, 'POST', `/plwl/apply?token=${encodeURIComponent(token)}`, { json: buildRegistryPayload([...cats]), timeout: 60000 })
if (!applied.data || !applied.data.ok) throw new Error((applied.data && applied.data.error) || `http-${applied.status}`)
for (const key of ['apps', 'wines', 'prefixes']) {
@ -412,7 +434,7 @@ function createPusher(api) {
if (deleted) summary[key].deleted += deleted
}
if (applied.data.deleted) summary.deleted += applied.data.deleted
emit('done', null, summary.uploaded, summary.uploaded, true)
emit('done', null, allDone, allTotal, true)
await end()
} catch (err) {
await end()