@logux/client
Version:
Logux base components to build web client
113 lines (98 loc) • 2.9 kB
JavaScript
const NO_JIGGLING_TIMEOUT = 500
export function status(client, callback, options = {}) {
let observable = client.on ? client : client.node
let disconnected = observable.state === 'disconnected'
let wait = false
let error = false
if (typeof options.duration === 'undefined') options.duration = 3000
let timeout
let unbind = []
let processing = {}
function setSynchronized() {
if (Object.keys(processing).length === 0) {
clearTimeout(timeout)
if (wait) {
wait = false
callback('synchronizedAfterWait')
timeout = setTimeout(() => {
callback('synchronized')
}, options.duration)
} else {
timeout = setTimeout(() => {
callback('synchronized')
}, NO_JIGGLING_TIMEOUT)
}
}
}
function changeState() {
clearTimeout(timeout)
if (observable.state === 'disconnected') {
disconnected = true
if (!error) callback(wait ? 'wait' : 'disconnected')
} else if (observable.state === 'synchronized') {
error = false
disconnected = false
setSynchronized()
} else if (observable.state === 'connecting') {
if (!error) {
timeout = setTimeout(() => {
callback('connecting' + (wait ? 'AfterWait' : ''))
}, 100)
}
} else if (!error) {
callback(client.state + (wait ? 'AfterWait' : ''))
}
}
unbind.push(observable.on('state', changeState))
unbind.push(
client.node.on('error', e => {
if (e.type === 'wrong-protocol' || e.type === 'wrong-subprotocol') {
error = true
callback('protocolError')
} else if (e.type === 'wrong-credentials') {
error = true
callback('wrongCredentials')
} else if (e.type !== 'timeout') {
error = true
callback('syncError', { error: e })
}
})
)
unbind.push(
client.node.on('clientError', e => {
callback('syncError', { error: e })
})
)
let log = client.on ? client : client.log
unbind.push(
log.on('add', (action, meta) => {
if (action.type === 'logux/subscribe') {
return
} else if (action.type === 'logux/unsubscribe') {
return
}
if (action.type === 'logux/processed') {
delete processing[action.id]
setSynchronized()
} else if (action.type === 'logux/undo') {
delete processing[action.id]
} else if (meta.sync) {
processing[meta.id] = true
}
if (action.type === 'logux/undo' && action.reason) {
if (action.reason === 'denied') {
callback('denied', { action, meta })
} else {
callback('error', { action, meta })
}
} else if (disconnected && meta.sync && meta.added) {
if (!wait) callback('wait')
wait = true
}
})
)
changeState()
return () => {
for (let i of unbind) i()
}
}