126 lines
3.7 KiB
JavaScript
126 lines
3.7 KiB
JavaScript
import { buttonResults } from '../resources/vue/stores/buttonResults.js'
|
|
import { rateLimits } from '../resources/vue/stores/rateLimits.js'
|
|
import { connectionState } from '../resources/vue/stores/connectionState.js'
|
|
|
|
const RECONNECT_DELAY_MS = 10000
|
|
|
|
export function initWebsocket () {
|
|
window.addEventListener('EventOutputChunk', onOutputChunk)
|
|
window.addEventListener('EventExecutionStarted', onExecutionChanged)
|
|
window.addEventListener('EventExecutionFinished', onExecutionChanged)
|
|
|
|
reconnectWebsocket()
|
|
}
|
|
|
|
window.websocketAvailable = false
|
|
|
|
async function reconnectWebsocket () {
|
|
if (window.websocketAvailable) {
|
|
return
|
|
}
|
|
|
|
connectionState.reconnecting = true
|
|
connectionState.connected = false
|
|
if (connectionState.disconnectedAt == null) {
|
|
connectionState.disconnectedAt = Date.now()
|
|
}
|
|
connectionState.nextReconnectAt = null
|
|
|
|
try {
|
|
window.websocketAvailable = true
|
|
const stream = window.client.eventStream()
|
|
connectionState.connected = true
|
|
connectionState.reconnecting = false
|
|
connectionState.nextReconnectAt = null
|
|
for await (const e of stream) {
|
|
connectionState.disconnectedAt = null
|
|
handleEvent(e)
|
|
}
|
|
} catch (err) {
|
|
console.error('Websocket connection failed: ', err)
|
|
}
|
|
|
|
window.websocketAvailable = false
|
|
connectionState.connected = false
|
|
connectionState.disconnectedAt = connectionState.disconnectedAt ?? Date.now()
|
|
connectionState.nextReconnectAt = Date.now() + RECONNECT_DELAY_MS
|
|
console.log('Reconnecting websocket in ' + RECONNECT_DELAY_MS + 'ms...')
|
|
setTimeout(() => {
|
|
reconnectWebsocket()
|
|
}, RECONNECT_DELAY_MS)
|
|
}
|
|
|
|
async function refreshInitAfterConfigChange () {
|
|
if (!window.client) {
|
|
return
|
|
}
|
|
|
|
try {
|
|
window.initResponse = await window.client.init({})
|
|
|
|
if (typeof window.updateHeaderFromInit === 'function') {
|
|
window.updateHeaderFromInit()
|
|
}
|
|
} catch (err) {
|
|
console.error('Failed to refresh config from server after EventConfigChanged:', err)
|
|
}
|
|
}
|
|
|
|
async function handleConfigChangedEvent (j) {
|
|
await refreshInitAfterConfigChange()
|
|
window.dispatchEvent(j)
|
|
}
|
|
|
|
function handleEvent (msg) {
|
|
const typeName = msg.event.value.$typeName.replace('olivetin.api.v1.', '')
|
|
|
|
const j = new Event(typeName)
|
|
j.payload = msg.event.value
|
|
|
|
switch (typeName) {
|
|
case 'EventConfigChanged':
|
|
handleConfigChangedEvent(j).catch((err) => {
|
|
console.error('EventConfigChanged handler failed:', err)
|
|
})
|
|
break
|
|
case 'EventOutputChunk':
|
|
case 'EventEntityChanged':
|
|
window.dispatchEvent(j)
|
|
break
|
|
case 'EventExecutionFinished':
|
|
case 'EventExecutionStarted':
|
|
window.dispatchEvent(j)
|
|
break
|
|
default:
|
|
console.warn('Unhandled websocket message type from server: ', typeName)
|
|
|
|
window.showBigError('ws-unhandled-message', 'handling websocket message', 'Unhandled websocket message type from server: ' + typeName, true)
|
|
}
|
|
}
|
|
|
|
function onOutputChunk (evt) {
|
|
const chunk = evt.payload
|
|
|
|
if (window.terminal) {
|
|
if (chunk.executionTrackingId === window.terminal.executionTrackingId) {
|
|
window.terminal.write(chunk.output)
|
|
}
|
|
}
|
|
}
|
|
|
|
function onExecutionChanged (evt) {
|
|
buttonResults[evt.payload.logEntry.executionTrackingId] = evt.payload.logEntry
|
|
|
|
const logEntry = evt.payload.logEntry
|
|
|
|
// Update rate limit store from logEntry if rate limit expiry datetime is provided
|
|
if (logEntry && logEntry.datetimeRateLimitExpires && logEntry.bindingId) {
|
|
// Parse datetime string "2006-01-02 15:04:05" and convert to Unix timestamp
|
|
const date = new Date(logEntry.datetimeRateLimitExpires.replace(' ', 'T') + 'Z')
|
|
rateLimits[logEntry.bindingId] = date.getTime() / 1000
|
|
} else if (logEntry && logEntry.bindingId) {
|
|
// Clear rate limit if not set
|
|
rateLimits[logEntry.bindingId] = 0
|
|
}
|
|
}
|