sync fixes:
- file counter - popup text - default settings not syncing
This commit is contained in:
parent
f0e097fa76
commit
b087db1b4d
4 changed files with 69 additions and 38 deletions
|
|
@ -167,6 +167,7 @@
|
||||||
"lansync.defaults": "Default settings (default Wine and prefix)",
|
"lansync.defaults": "Default settings (default Wine and prefix)",
|
||||||
"lansync.force": "Force sync all files (skip the hash check and overwrite everything)",
|
"lansync.force": "Force sync all files (skip the hash check and overwrite everything)",
|
||||||
"lansync.mirrorWarning": "This device is the source of truth: on the other device, files and items that do not exist here will be deleted.",
|
"lansync.mirrorWarning": "This device is the source of truth: on the other device, files and items that do not exist here will be deleted.",
|
||||||
|
"lansync.incomingMirror": "The other device is the source of truth: files and items on this device that do not exist there will be deleted.",
|
||||||
"lansync.start": "Start sync",
|
"lansync.start": "Start sync",
|
||||||
"lansync.progress": "Syncing to {0}…",
|
"lansync.progress": "Syncing to {0}…",
|
||||||
"lansync.phase.scan": "Preparing {0}",
|
"lansync.phase.scan": "Preparing {0}",
|
||||||
|
|
|
||||||
|
|
@ -167,6 +167,7 @@
|
||||||
"lansync.defaults": "Ustawienia domyślne (domyślne Wine i prefiks)",
|
"lansync.defaults": "Ustawienia domyślne (domyślne Wine i prefiks)",
|
||||||
"lansync.force": "Wymuś synchronizację wszystkich plików (pomiń sprawdzanie hashy i nadpisz wszystko)",
|
"lansync.force": "Wymuś synchronizację wszystkich plików (pomiń sprawdzanie hashy i nadpisz wszystko)",
|
||||||
"lansync.mirrorWarning": "To urządzenie jest źródłem prawdy: na drugim urządzeniu pliki i elementy, których tu nie ma, zostaną usunięte.",
|
"lansync.mirrorWarning": "To urządzenie jest źródłem prawdy: na drugim urządzeniu pliki i elementy, których tu nie ma, zostaną usunięte.",
|
||||||
|
"lansync.incomingMirror": "Drugie urządzenie jest źródłem prawdy: pliki i elementy na tym urządzeniu, których tam nie ma, zostaną usunięte.",
|
||||||
"lansync.start": "Rozpocznij synchronizację",
|
"lansync.start": "Rozpocznij synchronizację",
|
||||||
"lansync.progress": "Synchronizowanie na {0}…",
|
"lansync.progress": "Synchronizowanie na {0}…",
|
||||||
"lansync.phase.scan": "Przygotowywanie {0}",
|
"lansync.phase.scan": "Przygotowywanie {0}",
|
||||||
|
|
|
||||||
|
|
@ -1337,13 +1337,13 @@ async function runLanSync(device, code, categories, force) {
|
||||||
state.lanPushing = true
|
state.lanPushing = true
|
||||||
window.plwl.onLanSyncProgress(data => {
|
window.plwl.onLanSyncProgress(data => {
|
||||||
if (!active) return
|
if (!active) return
|
||||||
// Every line keeps its value while the sync moves between phases: hashing
|
// Every line keeps its value while the sync moves between phases: the
|
||||||
// reports its own file counter, copying its own, and the bar follows the
|
// file counter is CUMULATIVE across units (it never resets to 0/N with
|
||||||
// bytes the whole way through
|
// the next app) and phases that move no files simply do not touch it -
|
||||||
|
// only the byte bar follows the phase being worked on
|
||||||
phase.textContent = t('lansync.phase.' + data.phase, data.label || '').trim()
|
phase.textContent = t('lansync.phase.' + data.phase, data.label || '').trim()
|
||||||
renderProgressBar(bar, ...barValues(data))
|
renderProgressBar(bar, ...barValues(data))
|
||||||
if (data.total > 0) count.textContent = t('lansync.progressFiles', data.done, data.total)
|
if (data.total > 0) count.textContent = t('lansync.progressFiles', data.done, data.total)
|
||||||
else count.textContent = ''
|
|
||||||
stats.textContent = lanStatsLine(data.items, data.itemsDone, data.totals)
|
stats.textContent = lanStatsLine(data.items, data.itemsDone, data.totals)
|
||||||
bytes.textContent = lanBytesLine(data.bytes, data.totalBytes)
|
bytes.textContent = lanBytesLine(data.bytes, data.totalBytes)
|
||||||
})
|
})
|
||||||
|
|
@ -1427,7 +1427,9 @@ function onLanIncoming(info) {
|
||||||
modal.querySelector('#ls-incoming-title').textContent = t('lansync.incomingTitle', name)
|
modal.querySelector('#ls-incoming-title').textContent = t('lansync.incomingTitle', name)
|
||||||
modal.querySelector('#ls-incoming-text').textContent = t('lansync.incomingText', name)
|
modal.querySelector('#ls-incoming-text').textContent = t('lansync.incomingText', name)
|
||||||
modal.querySelector('#ls-incoming-what').textContent = parts.length ? parts.join(' · ') : t('lansync.incomingNothing')
|
modal.querySelector('#ls-incoming-what').textContent = parts.length ? parts.join(' · ') : t('lansync.incomingNothing')
|
||||||
modal.querySelector('#ls-incoming-warning').textContent = t('lansync.mirrorWarning')
|
// the SENDER is the source of truth: the warning is phrased from this
|
||||||
|
// (receiving) side's point of view, not the send modal's mirrorWarning
|
||||||
|
modal.querySelector('#ls-incoming-warning').textContent = t('lansync.incomingMirror')
|
||||||
modal.querySelector('#ls-incoming-decline').textContent = t('lansync.decline')
|
modal.querySelector('#ls-incoming-decline').textContent = t('lansync.decline')
|
||||||
modal.querySelector('#ls-incoming-accept').textContent = t('lansync.accept')
|
modal.querySelector('#ls-incoming-accept').textContent = t('lansync.accept')
|
||||||
const answer = accept => {
|
const answer = accept => {
|
||||||
|
|
@ -1563,19 +1565,24 @@ function renderReceiving(info) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Data received from another device changed the local files: reload every
|
// Data received from another device changed the local files: reload every
|
||||||
// list so the views show the merged library instead of stale state.
|
// list so the views show the merged library instead of stale state. Settings
|
||||||
|
// too - a sync with "Default settings" rewrote the default wine/prefix on
|
||||||
|
// disk, and the settings view would keep showing the values from before.
|
||||||
async function reloadLocalData() {
|
async function reloadLocalData() {
|
||||||
const [wines, prefixes, games] = await Promise.all([
|
const [wines, prefixes, games, settings] = await Promise.all([
|
||||||
window.plwl.winesList(),
|
window.plwl.winesList(),
|
||||||
window.plwl.prefixesList(),
|
window.plwl.prefixesList(),
|
||||||
window.plwl.gamesList()
|
window.plwl.gamesList(),
|
||||||
|
window.plwl.settingsGet()
|
||||||
])
|
])
|
||||||
state.wines = wines
|
state.wines = wines
|
||||||
state.prefixes = prefixes
|
state.prefixes = prefixes
|
||||||
state.games = games
|
state.games = games
|
||||||
|
state.settings = settings
|
||||||
if (state.currentView === 'library') renderLibrary()
|
if (state.currentView === 'library') renderLibrary()
|
||||||
else if (state.currentView === 'wines') renderWines()
|
else if (state.currentView === 'wines') renderWines()
|
||||||
else if (state.currentView === 'prefixes') renderPrefixes()
|
else if (state.currentView === 'prefixes') renderPrefixes()
|
||||||
|
else if (state.currentView === 'settings') renderSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
function wireLanSync() {
|
function wireLanSync() {
|
||||||
|
|
|
||||||
|
|
@ -297,31 +297,45 @@ function createPusher(api) {
|
||||||
// show "1.2 GB / 3.4 GB" instead of only what has already arrived
|
// show "1.2 GB / 3.4 GB" instead of only what has already arrived
|
||||||
let plannedBytes = 0
|
let plannedBytes = 0
|
||||||
let itemsSeen = 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
|
// the bar tracks the PHASE being worked on (its own bytes), never a
|
||||||
// leftover from the phase before: hashing starts from an empty bar
|
// leftover from the phase before: hashing starts from an empty bar
|
||||||
let barBytes = 0
|
let barBytes = 0
|
||||||
let barTotal = 0
|
let barTotal = 0
|
||||||
const snapshot = (phase, unit, done, total) => ({
|
const snapshot = (phase, unit, done, total) => {
|
||||||
stage: phase,
|
const data = {
|
||||||
phase,
|
stage: phase,
|
||||||
kind: (unit && unit.kind) || '',
|
phase,
|
||||||
id: (unit && unit.id) || '',
|
kind: (unit && unit.kind) || '',
|
||||||
key: (unit && unit.key) || '',
|
id: (unit && unit.id) || '',
|
||||||
unit: (unit && unit.label) || '',
|
key: (unit && unit.key) || '',
|
||||||
label: (unit && unit.label) || '',
|
unit: (unit && unit.label) || '',
|
||||||
name: (unit && unit.label) || '',
|
label: (unit && unit.label) || '',
|
||||||
done,
|
name: (unit && unit.label) || '',
|
||||||
total,
|
bytes: summary.bytes,
|
||||||
bytes: summary.bytes,
|
totalBytes: plannedBytes,
|
||||||
totalBytes: plannedBytes,
|
units: summary.units,
|
||||||
units: summary.units,
|
unitsDone: itemsSeen,
|
||||||
unitsDone: itemsSeen,
|
items: { ...summary.items },
|
||||||
items: { ...summary.items },
|
itemsDone: { ...finished },
|
||||||
itemsDone: { ...finished },
|
totals: { ...totals },
|
||||||
totals: { ...totals },
|
barBytes,
|
||||||
barBytes,
|
barTotalBytes: barTotal
|
||||||
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
|
// hashing and copying walk thousands of files: the state is snapshotted on
|
||||||
// every file but forwarded a few times per second (phase changes always
|
// every file but forwarded a few times per second (phase changes always
|
||||||
// go through, so nothing on screen ever jumps backwards)
|
// go through, so nothing on screen ever jumps backwards)
|
||||||
|
|
@ -342,13 +356,15 @@ function createPusher(api) {
|
||||||
itemsSeen += 1
|
itemsSeen += 1
|
||||||
barBytes = 0
|
barBytes = 0
|
||||||
barTotal = 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) => {
|
const entries = await buildManifest(roots, !!force, (done, total, hashedBytes, totalBytes) => {
|
||||||
barBytes = hashedBytes
|
barBytes = hashedBytes
|
||||||
barTotal = totalBytes
|
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 })
|
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}`)
|
if (!plan.data || !plan.data.ok) throw new Error((plan.data && plan.data.error) || `http-${plan.status}`)
|
||||||
const upload = new Set(plan.data.upload || [])
|
const upload = new Set(plan.data.upload || [])
|
||||||
|
|
@ -365,6 +381,7 @@ function createPusher(api) {
|
||||||
pending.push(entry)
|
pending.push(entry)
|
||||||
plannedBytes += entry.size || 0
|
plannedBytes += entry.size || 0
|
||||||
}
|
}
|
||||||
|
allTotal += pending.length
|
||||||
// a few files in flight at once: with thousands of small ones the
|
// 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
|
// round trip to the other machine costs more than the bytes do
|
||||||
// the files that were already identical never move, so the bar counts
|
// the files that were already identical never move, so the bar counts
|
||||||
|
|
@ -372,7 +389,7 @@ function createPusher(api) {
|
||||||
if (pending.length) {
|
if (pending.length) {
|
||||||
barBytes = 0
|
barBytes = 0
|
||||||
barTotal = pending.reduce((sum, entry) => sum + (entry.size || 0), 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 failed = null
|
||||||
let done = 0
|
let done = 0
|
||||||
|
|
@ -387,12 +404,17 @@ function createPusher(api) {
|
||||||
summary.uploaded++
|
summary.uploaded++
|
||||||
summary.bytes += entry.size || 0
|
summary.bytes += entry.size || 0
|
||||||
barBytes += 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)
|
if (typeof api.mapLimit === 'function') await api.mapLimit(pending, UPLOAD_CONCURRENCY, send)
|
||||||
else for (const entry of pending) await send(entry)
|
else for (const entry of pending) await send(entry)
|
||||||
if (failed) throw failed
|
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: {} })
|
const commit = await httpJson(device, 'POST', `/plwl/unit/commit?token=${encodeURIComponent(token)}&unit=${encodeURIComponent(unit.key)}`, { json: {} })
|
||||||
if (commit.data && commit.data.deleted) {
|
if (commit.data && commit.data.deleted) {
|
||||||
summary.deleted += 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
|
// a finished unit leaves a finished bar behind, even one that sent none
|
||||||
barTotal = barTotal || 1
|
barTotal = barTotal || 1
|
||||||
barBytes = barTotal
|
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 })
|
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}`)
|
if (!applied.data || !applied.data.ok) throw new Error((applied.data && applied.data.error) || `http-${applied.status}`)
|
||||||
for (const key of ['apps', 'wines', 'prefixes']) {
|
for (const key of ['apps', 'wines', 'prefixes']) {
|
||||||
|
|
@ -412,7 +434,7 @@ function createPusher(api) {
|
||||||
if (deleted) summary[key].deleted += deleted
|
if (deleted) summary[key].deleted += deleted
|
||||||
}
|
}
|
||||||
if (applied.data.deleted) summary.deleted += applied.data.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()
|
await end()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
await end()
|
await end()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue