feat: cache removing channels and messages that haven't been used in long
This commit is contained in:
parent
45fb025065
commit
33e4bc87d9
6 changed files with 93 additions and 59 deletions
|
@ -8,8 +8,6 @@
|
||||||
|
|
||||||
export let message = null; // Contenu du message
|
export let message = null; // Contenu du message
|
||||||
|
|
||||||
let defaultProfilePicture = "/images/default-profile.png";
|
|
||||||
|
|
||||||
export let setActiveProfile;
|
export let setActiveProfile;
|
||||||
export let activeProfileId = null;
|
export let activeProfileId = null;
|
||||||
|
|
||||||
|
@ -21,11 +19,28 @@
|
||||||
timeElapsed = formatDistanceToNow(message.createdAt);
|
timeElapsed = formatDistanceToNow(message.createdAt);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let user = null;
|
||||||
|
|
||||||
|
async function fetchUser() {
|
||||||
|
const res = await fetch(`/api/users/${message.user.id}`, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = await res.json();
|
||||||
|
console.log(data)
|
||||||
|
user = data;
|
||||||
|
}
|
||||||
|
|
||||||
// Initialisation de l'intervalle
|
// Initialisation de l'intervalle
|
||||||
onMount(() => {
|
onMount(async () => {
|
||||||
updateElapsed(); // Calcul initial
|
updateElapsed(); // Calcul initial
|
||||||
const interval = setInterval(updateElapsed, 1000); // Mise à jour toutes les secondes
|
const interval = setInterval(updateElapsed, 1000); // Mise à jour toutes les secondes
|
||||||
|
|
||||||
|
await fetchUser();
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
clearInterval(interval); // Nettoyage lors du démontage
|
clearInterval(interval); // Nettoyage lors du démontage
|
||||||
};
|
};
|
||||||
|
@ -41,8 +56,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
{#if user !== null}
|
||||||
|
|
||||||
<Card.Root class="relative">
|
<Card.Root class="relative">
|
||||||
<Card.Header
|
<Card.Header
|
||||||
class="flex items-center justify-between {myMessage ? 'flex-row' : 'flex-row-reverse'}"
|
class="flex items-center justify-between {myMessage ? 'flex-row' : 'flex-row-reverse'}"
|
||||||
|
@ -60,20 +79,20 @@
|
||||||
>
|
>
|
||||||
<!-- Image de profil -->
|
<!-- Image de profil -->
|
||||||
<img
|
<img
|
||||||
src={message.user.profilePicture ? `http://localhost:5173/${message.user.profilePicture}` : defaultProfilePicture}
|
src={`http://localhost:5173/${user.profilePicture}`}
|
||||||
alt="Profile Picture"
|
alt="Profile Picture"
|
||||||
class="h-10 w-10 rounded-full border border-gray-300 cursor-pointer"
|
class="h-10 w-10 rounded-full border border-gray-300 cursor-pointer"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- Infos du profil (affichées au survol) -->
|
<!-- Infos du profil (affichées au survol) -->
|
||||||
<ProfileInfo user={message.user} show={activeProfileId === message.id} position={myMessage} />
|
<ProfileInfo user={user} show={activeProfileId === message.id} position={myMessage} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col text-right {myMessage ? 'text-right' : 'text-left'}">
|
<div class="flex flex-col text-right {myMessage ? 'text-right' : 'text-left'}">
|
||||||
<Card.Title
|
<Card.Title
|
||||||
class="text-gray-800 text-sm sm:text-base md:text-lg truncate {myMessage ? 'font-bold' : ''}"
|
class="text-gray-800 text-sm sm:text-base md:text-lg truncate {myMessage ? 'font-bold' : ''}"
|
||||||
>
|
>
|
||||||
{myMessage ? "(Moi)" : ""} {message.user.username}
|
{myMessage ? "(Moi)" : ""} {user.username}
|
||||||
</Card.Title>
|
</Card.Title>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -85,6 +104,8 @@
|
||||||
</Card.Content>
|
</Card.Content>
|
||||||
</Card.Root>
|
</Card.Root>
|
||||||
|
|
||||||
|
|
||||||
|
{/if}
|
||||||
<style>
|
<style>
|
||||||
img {
|
img {
|
||||||
object-fit: cover; /* Assure un bon rendu des images */
|
object-fit: cover; /* Assure un bon rendu des images */
|
||||||
|
|
|
@ -5,7 +5,7 @@ import logger from '$lib/logger';
|
||||||
import { sortChannels } from '$lib/utils/sort.ts';
|
import { sortChannels } from '$lib/utils/sort.ts';
|
||||||
|
|
||||||
// GET: Liste tous les canaux avec leur premier message
|
// GET: Liste tous les canaux avec leur premier message
|
||||||
export async function GET({ params, url }) {
|
export async function GET({ url }) {
|
||||||
if(url.searchParams.get("name") != null && url.searchParams.get("name") != ""){
|
if(url.searchParams.get("name") != null && url.searchParams.get("name") != ""){
|
||||||
const name = url.searchParams.get("name");
|
const name = url.searchParams.get("name");
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -14,7 +14,7 @@ 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.zRange(
|
const redisMessageKeys = await redisClient.zRangeWithScores(
|
||||||
`channel:${channelId}:messages`,
|
`channel:${channelId}:messages`,
|
||||||
offset,
|
offset,
|
||||||
offset + limit - 1,
|
offset + limit - 1,
|
||||||
|
@ -24,10 +24,23 @@ export async function GET({ params, url }) {
|
||||||
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) => {
|
||||||
const message = await redisClient.get(key);
|
const message = await redisClient.get(key.value);
|
||||||
return JSON.parse(message);
|
return JSON.parse(message);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const redisPipeline = redisClient.multi();
|
||||||
|
for (const key of redisMessageKeys) {
|
||||||
|
const message = await redisClient.get(key.value);
|
||||||
|
const msg = JSON.parse(message)
|
||||||
|
redisPipeline.set(key.value, JSON.stringify(msg), {EX: 1800});
|
||||||
|
redisPipeline.zAdd(`channel:${channelId}:messages`, {
|
||||||
|
score: key.score,
|
||||||
|
value: key.value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await redisPipeline.exec();
|
||||||
|
|
||||||
return json({ limit, page, messages: messages.reverse() });
|
return json({ limit, page, messages: messages.reverse() });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,10 +54,6 @@ export async function GET({ params, url }) {
|
||||||
user: {
|
user: {
|
||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true,
|
||||||
username: true,
|
|
||||||
surname: true,
|
|
||||||
name: true,
|
|
||||||
profilePicture: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -57,7 +66,7 @@ export async function GET({ params, url }) {
|
||||||
const redisPipeline = redisClient.multi();
|
const redisPipeline = redisClient.multi();
|
||||||
for (const message of messagesFromDB) {
|
for (const message of messagesFromDB) {
|
||||||
const messageKey = `message:${message.id}`;
|
const messageKey = `message:${message.id}`;
|
||||||
redisPipeline.set(messageKey, JSON.stringify(message));
|
redisPipeline.set(messageKey, JSON.stringify(message), {EX: 1800});
|
||||||
redisPipeline.zAdd(`channel:${channelId}:messages`, {
|
redisPipeline.zAdd(`channel:${channelId}:messages`, {
|
||||||
score: new Date(message.createdAt).getTime(),
|
score: new Date(message.createdAt).getTime(),
|
||||||
value: messageKey,
|
value: messageKey,
|
||||||
|
@ -93,10 +102,6 @@ export async function POST({ params, request }) {
|
||||||
user: {
|
user: {
|
||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true,
|
||||||
username: true,
|
|
||||||
surname: true,
|
|
||||||
name: true,
|
|
||||||
profilePicture: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
channel: {
|
channel: {
|
||||||
|
|
|
@ -7,6 +7,7 @@ export async function load({ fetch, params, locals }) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const messages = await res.json();
|
const messages = await res.json();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
messages,
|
messages,
|
||||||
channelId: params.id,
|
channelId: params.id,
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
import UserChat from '$lib/components/ui/UserChat.svelte';
|
import UserChat from '$lib/components/ui/UserChat.svelte';
|
||||||
import { onMount, tick } from 'svelte';
|
import { onMount, tick } from 'svelte';
|
||||||
import { initSocket } from '$lib/stores/socket';
|
import { initSocket } from '$lib/stores/socket';
|
||||||
|
import { ArrowLeft } from 'lucide-svelte';
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
export let messages = data.messages.messages;
|
export let messages = data.messages.messages;
|
||||||
|
@ -95,11 +96,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
scrollToBottom(scrollContainer);
|
|
||||||
|
|
||||||
socket.on("new-message", (message) => {
|
socket.on("new-message", (message) => {
|
||||||
messages = [...messages , message ];
|
messages = [...messages , message ];
|
||||||
});
|
});
|
||||||
|
scrollToBottom(scrollContainer);
|
||||||
});
|
});
|
||||||
|
|
||||||
async function handleEnter(event: KeyboardEvent) {
|
async function handleEnter(event: KeyboardEvent) {
|
||||||
|
@ -123,7 +123,10 @@
|
||||||
<div class="h-full flex">
|
<div class="h-full flex">
|
||||||
<!-- Liste des utilisateurs (colonne gauche) -->
|
<!-- Liste des utilisateurs (colonne gauche) -->
|
||||||
<div class="w-1/4 bg-gray-100 border-r overflow-y-auto">
|
<div class="w-1/4 bg-gray-100 border-r overflow-y-auto">
|
||||||
<h2 class="text-3xl font-bold px-4 mt-5">Utilisateurs</h2>
|
<div class="flex gap-4 px-4 mt-5">
|
||||||
|
<Button href="/chats" variant="outline" size="icon" ><ArrowLeft /></Button>
|
||||||
|
<h2 class="text-3xl font-bold">Utilisateurs</h2>
|
||||||
|
</div>
|
||||||
<div class="flex flex-col m-5 gap-2">
|
<div class="flex flex-col m-5 gap-2">
|
||||||
{#each users as user}
|
{#each users as user}
|
||||||
<UserChat
|
<UserChat
|
||||||
|
@ -151,7 +154,7 @@
|
||||||
{#if messages !== undefined && messages.length > 0}
|
{#if messages !== undefined && messages.length > 0}
|
||||||
{#each messages as message}
|
{#each messages as message}
|
||||||
<Message
|
<Message
|
||||||
myMessage={data.userId == message.user.id}
|
myMessage={data.userId === message.user.id}
|
||||||
message={message}
|
message={message}
|
||||||
activeProfileId={activeProfileId}
|
activeProfileId={activeProfileId}
|
||||||
setActiveProfile={setActiveProfile}
|
setActiveProfile={setActiveProfile}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from 'svelte';
|
import ChoosePicture from "$lib/components/ui/ChoosePicture.svelte";
|
||||||
import ChoosePicture from "$lib/components/ui/ChoosePicture.svelte"; // Import du composant
|
import { Button } from '$lib/components/ui/button';
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
const user = data.user;
|
const user = data.user;
|
||||||
|
@ -50,7 +50,7 @@
|
||||||
|
|
||||||
const res = await fetch(`/api/users/${user.id}`, {
|
const res = await fetch(`/api/users/${user.id}`, {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
body: formData, // Transmet les données comme multipart/form-data
|
body: formData,
|
||||||
});
|
});
|
||||||
const result = await res.json();
|
const result = await res.json();
|
||||||
console.log(result);
|
console.log(result);
|
||||||
|
@ -120,15 +120,19 @@
|
||||||
<ChoosePicture bind:profilePicture={profilePicture} />
|
<ChoosePicture bind:profilePicture={profilePicture} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-6 flex justify-center">
|
<div class="mt-6 flex flex-col gap-6 items-center justify-center">
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
class="bg-blue-500 text-white px-6 py-2 rounded-md hover:bg-blue-600 focus:outline-none"
|
class="bg-blue-500 text-white px-6 py-2 rounded-md hover:bg-blue-600 focus:outline-none"
|
||||||
>
|
>
|
||||||
Mettre à jour
|
Mettre à jour
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
|
||||||
|
<Button href="/chats" variant="secondary">Retour au menu principal</Button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue