forked from BRETT/BRETT
86 lines
2.8 KiB
TypeScript
86 lines
2.8 KiB
TypeScript
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 { $i18n } = useNuxtApp()
|
|
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<typeof setTimeout> | 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($i18n.t(n.isMention ? 'notifications.toastMentioned' : 'notifications.toastCommented', { name: n.actorName }), {
|
|
id: `notification-${n.uploadId}`,
|
|
description: n.content?.slice(0, 80) || undefined,
|
|
action: {
|
|
label: $i18n.t('notifications.view'),
|
|
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 })
|
|
})
|