import { toast } from 'vue-sonner' import type { ReactionEventPayload } from '@/composables/useCommentReactions' import type { UploadReactionEventPayload } from '@/composables/useUploadReactions' import type { LiveComment } from '@/composables/useLiveComments' import type { AppNotification } from '@/composables/useNotifications' export default defineNuxtPlugin(() => { const { user } = useAuth() const { fetchAll, addLive, reset } = useNotifications() const { pushLive } = useLiveComments() const motd = useMotd() const { applyEvent } = useCommentReactions() const { applyEvent: applyUploadEvent } = useUploadReactions() let ws: WebSocket | null = null let reconnectTimer: ReturnType | undefined function connect() { if (ws) return const protocol = location.protocol === 'https:' ? 'wss' : 'ws' const socket = new WebSocket(`${protocol}://${location.host}/_ws`) ws = socket socket.onmessage = (event) => { try { const message = JSON.parse(event.data as string) if (message.type === 'comment') { pushLive(message.comment as LiveComment) } else if (message.type === 'reaction') { applyEvent(message as ReactionEventPayload) } else if (message.type === 'upload-reaction') { applyUploadEvent(message as UploadReactionEventPayload) } else if (message.type === 'motd') { motd.value = typeof message.message === 'string' ? message.message : '' } else if (message.type === 'notification') { const n = message.notification as AppNotification addLive(n, typeof message.unreadCount === 'number' ? message.unreadCount : undefined) toast(n.isMention ? `${n.actorName} hat dich erwähnt` : `${n.actorName} hat in einem abonnierten Thread kommentiert`, { id: `notification-${n.uploadId}`, description: n.content?.slice(0, 80) || undefined, action: { label: 'Ansehen', onClick: () => navigateTo(`/thread/${n.uploadId}#comment-${n.commentId}`), }, }) } } catch { // ungültige Nachricht ignorieren } } socket.onclose = () => { if (ws === socket) ws = null reconnectTimer = setTimeout(connect, 3000) } socket.onerror = () => { socket.close() } } function disconnect() { clearTimeout(reconnectTimer) ws?.close() ws = null } // Bei Login/Logout neu verbinden, damit die Server-seitige User-Zuordnung stimmt watch(() => user.value?.id, (id) => { disconnect() connect() if (id) { fetchAll().catch(() => {}) } else { reset() } }, { immediate: true }) })