useSSE.ts 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. import type { SSEvent } from 'sse.js'
  2. import { urlJoin } from '@/lib/helper'
  3. import { useSettingsStore, useUserStore } from '@/pinia'
  4. import { storeToRefs } from 'pinia'
  5. import { SSE } from 'sse.js'
  6. const userStore = useUserStore()
  7. const { token } = storeToRefs(userStore)
  8. const settings = useSettingsStore()
  9. export interface SSEOptions {
  10. url: string
  11. // eslint-disable-next-line ts/no-explicit-any
  12. onMessage?: (data: any) => void
  13. onError?: () => void
  14. parseData?: boolean
  15. reconnectInterval?: number
  16. }
  17. /**
  18. * SSE Composable
  19. * Provide the ability to create, manage, and automatically clean up SSE connections
  20. */
  21. export function useSSE() {
  22. const sseInstance = shallowRef<SSE>()
  23. /**
  24. * Connect to SSE service
  25. */
  26. function connect(options: SSEOptions) {
  27. if (!token.value) {
  28. return
  29. }
  30. const {
  31. url,
  32. onMessage,
  33. onError,
  34. parseData = true,
  35. reconnectInterval = 5000,
  36. } = options
  37. const fullUrl = urlJoin(window.location.pathname, url)
  38. const headers = {
  39. Authorization: token.value,
  40. }
  41. if (settings.environment.id) {
  42. headers['X-Node-ID'] = settings.environment.id.toString()
  43. }
  44. const sse = new SSE(fullUrl, {
  45. headers,
  46. })
  47. // Handle messages
  48. sse.onmessage = (e: SSEvent) => {
  49. if (!e.data) {
  50. return
  51. }
  52. try {
  53. const parsedData = parseData ? JSON.parse(e.data) : e.data
  54. onMessage?.(parsedData)
  55. }
  56. catch (error) {
  57. console.error('Error parsing SSE message:', error)
  58. }
  59. }
  60. // Handle errors and reconnect
  61. sse.onerror = () => {
  62. onError?.()
  63. // Reconnect logic
  64. setTimeout(() => {
  65. connect(options)
  66. }, reconnectInterval)
  67. }
  68. sseInstance.value = sse
  69. return sse
  70. }
  71. /**
  72. * Disconnect SSE connection
  73. */
  74. function disconnect() {
  75. if (sseInstance.value) {
  76. sseInstance.value.close()
  77. sseInstance.value = undefined
  78. }
  79. }
  80. // Automatically disconnect when the component is unmounted
  81. if (getCurrentInstance()) {
  82. onUnmounted(() => {
  83. disconnect()
  84. })
  85. }
  86. return {
  87. connect,
  88. disconnect,
  89. sseInstance,
  90. }
  91. }