sseSource.ts 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. import { EventSourcePolyfill } from "event-source-polyfill";
  2. class SseSource {
  3. private readonly url: URL
  4. private readonly onOpen: (() => void)
  5. private readonly onMessage: ((eventData: Array<any>) => void)
  6. private readonly onClose: (() => void)
  7. private readonly withCredentials: boolean
  8. private eventSource: EventSource | null = null
  9. constructor(
  10. mercureHubBaseUrl: string,
  11. topic: string,
  12. onOpen: (() => void),
  13. onMessage: ((eventData: Array<any>) => void),
  14. onClose: (() => void),
  15. withCredentials: boolean = true
  16. ) {
  17. this.url = new URL(mercureHubBaseUrl)
  18. this.url.searchParams.append('topic', topic)
  19. this.onOpen = onOpen
  20. this.onMessage = onMessage
  21. this.onClose = onClose
  22. this.withCredentials = withCredentials
  23. }
  24. isConnected () {
  25. return this.eventSource !== null && this.eventSource.readyState === EventSource.OPEN
  26. }
  27. public subscribe () {
  28. if (this.isConnected()) {
  29. throw new Error('SSE - Already subscribed to this event source')
  30. }
  31. if (process.server) {
  32. throw new Error('SSE - Cannot subscribe on server side')
  33. }
  34. this.eventSource = new EventSourcePolyfill(
  35. this.url.toString(),
  36. {
  37. withCredentials: this.withCredentials,
  38. heartbeatTimeout: 45 * 1000 // in ms, timeout can not be disabled yet, so I set it very large instead
  39. }
  40. );
  41. this.eventSource.onerror = (event) => {
  42. console.error('SSE - An error happened')
  43. }
  44. this.eventSource.onopen = () => {
  45. console.log('SSE - Listening for events...')
  46. this.onOpen()
  47. }
  48. this.eventSource.onmessage = event => {
  49. const data = JSON.parse(event.data)
  50. this.onMessage(data)
  51. }
  52. }
  53. public unsubscribe () {
  54. if (this.eventSource === null || this.eventSource.readyState === EventSource.CLOSED) {
  55. return
  56. }
  57. this.eventSource.close()
  58. this.onClose()
  59. console.log('SSE - Subscription closed')
  60. }
  61. }
  62. export default SseSource