浏览代码

mercure implementation: refactoring (ongoing)

Olivier Massot 3 年之前
父节点
当前提交
de307efcc2
共有 3 个文件被更改,包括 102 次插入20 次删除
  1. 23 2
      layouts/default.vue
  2. 22 18
      pages/cmf_licence/organization.vue
  3. 57 0
      services/sse/sse.ts

+ 23 - 2
layouts/default.vue

@@ -23,15 +23,25 @@
 </template>
 
 <script lang="ts">
-import { computed, ComputedRef, defineComponent, reactive, useContext } from '@nuxtjs/composition-api'
+import {
+  computed,
+  ComputedRef,
+  defineComponent,
+  onBeforeUnmount,
+  onMounted,
+  reactive,
+  useContext
+} from '@nuxtjs/composition-api'
 import { $useMenu } from '@/composables/layout/menu'
+import Sse from "~/services/sse/sse";
+import sse from '~/services/sse/sse';
 
 export default defineComponent({
   name: 'DefaultLayout',
 
   middleware: ['auth'],
   setup () {
-    const { store } = useContext()
+    const { store, $config } = useContext()
     const menu = $useMenu.setupContext().useLateralMenuConstruct()
 
     const properties = reactive({
@@ -50,6 +60,17 @@ export default defineComponent({
       properties.miniVariant = miniVariant
     }
 
+
+    const sse = new Sse($config.baseUrl_mercure, store.state.profile.access.id)
+
+    onMounted(() => {
+      sse.subscribe()
+      window.addEventListener('beforeunload', () => { sse.unsubscribe() })
+    })
+    onBeforeUnmount(() => {
+      sse.unsubscribe()
+    })
+
     return {
       properties,
       menu,

+ 22 - 18
pages/cmf_licence/organization.vue

@@ -34,7 +34,7 @@
 </template>
 
 <script lang="ts">
-import {defineComponent, onBeforeMount, onBeforeUnmount, onMounted, onServerPrefetch, onUnmounted, Ref, ref, useContext} from "@nuxtjs/composition-api";
+import {defineComponent, onBeforeUnmount, onMounted, Ref, ref, useContext} from "@nuxtjs/composition-api";
 import {HTTP_METHOD, QUERY_TYPE} from "~/types/enums";
 import DataPersister from "~/services/data/dataPersister";
 import {DataPersisterArgs} from "~/types/interfaces";
@@ -47,10 +47,10 @@ export default defineComponent({
 
     let pending: Ref<boolean> = ref(false)
     let fileUrl: Ref<string | null> = ref(null)
-    let eventSource: Ref<EventSource | null> = ref(null)
+    let eventSource: EventSource | null = null
 
     const sseOpened = () => {
-      return eventSource.value !== null && eventSource.value?.readyState === EventSource.OPEN
+      return eventSource !== null && eventSource.readyState === EventSource.OPEN
     }
 
     const submit = async () => {
@@ -68,11 +68,11 @@ export default defineComponent({
     }
 
     const unsubscribe = async () => {
-      if (eventSource.value === null || eventSource.value.readyState === EventSource.CLOSED) {
+      if (eventSource === null || eventSource.readyState === EventSource.CLOSED) {
         return
       }
       console.log('SSE - Close subscription')
-      eventSource.value.close()
+      eventSource.close()
     }
 
     const subscribe = async () => {
@@ -88,32 +88,36 @@ export default defineComponent({
       const url = new URL($config.baseUrl_mercure)
       url.searchParams.append('topic', "access/" + store.state.profile.access.id)
 
-      eventSource.value = new EventSourcePolyfill(
+      eventSource = new EventSourcePolyfill(
         url.toString(),
-        { withCredentials: true, heartbeatTimeout: 3600 * 1000 }
+        { withCredentials: true }
       );
 
-      eventSource.value.onerror = (event) => {
+      eventSource.onerror = (event) => {
         console.error('SSE - An error happened : ' + JSON.stringify(event))
-        eventSource.value?.close()
+        eventSource?.close()
       }
-      eventSource.value.onopen = () => {
+      eventSource.onopen = () => {
         console.log('SSE - Listening for events...')
       }
-      eventSource.value.onmessage = event => {
+      eventSource.onmessage = event => {
         const data = JSON.parse(event.data)
         fileUrl.value = data.url
         pending.value = false
       }
     }
 
-    onMounted(() => {
-      subscribe()
-    })
-
-    onBeforeUnmount(() => {
-      unsubscribe()
-    })
+    // onMounted(() => {
+    //   subscribe()
+    // })
+    //
+    // onBeforeUnmount(() => {
+    //   unsubscribe()
+    // })
+    //
+    // if (process.browser) {
+    //   window.addEventListener('beforeunload', unsubscribe)
+    // }
 
     return {
       submit,

+ 57 - 0
services/sse/sse.ts

@@ -0,0 +1,57 @@
+import { EventSourcePolyfill } from "event-source-polyfill";
+
+class Sse {
+  private readonly accessId: number
+  private readonly url: URL
+  private eventSource: EventSource | null = null
+
+  constructor(mercureBaseUrl: string, accessId: number) {
+    this.accessId = accessId
+    this.url = new URL(mercureBaseUrl)
+    this.url.searchParams.append('topic', "access/" + this.accessId)
+  }
+
+  getUrl () {
+    return this.url
+  }
+
+  isOpen () {
+    return this.eventSource !== null && this.eventSource.readyState === EventSource.OPEN
+  }
+
+  public subscribe () {
+    if (this.isOpen()) {
+      throw new Error('SSE - Already subscribed to this event source')
+    }
+    if (process.server) {
+      throw new Error('SSE - Cannot subscribe on server side')
+    }
+
+    this.eventSource = new EventSourcePolyfill(
+      this.url.toString(),
+      { withCredentials: true }
+    );
+
+    this.eventSource.onerror = (event) => {
+      console.error('SSE - An error happened : ' + JSON.stringify(event))
+      this.eventSource?.close()
+    }
+    this.eventSource.onopen = () => {
+      console.log('SSE - Listening for events...')
+    }
+    this.eventSource.onmessage = event => {
+      const data = JSON.parse(event.data)
+      console.log(data)
+    }
+  }
+
+  public unsubscribe () {
+    if (this.eventSource === null || this.eventSource.readyState === EventSource.CLOSED) {
+      return
+    }
+    this.eventSource.close()
+    console.log('SSE - Subscription closed')
+  }
+}
+
+export default Sse