Better visual sync

This commit is contained in:
Magnus Åhall 2025-11-29 16:45:56 +01:00
parent 40a68d6ad0
commit d9c82868ab
6 changed files with 130 additions and 106 deletions

View file

@ -1,31 +1,11 @@
import { API } from 'api'
import { Node } from 'node'
import { h, Component } from 'preact'
import htm from 'htm'
const html = htm.bind(h)
const SYNC_COUNT = 1
const SYNC_HANDLED = 2
const SYNC_DONE = 3
export class Sync {
constructor() {//{{{
this.listeners = []
this.messagesReceived = []
}//}}}
addListener(fn, runMessageQueue) {//{{{
// Some handlers won't be added until a time after sync messages have been added to the queue.
// This is an opportunity for the handler to receive the old messages in order.
if (runMessageQueue)
for (const msg of this.messagesReceived)
fn(msg)
this.listeners.push(fn)
}//}}}
pushMessage(msg) {//{{{
this.messagesReceived.push(msg)
for (const fn of this.listeners)
fn(msg)
}//}}}
async run() {//{{{
try {
@ -38,8 +18,8 @@ export class Sync {
let nodeCount = await this.getNodeCount(oldMax)
nodeCount += await nodeStore.sendQueue.count()
const msg = { op: SYNC_COUNT, count: nodeCount }
this.pushMessage(msg)
_mbus.dispatch('SYNC_COUNT', { count: nodeCount })
await this.nodesFromServer(oldMax)
.then(durationNodes => {
@ -49,7 +29,7 @@ export class Sync {
await this.nodesToServer()
} finally {
this.pushMessage({ op: SYNC_DONE })
_mbus.dispatch('SYNC_DONE')
}
}//}}}
async getNodeCount(oldMax) {//{{{
@ -60,6 +40,7 @@ export class Sync {
async nodesFromServer(oldMax) {//{{{
const syncStart = Date.now()
let syncEnd
let handled = 0
try {
let currMax = oldMax
let offset = 0
@ -86,9 +67,14 @@ export class Sync {
for (const i in res.Nodes) {
backendNode = new Node(res.Nodes[i], -1)
await window._sync.handleNode(backendNode)
handled++
if (handled % 100 === 0)
_mbus.dispatch('SYNC_HANDLED', { handled })
}
} while (res.Continue)
_mbus.dispatch('SYNC_HANDLED', { handled })
nodeStore.setAppState('latest_sync_node', currMax)
} catch (e) {
@ -130,7 +116,7 @@ export class Sync {
} catch (e) {
console.error(e)
} finally {
this.pushMessage({ op: SYNC_HANDLED, count: 1 })
//_mbus.dispatch('SYNC_HANDLED', { count: 1 })
}
}//}}}
async nodesToServer() {//{{{
@ -157,7 +143,7 @@ export class Sync {
// Nodes are archived on server and can now be deleted from the send queue.
const keys = nodesToSend.map(node => node.ClientSequence)
await nodeStore.sendQueue.delete(keys)
this.pushMessage({ op: SYNC_HANDLED, count: nodesToSend.length })
_mbus.dispatch('SYNC_UPLOADED', { count: nodesToSend.length })
} catch (e) {
console.trace(e)
@ -168,11 +154,28 @@ export class Sync {
}//}}}
}
export class SyncProgress extends Component {
constructor() {//{{{
super()
export class SyncProgress {
constructor(parentEl) {//{{{
this.reset()
_mbus.subscribe('SYNC_COUNT', event => this.progressHandler(event))
_mbus.subscribe('SYNC_HANDLED', event => this.progressHandler(event))
_mbus.subscribe('SYNC_DONE', event => this.progressHandler(event))
this.el = this.createElements()
parentEl.replaceChildren(this.el)
}//}}}
createElements() {
const div = document.createElement('div')
div.classList.add('container')
div.innerHTML = `
<progress min=0 max=137 value=0></progress>
<div class="count">0 / 0</div>
`
this.elProgress = div.querySelector('progress')
this.elCount = div.querySelector('.count')
return div
}
reset() {//{{{
this.forceUpdateRequest = null
this.state = {
@ -182,9 +185,6 @@ export class SyncProgress extends Component {
}
document.getElementById('sync-progress')?.classList.remove('hidden')
}//}}}
componentDidMount() {//{{{
window._sync.addListener(msg => this.progressHandler(msg), true)
}//}}}
getSnapshotBeforeUpdate(_, prevState) {//{{{
if (!prevState.syncedDone && this.state.syncedDone)
setTimeout(() => document.getElementById('sync-progress')?.classList.add('hidden'), 750)
@ -202,19 +202,22 @@ export class SyncProgress extends Component {
)
}
}//}}}
progressHandler(msg) {//{{{
switch (msg.op) {
case SYNC_COUNT:
this.setState({ nodesToSync: msg.count })
progressHandler(event) {//{{{
const eventData = event.detail.data
switch (event.type) {
case 'SYNC_COUNT':
console.log(eventData.count)
this.state.nodesToSync = eventData.count
break
case SYNC_HANDLED:
this.state.nodesSynced += msg.count
case 'SYNC_HANDLED':
console.log('sync handled')
this.state.nodesSynced = eventData.handled
break
case SYNC_DONE:
case 'SYNC_DONE':
// Hides the progress bar.
this.setState({ syncedDone: true })
this.state.syncedDone = true
// Don't update anything if nothing was synced.
if (this.state.nodesSynced === 0)
@ -227,17 +230,19 @@ export class SyncProgress extends Component {
}
break
}
this.render()
}//}}}
render(_, { nodesToSync, nodesSynced }) {//{{{
render() {//{{{
console.log('render', this.state.nodesToSync)
this.elProgress.max = this.state.nodesToSync
this.elProgress.value = this.state.nodesSynced
this.elCount.innerText = `${this.state.nodesSynced} / ${this.state.nodesToSync}`
/*
if (nodesToSync === 0)
return html`<div id="sync-progress"></div>`
*/
return html`
<div id="sync-progress">
<progress min=0 max=${nodesToSync} value=${nodesSynced}></progress>
<div class="count">${nodesSynced} / ${nodesToSync}</div>
</div>
`
}//}}}
}