You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
52 lines
1.7 KiB
52 lines
1.7 KiB
/**
|
|
* GET /api/chat/sse — Server-Sent Events stream for real-time chat messages
|
|
*/
|
|
import { subscribe, authorConnected, authorDisconnected, isAuthorOnline, userConnected, userDisconnected } from "#server/service/chat"
|
|
import { getCurrentUser } from "#server/utils/context"
|
|
|
|
export default defineEventHandler(async (event) => {
|
|
const res = event.node.res
|
|
|
|
const user = await getCurrentUser(event)
|
|
const isAuthor = user?.role === 'admin'
|
|
const userId = user?.id
|
|
|
|
// Register connection BEFORE sending connected event (so isAuthorOnline is accurate)
|
|
if (isAuthor) authorConnected()
|
|
if (userId) userConnected(String(userId))
|
|
|
|
res.writeHead(200, {
|
|
'Content-Type': 'text/event-stream',
|
|
'Cache-Control': 'no-cache, no-transform',
|
|
'Connection': 'keep-alive',
|
|
'X-Accel-Buffering': 'no',
|
|
})
|
|
|
|
// Send actual global author online status (not just the connecting user's role)
|
|
res.write(`data: ${JSON.stringify({ type: 'connected', authorOnline: isAuthorOnline() })}\n\n`)
|
|
|
|
const unsub = subscribe((msg) => {
|
|
// msg is either a ChatMessage object or a status-string from broadcastStatus
|
|
if (typeof msg === 'string') {
|
|
// Status broadcast: send directly (already JSON: {"type":"authorOnline","data":true})
|
|
res.write(`data: ${msg}\n\n`)
|
|
} else {
|
|
res.write(`data: ${JSON.stringify({ type: 'message', data: msg })}\n\n`)
|
|
}
|
|
})
|
|
|
|
const heartbeat = setInterval(() => {
|
|
res.write(': heartbeat\n\n')
|
|
}, 30_000)
|
|
|
|
event.node.req.on('close', () => {
|
|
unsub()
|
|
clearInterval(heartbeat)
|
|
if (isAuthor) authorDisconnected()
|
|
if (userId) userDisconnected(String(userId))
|
|
})
|
|
|
|
await new Promise<void>((resolve) => {
|
|
event.node.req.on('close', () => resolve())
|
|
})
|
|
})
|
|
|