websocket.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. import { buttonResults } from '../resources/vue/stores/buttonResults.js'
  2. import { rateLimits } from '../resources/vue/stores/rateLimits.js'
  3. import { connectionState } from '../resources/vue/stores/connectionState.js'
  4. const RECONNECT_DELAY_MS = 10000
  5. export function initWebsocket () {
  6. window.addEventListener('EventOutputChunk', onOutputChunk)
  7. window.addEventListener('EventExecutionStarted', onExecutionChanged)
  8. window.addEventListener('EventExecutionFinished', onExecutionChanged)
  9. reconnectWebsocket()
  10. }
  11. window.websocketAvailable = false
  12. async function reconnectWebsocket () {
  13. if (window.websocketAvailable) {
  14. return
  15. }
  16. connectionState.reconnecting = true
  17. connectionState.connected = false
  18. if (connectionState.disconnectedAt == null) {
  19. connectionState.disconnectedAt = Date.now()
  20. }
  21. connectionState.nextReconnectAt = null
  22. try {
  23. window.websocketAvailable = true
  24. const stream = window.client.eventStream()
  25. connectionState.connected = true
  26. connectionState.reconnecting = false
  27. connectionState.nextReconnectAt = null
  28. for await (const e of stream) {
  29. connectionState.disconnectedAt = null
  30. handleEvent(e)
  31. }
  32. } catch (err) {
  33. console.error('Websocket connection failed: ', err)
  34. }
  35. window.websocketAvailable = false
  36. connectionState.connected = false
  37. connectionState.disconnectedAt = connectionState.disconnectedAt ?? Date.now()
  38. connectionState.nextReconnectAt = Date.now() + RECONNECT_DELAY_MS
  39. console.log('Reconnecting websocket in ' + RECONNECT_DELAY_MS + 'ms...')
  40. setTimeout(() => {
  41. reconnectWebsocket()
  42. }, RECONNECT_DELAY_MS)
  43. }
  44. async function refreshInitAfterConfigChange () {
  45. if (!window.client) {
  46. return
  47. }
  48. try {
  49. window.initResponse = await window.client.init({})
  50. if (typeof window.updateHeaderFromInit === 'function') {
  51. window.updateHeaderFromInit()
  52. }
  53. } catch (err) {
  54. console.error('Failed to refresh config from server after EventConfigChanged:', err)
  55. }
  56. }
  57. async function handleConfigChangedEvent (j) {
  58. await refreshInitAfterConfigChange()
  59. window.dispatchEvent(j)
  60. }
  61. function handleEvent (msg) {
  62. const typeName = msg.event.value.$typeName.replace('olivetin.api.v1.', '')
  63. const j = new Event(typeName)
  64. j.payload = msg.event.value
  65. switch (typeName) {
  66. case 'EventConfigChanged':
  67. handleConfigChangedEvent(j).catch((err) => {
  68. console.error('EventConfigChanged handler failed:', err)
  69. })
  70. break
  71. case 'EventOutputChunk':
  72. case 'EventEntityChanged':
  73. window.dispatchEvent(j)
  74. break
  75. case 'EventExecutionFinished':
  76. case 'EventExecutionStarted':
  77. window.dispatchEvent(j)
  78. break
  79. default:
  80. console.warn('Unhandled websocket message type from server: ', typeName)
  81. window.showBigError('ws-unhandled-message', 'handling websocket message', 'Unhandled websocket message type from server: ' + typeName, true)
  82. }
  83. }
  84. function onOutputChunk (evt) {
  85. const chunk = evt.payload
  86. if (window.terminal) {
  87. if (chunk.executionTrackingId === window.terminal.executionTrackingId) {
  88. window.terminal.write(chunk.output)
  89. }
  90. }
  91. }
  92. function onExecutionChanged (evt) {
  93. buttonResults[evt.payload.logEntry.executionTrackingId] = evt.payload.logEntry
  94. const logEntry = evt.payload.logEntry
  95. // Update rate limit store from logEntry if rate limit expiry datetime is provided
  96. if (logEntry && logEntry.datetimeRateLimitExpires && logEntry.bindingId) {
  97. // Parse datetime string "2006-01-02 15:04:05" and convert to Unix timestamp
  98. const date = new Date(logEntry.datetimeRateLimitExpires.replace(' ', 'T') + 'Z')
  99. rateLimits[logEntry.bindingId] = date.getTime() / 1000
  100. } else if (logEntry && logEntry.bindingId) {
  101. // Clear rate limit if not set
  102. rateLimits[logEntry.bindingId] = 0
  103. }
  104. }