sseSource.ts 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. import { EventSourcePolyfill } from "event-source-polyfill";
  2. class SseSource {
  3. protected readonly url: URL
  4. protected readonly onOpen: (() => void)
  5. protected readonly onMessage: ((eventData: Array<any>) => void)
  6. protected readonly onClose: (() => void)
  7. protected readonly withCredentials: boolean
  8. protected eventSource: EventSourcePolyfill | 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. protected createEventSource(url: string, withCredentials: boolean): EventSourcePolyfill {
  25. return new EventSourcePolyfill(
  26. url,
  27. {
  28. withCredentials: withCredentials,
  29. heartbeatTimeout: 45 * 1000 // in ms
  30. }
  31. );
  32. }
  33. public isConnected () {
  34. return this.eventSource !== null && this.eventSource.readyState === EventSourcePolyfill.OPEN
  35. }
  36. public subscribe () {
  37. if (this.isConnected()) {
  38. throw new Error('SSE - Already subscribed to this event source')
  39. }
  40. if (process.server) {
  41. throw new Error('SSE - Cannot subscribe on server side')
  42. }
  43. this.eventSource = this.createEventSource(this.url.toString(), this.withCredentials)
  44. this.eventSource.onerror = (event) => {
  45. if (event.target.readyState === EventSourcePolyfill.CLOSED) {
  46. console.log("SSE closed");
  47. }
  48. // @ts-ignore
  49. this.eventSource.close();
  50. }
  51. this.eventSource.onopen = () => {
  52. console.log('SSE - Listening for events...')
  53. this.onOpen()
  54. }
  55. this.eventSource.onmessage = event => {
  56. const data = JSON.parse(event.data)
  57. this.onMessage(data)
  58. }
  59. }
  60. public unsubscribe () {
  61. if (this.eventSource === null || this.eventSource.readyState === EventSourcePolyfill.CLOSED) {
  62. return
  63. }
  64. this.eventSource.close()
  65. this.onClose()
  66. console.log('SSE - Subscription closed')
  67. }
  68. }
  69. export default SseSource