import { NextRequest } from 'next/server'; import { prisma } from '@/lib/prisma'; import { getCurrentUser } from '@/lib/auth'; // Server-Sent Events pour les notifications en temps réel export async function GET( request: NextRequest, { params }: { params: { id: string } } ) { const user = await getCurrentUser(); if (!user) { return new Response('Non autorisé', { status: 401 }); } const conversation = await prisma.conversation.findUnique({ where: { id: params.id }, include: { participants: true, }, }); if (!conversation) { return new Response('Conversation non trouvée', { status: 404 }); } // Vérifier que l'utilisateur est participant const isParticipant = conversation.participants.some((p) => p.userId === user.id); if (!isParticipant) { return new Response('Accès non autorisé', { status: 403 }); } // Créer un stream SSE const stream = new ReadableStream({ async start(controller) { const encoder = new TextEncoder(); let isClosed = false; // Fonction pour envoyer un événement const sendEvent = (data: any) => { if (isClosed) return; try { const message = `data: ${JSON.stringify(data)}\n\n`; controller.enqueue(encoder.encode(message)); } catch (error) { // Le controller est fermé, arrêter le polling isClosed = true; clearInterval(pollInterval); } }; // Envoyer un événement de connexion sendEvent({ type: 'connected', conversationId: params.id }); // Polling pour vérifier les nouveaux messages let lastMessageId: string | null = null; const pollInterval = setInterval(async () => { if (isClosed) { clearInterval(pollInterval); return; } try { const lastMessage = await prisma.message.findFirst({ where: { conversationId: params.id, ...(lastMessageId ? { id: { gt: lastMessageId } } : {}), }, orderBy: { createdAt: 'desc', }, include: { sender: { select: { id: true, email: true, name: true, }, }, files: true, }, }); if (lastMessage) { lastMessageId = lastMessage.id; sendEvent({ type: 'new_message', message: lastMessage, }); } // Vérifier les mises à jour de conversation const updatedConversation = await prisma.conversation.findUnique({ where: { id: params.id }, include: { participants: { include: { user: { select: { id: true, email: true, name: true, }, }, }, }, }, }); if (updatedConversation) { sendEvent({ type: 'conversation_updated', conversation: updatedConversation, }); } } catch (error) { // Si c'est une erreur de controller fermé, arrêter le polling if (error instanceof Error && error.message.includes('closed')) { isClosed = true; clearInterval(pollInterval); } else { console.error('Erreur lors du polling:', error); } } }, 1000); // Poll toutes les secondes // Nettoyer lors de la fermeture const cleanup = () => { isClosed = true; clearInterval(pollInterval); try { controller.close(); } catch (e) { // Ignorer les erreurs de fermeture } }; // Gérer la fermeture de la connexion request.signal?.addEventListener('abort', cleanup); }, }); return new Response(stream, { headers: { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', }, }); }