olivetin/frontend/resources/vue/stores/bindingExecutionState.js

135 lines
3.3 KiB
JavaScript

import { reactive } from 'vue'
import { buttonResults } from './buttonResults.js'
const INDICATOR_SHOW_DELAY_MS = 1000
const PENDING_FLASH_TTL_MS = 5000
export const bindingExecutionState = reactive({})
export const pendingBindingFlash = reactive({})
const pendingShowTimers = {}
const pendingFlashExpireTimers = {}
function cancelPendingShowTimer (bindingId) {
const timer = pendingShowTimers[bindingId]
if (timer != null) {
clearTimeout(timer)
delete pendingShowTimers[bindingId]
}
}
function scheduleIndicatorShow (bindingId) {
cancelPendingShowTimer(bindingId)
pendingShowTimers[bindingId] = setTimeout(() => {
delete pendingShowTimers[bindingId]
recomputeBindingExecutionState(bindingId)
}, INDICATOR_SHOW_DELAY_MS)
}
export function setBindingExecutionState (bindingId, hasRunning, hasQueued) {
if (!bindingId) {
return
}
if (!hasRunning && !hasQueued) {
delete bindingExecutionState[bindingId]
return
}
bindingExecutionState[bindingId] = { hasRunning, hasQueued }
}
export function recomputeBindingExecutionState (bindingId) {
if (!bindingId) {
return
}
let hasRunning = false
let hasQueued = false
for (const trackingId in buttonResults) {
const entry = buttonResults[trackingId]
if (!entry || entry.bindingId !== bindingId || entry.executionFinished) {
continue
}
if (entry.executionStarted) {
hasRunning = true
} else {
hasQueued = true
}
}
setBindingExecutionState(bindingId, hasRunning, hasQueued)
}
export function applyExecutionStartedBindingState (logEntry) {
if (!logEntry?.bindingId || logEntry.executionFinished) {
return
}
scheduleIndicatorShow(logEntry.bindingId)
}
export function applyExecutionFinishedBindingState (logEntry) {
if (!logEntry?.bindingId) {
return
}
cancelPendingShowTimer(logEntry.bindingId)
recomputeBindingExecutionState(logEntry.bindingId)
recordPendingBindingFlash(logEntry)
}
function cancelPendingFlashExpireTimer (bindingId) {
const timer = pendingFlashExpireTimers[bindingId]
if (timer != null) {
clearTimeout(timer)
delete pendingFlashExpireTimers[bindingId]
}
}
export function recordPendingBindingFlash (logEntry) {
if (!logEntry?.bindingId || !logEntry.executionFinished) {
return
}
const bindingId = logEntry.bindingId
cancelPendingFlashExpireTimer(bindingId)
pendingBindingFlash[bindingId] = {
executionTrackingId: logEntry.executionTrackingId,
timedOut: logEntry.timedOut,
blocked: logEntry.blocked,
exitCode: logEntry.exitCode,
datetimeStarted: logEntry.datetimeStarted,
datetimeFinished: logEntry.datetimeFinished,
recordedAt: Date.now()
}
pendingFlashExpireTimers[bindingId] = setTimeout(() => {
delete pendingFlashExpireTimers[bindingId]
const current = pendingBindingFlash[bindingId]
if (current?.executionTrackingId === logEntry.executionTrackingId) {
delete pendingBindingFlash[bindingId]
}
}, PENDING_FLASH_TTL_MS)
}
export function consumePendingBindingFlash (bindingId) {
if (!bindingId || pendingBindingFlash[bindingId] === undefined) {
return null
}
const result = pendingBindingFlash[bindingId]
cancelPendingFlashExpireTimer(bindingId)
delete pendingBindingFlash[bindingId]
if (result.recordedAt && (Date.now() - result.recordedAt) > PENDING_FLASH_TTL_MS) {
return null
}
return result
}