import type { Schedule } from '~/shared/types/schedule'; let source: EventSource | null = null; let sourceRefs = 0; let sourceSessionId: number | undefined = undefined; export const useSchedule = () => { const { data: session } = useAccountSession(); const asyncData = useAsyncData( 'schedule', () => $fetch("/api/schedule"), { default: () => ({ events: [], locations: [] }) }, ) const { data: schedule } = asyncData; function connect() { console.log("Opening event source sid:", session.value?.id); sourceSessionId = session.value?.id; source = new EventSource("/api/events"); source.addEventListener("message", (message) => { console.log("Message", message.data); }); source.addEventListener("update", (message) => { const updatedSchedule: Schedule = JSON.parse(message.data); console.log("Update", updatedSchedule); schedule.value = updatedSchedule; }); } function disconnect() { console.log("Closing event source") source!.close(); source = null; } onMounted(() => { console.log("useSchedule onMounted", sourceRefs); sourceRefs += 1; if (sourceRefs !== 1) { console.log("Event source already open"); return; } connect(); }) watch(() => session.value?.id, () => { if (sourceSessionId === session.value?.id) { return; } sourceSessionId = session.value?.id; console.log("Session changed, refetching schedule") $fetch("/api/schedule").then( data => { schedule.value = data; }, err => { console.error(err); schedule.value = { locations: [], events: []}}, ) if (source && sourceRefs > 0) { console.log("Restarting event stream") disconnect(); connect(); } }) onUnmounted(() => { console.log("useSchedule onUnmounted", sourceRefs); sourceRefs -= 1; if (source && sourceRefs === 0) { disconnect(); } if (sourceRefs < 0) { throw Error("Source reference count below zero"); } }); return asyncData.then(({ data }) => data); }