Fix des bugs de scroll dans la page de message

Fix des bugs de l'api dans le cache pour les messages
This commit is contained in:
Bilal Dieumegard 2024-12-17 21:13:43 +01:00
parent caf6e771f8
commit 15b0c91992
4 changed files with 59 additions and 25 deletions

View file

@ -1,18 +1,4 @@
services: 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: mongodb:
build: ./mongodb_rs build: ./mongodb_rs

View file

@ -1,7 +1,7 @@
import { createClient } from 'redis'; import { createClient } from 'redis';
const client = await createClient({ const client = await createClient({
url: process.env.REDIS_URL || 'redis://redis-server:6379' url: process.env.REDIS_URL || 'redis://localhost:6379'
}); });

View file

@ -14,13 +14,28 @@ export async function GET({ params, url }) {
try { try {
logger.debug(`Tentative de récupération des messages du cache pour le channel : ${channelId}`); 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`, `channel:${channelId}:messages`,
offset, offset,
offset + limit - 1, offset + limit - 1,
{ REV: true } { 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) { if (redisMessageKeys.length > 0) {
const messages = await Promise.all( const messages = await Promise.all(
redisMessageKeys.map(async (key) => { redisMessageKeys.map(async (key) => {
@ -114,7 +129,7 @@ export async function POST({ params, request }) {
}); });
// Ajouter le message dans Redis // 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`, { await redisClient.zAdd(`channel:${channelId}:messages`, {
score: new Date(newMessage.createdAt).getTime(), score: new Date(newMessage.createdAt).getTime(),
value: `message:${newMessage.id}`, value: `message:${newMessage.id}`,
@ -125,6 +140,7 @@ export async function POST({ params, request }) {
let channels = cachedChannels ? JSON.parse(cachedChannels) : []; let channels = cachedChannels ? JSON.parse(cachedChannels) : [];
let channel = channels.find((c) => c.id === channelId); let channel = channels.find((c) => c.id === channelId);
if(channel){ if(channel){
console.log('channel found')
channel.lastMessage = { channel.lastMessage = {
id: newMessage.id, id: newMessage.id,
text: newMessage.text, text: newMessage.text,
@ -141,8 +157,8 @@ export async function POST({ params, request }) {
user: newMessage.user, user: newMessage.user,
createdAt: newMessage.createdAt, createdAt: newMessage.createdAt,
}, lastUpdate: newMessage.createdAt, messages: undefined}; }, lastUpdate: newMessage.createdAt, messages: undefined};
}
channels = [channel, ...channels]; channels = [channel, ...channels];
}
await redisClient.set('channels', JSON.stringify(channels), { EX: 600 }); await redisClient.set('channels', JSON.stringify(channels), { EX: 600 });
newMessage.channel = { newMessage.channel = {

View file

@ -77,6 +77,10 @@
} }
isLoading = true; isLoading = true;
const previousMessages = $messagesStore;
let newMessages = [];
try { try {
// Calculer la page à charger en fonction du nombre total de messages existants // Calculer la page à charger en fonction du nombre total de messages existants
const totalMessages = $messagesStore.length; const totalMessages = $messagesStore.length;
@ -90,7 +94,7 @@
}); });
if (response.ok) { if (response.ok) {
const newMessages = await response.json(); newMessages = await response.json();
if (newMessages.messages.length <= 0) { if (newMessages.messages.length <= 0) {
console.log("Pas d'autres anciens messages"); console.log("Pas d'autres anciens messages");
@ -116,6 +120,23 @@
console.error("Erreur réseau lors du chargement des messages:", error); console.error("Erreur réseau lors du chargement des messages:", error);
} finally { } finally {
isLoading = false; 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 }); socket.emit('stop-writing', { userId: data.userId, channelId: data.channelId });
} }
async function scrollToBottom(retries = 3) { async function scrollToBottom(retries = 20) {
await tick(); await tick();
const attemptScroll = () => { const attemptScroll = () => {
@ -151,16 +172,22 @@
} }
}; };
// Protéger l'utilisation de requestAnimationFrame
if (typeof window !== 'undefined' && typeof requestAnimationFrame === 'function') {
attemptScroll(); attemptScroll();
if (retries > 0) { if (retries > 0) {
requestAnimationFrame(() => scrollToBottom(retries - 1)); requestAnimationFrame(() => scrollToBottom(retries - 1));
} }
} }
}
onDestroy(() => { onDestroy(() => {
socket.emit('leave-channel', { userId: data.userId, channelId: data.channelId }); socket.emit('leave-channel', { userId: data.userId, channelId: data.channelId });
socket.disconnect(); // Déconnexion propre du socket socket.disconnect(); // Déconnexion propre du socket
if (scrollContainer) {
scrollContainer.removeEventListener('scroll', handleScroll);
}
}); });
// Ecoute des événements socket // Ecoute des événements socket
@ -221,12 +248,16 @@
messagesStore.subscribe(async () => { messagesStore.subscribe(async () => {
await tick(); await tick();
await scrollToBottom(); // Scroll to the bottom after the message is added
}); });
let firstPageLoad = true;
onMount(async () => { onMount(async () => {
await tick(); await tick();
if(firstPageLoad){
firstPageLoad = false;
await scrollToBottom(); await scrollToBottom();
}
}); });
</script> </script>
@ -254,6 +285,7 @@
<div <div
class="m-10 flex flex-col gap-5 overflow-auto flex-grow" class="m-10 flex flex-col gap-5 overflow-auto flex-grow"
bind:this={scrollContainer} bind:this={scrollContainer}
on:scroll={handleScroll}
> >
{#if isLoading} {#if isLoading}
<div class="loading-indicator">Chargement...</div> <div class="loading-indicator">Chargement...</div>