diff --git a/docker-compose.yml b/docker-compose.yml index ae600c8..9ed4893 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,18 +1,4 @@ services: - app: - build: . - hostname: chat-app - restart: always - environment: - - DATABASE_URL=mongodb://temp-root-username:temp-password@mongodb:27017/chat_projetweb - - JWT_SECRET=1f49ba5426afebd6e27eed416d0c31925ca5c4dc39ab4fdea514c8a858312608 - ports: - - "3000:3000" - networks: - - app_network - depends_on: - - mongodb - - redis mongodb: build: ./mongodb_rs diff --git a/src/lib/redisClient.ts b/src/lib/redisClient.ts index 62fec25..2b06109 100644 --- a/src/lib/redisClient.ts +++ b/src/lib/redisClient.ts @@ -1,7 +1,7 @@ import { createClient } from 'redis'; const client = await createClient({ - url: process.env.REDIS_URL || 'redis://redis-server:6379' + url: process.env.REDIS_URL || 'redis://localhost:6379' }); diff --git a/src/routes/api/channels/[id]/messages/+server.ts b/src/routes/api/channels/[id]/messages/+server.ts index 850429a..8aff2fa 100644 --- a/src/routes/api/channels/[id]/messages/+server.ts +++ b/src/routes/api/channels/[id]/messages/+server.ts @@ -14,13 +14,28 @@ export async function GET({ params, url }) { try { logger.debug(`Tentative de récupération des messages du cache pour le channel : ${channelId}`); - const redisMessageKeys = await redisClient.zRangeWithScores( + let redisMessageKeys = await redisClient.zRangeWithScores( `channel:${channelId}:messages`, offset, offset + limit - 1, { REV: true } ); + const redisPipelineRemove = redisClient.multi(); + + + for (const messageKey of redisMessageKeys) { + // Vérifie si la clé existe dans Redis + const messageKeyValue = messageKey.value; + const exists = await redisClient.exists(messageKeyValue); + if (!exists) { + // Supprime la référence expirée dans le zSet + redisPipelineRemove.zRem(`channel:${channelId}:messages`, messageKeyValue); + redisMessageKeys = redisMessageKeys.filter((key) => key.value !== messageKeyValue); + } + } + await redisPipelineRemove.exec(); + if (redisMessageKeys.length > 0) { const messages = await Promise.all( redisMessageKeys.map(async (key) => { @@ -114,7 +129,7 @@ export async function POST({ params, request }) { }); // Ajouter le message dans Redis - await redisClient.set(`message:${newMessage.id}`, JSON.stringify(newMessage)); + await redisClient.set(`message:${newMessage.id}`, JSON.stringify(newMessage), {EX: 1800}); await redisClient.zAdd(`channel:${channelId}:messages`, { score: new Date(newMessage.createdAt).getTime(), value: `message:${newMessage.id}`, @@ -125,6 +140,7 @@ export async function POST({ params, request }) { let channels = cachedChannels ? JSON.parse(cachedChannels) : []; let channel = channels.find((c) => c.id === channelId); if(channel){ + console.log('channel found') channel.lastMessage = { id: newMessage.id, text: newMessage.text, @@ -141,8 +157,8 @@ export async function POST({ params, request }) { user: newMessage.user, createdAt: newMessage.createdAt, }, lastUpdate: newMessage.createdAt, messages: undefined}; + channels = [channel, ...channels]; } - channels = [channel, ...channels]; await redisClient.set('channels', JSON.stringify(channels), { EX: 600 }); newMessage.channel = { diff --git a/src/routes/chats/[id]/+page.svelte b/src/routes/chats/[id]/+page.svelte index 21dd724..1661d6d 100644 --- a/src/routes/chats/[id]/+page.svelte +++ b/src/routes/chats/[id]/+page.svelte @@ -77,6 +77,10 @@ } isLoading = true; + const previousMessages = $messagesStore; + + let newMessages = []; + try { // Calculer la page à charger en fonction du nombre total de messages existants const totalMessages = $messagesStore.length; @@ -90,7 +94,7 @@ }); if (response.ok) { - const newMessages = await response.json(); + newMessages = await response.json(); if (newMessages.messages.length <= 0) { console.log("Pas d'autres anciens messages"); @@ -116,6 +120,23 @@ console.error("Erreur réseau lors du chargement des messages:", error); } finally { isLoading = false; + await tick(); + const filteredNewMessages = newMessages.messages.filter((msg) => { + return !previousMessages.some((m) => m.id === msg.id); + }); + scrollContainer.scrollTo({ + top: filteredNewMessages.length*300, + }); + + } + } + + function handleScroll() { + if (scrollContainer) { + // Détection quand on est en haut du scroll + if (scrollContainer.scrollTop <= 0 && !isLoading) { + loadMoreMessages(); + } } } @@ -139,7 +160,7 @@ socket.emit('stop-writing', { userId: data.userId, channelId: data.channelId }); } - async function scrollToBottom(retries = 3) { + async function scrollToBottom(retries = 20) { await tick(); const attemptScroll = () => { @@ -151,16 +172,22 @@ } }; - attemptScroll(); + // Protéger l'utilisation de requestAnimationFrame + if (typeof window !== 'undefined' && typeof requestAnimationFrame === 'function') { + attemptScroll(); - if (retries > 0) { - requestAnimationFrame(() => scrollToBottom(retries - 1)); + if (retries > 0) { + requestAnimationFrame(() => scrollToBottom(retries - 1)); + } } } onDestroy(() => { socket.emit('leave-channel', { userId: data.userId, channelId: data.channelId }); socket.disconnect(); // Déconnexion propre du socket + if (scrollContainer) { + scrollContainer.removeEventListener('scroll', handleScroll); + } }); // Ecoute des événements socket @@ -221,12 +248,16 @@ messagesStore.subscribe(async () => { await tick(); - await scrollToBottom(); // Scroll to the bottom after the message is added }); + let firstPageLoad = true; + onMount(async () => { await tick(); - await scrollToBottom(); + if(firstPageLoad){ + firstPageLoad = false; + await scrollToBottom(); + } }); @@ -254,6 +285,7 @@