connection.ts 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. // Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. import { computed, ref, watch } from 'vue'
  3. import {
  4. consumer,
  5. reopenWebSocketConnection,
  6. } from '#shared/server/action_cable/consumer.ts'
  7. import log from '#shared/utils/log.ts'
  8. import {
  9. NotificationTypes,
  10. useNotifications,
  11. } from '#shared/components/CommonNotifications/index.ts'
  12. import { useApplicationLoaded } from '#shared/composables/useApplicationLoaded.ts'
  13. const wsConnectionState = ref(true)
  14. const wsReopening = ref(false)
  15. const { loaded } = useApplicationLoaded()
  16. const isConnectionOpen = () => !loaded.value || consumer.connection.isOpen()
  17. const INTERVAL_CHECK_CONNECTION = 1000
  18. const TIMEOUT_CONFIRM_FAIL = 2000
  19. let faledTimeout: number | null = null
  20. let checkInterval: number | null = null
  21. const clearFailedTimeout = () => {
  22. if (faledTimeout) window.clearTimeout(faledTimeout)
  23. faledTimeout = null
  24. }
  25. const clearCheckInterval = () => {
  26. if (checkInterval) window.clearInterval(checkInterval)
  27. checkInterval = null
  28. }
  29. const checkStatus = () => {
  30. clearCheckInterval()
  31. checkInterval = window.setInterval(() => {
  32. const hasConnection = isConnectionOpen()
  33. if (hasConnection) {
  34. wsConnectionState.value = true
  35. return
  36. }
  37. // if there is no connection, let's wait a few seconds and check again
  38. // pause interval while we wait
  39. clearCheckInterval()
  40. clearFailedTimeout()
  41. faledTimeout = window.setTimeout(() => {
  42. wsConnectionState.value = isConnectionOpen()
  43. checkStatus()
  44. }, TIMEOUT_CONFIRM_FAIL)
  45. }, INTERVAL_CHECK_CONNECTION)
  46. }
  47. checkStatus()
  48. let connectionNotificationId: string
  49. const networkConnectionState = ref(true)
  50. const connected = computed(() => {
  51. return (
  52. (wsReopening.value || wsConnectionState.value) &&
  53. networkConnectionState.value
  54. )
  55. })
  56. const notifications = useNotifications()
  57. watch(
  58. () => connected.value,
  59. (connected) => {
  60. if (connected) {
  61. if (!connectionNotificationId) return
  62. log.debug('Application connection just came up.')
  63. notifications.removeNotification(connectionNotificationId)
  64. } else {
  65. log.debug('Application connection just went down.')
  66. connectionNotificationId = notifications.notify({
  67. message: __('The connection to the server was lost.'),
  68. type: NotificationTypes.Error,
  69. persistent: true,
  70. })
  71. }
  72. },
  73. )
  74. export const recordCommunicationSuccess = (): void => {
  75. networkConnectionState.value = true
  76. }
  77. export const recordCommunicationFailure = (): void => {
  78. networkConnectionState.value = false
  79. }
  80. export const triggerWebSocketReconnect = (): void => {
  81. wsReopening.value = true
  82. reopenWebSocketConnection()
  83. .then(() => {
  84. // Set this before setting wsReopening, otherwise it would be set later by the interval,
  85. // causing false positives.
  86. wsConnectionState.value = true
  87. })
  88. .finally(() => {
  89. wsReopening.value = false
  90. })
  91. }