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
|
||||
|
||||
let defaultProfilePicture = "/images/default-profile.png";
|
||||
|
||||
export let setActiveProfile;
|
||||
export let activeProfileId = null;
|
||||
|
||||
|
@ -21,11 +19,28 @@
|
|||
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
|
||||
onMount(() => {
|
||||
onMount(async () => {
|
||||
updateElapsed(); // Calcul initial
|
||||
const interval = setInterval(updateElapsed, 1000); // Mise à jour toutes les secondes
|
||||
|
||||
await fetchUser();
|
||||
|
||||
return () => {
|
||||
clearInterval(interval); // Nettoyage lors du démontage
|
||||
};
|
||||
|
@ -41,50 +56,56 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<Card.Root class="relative">
|
||||
<Card.Header
|
||||
class="flex items-center justify-between {myMessage ? 'flex-row' : 'flex-row-reverse'}"
|
||||
>
|
||||
<!-- Conteneur pour la date -->
|
||||
<span class="text-xs sm:text-sm md:text-base text-gray-500 items-top">
|
||||
{#if user !== null}
|
||||
|
||||
<Card.Root class="relative">
|
||||
<Card.Header
|
||||
class="flex items-center justify-between {myMessage ? 'flex-row' : 'flex-row-reverse'}"
|
||||
>
|
||||
<!-- Conteneur pour la date -->
|
||||
<span class="text-xs sm:text-sm md:text-base text-gray-500 items-top">
|
||||
{timeElapsed}
|
||||
</span>
|
||||
|
||||
<!-- Conteneur pour l'image et le nom d'utilisateur -->
|
||||
<div class="flex items-center gap-3 {myMessage ? 'flex-row-reverse' : 'flex-row'}">
|
||||
<div
|
||||
class="relative"
|
||||
on:click={toggleProfileInfo}
|
||||
>
|
||||
<!-- Image de profil -->
|
||||
<img
|
||||
src={message.user.profilePicture ? `http://localhost:5173/${message.user.profilePicture}` : defaultProfilePicture}
|
||||
alt="Profile Picture"
|
||||
class="h-10 w-10 rounded-full border border-gray-300 cursor-pointer"
|
||||
/>
|
||||
|
||||
<!-- Infos du profil (affichées au survol) -->
|
||||
<ProfileInfo user={message.user} show={activeProfileId === message.id} position={myMessage} />
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col text-right {myMessage ? 'text-right' : 'text-left'}">
|
||||
<Card.Title
|
||||
class="text-gray-800 text-sm sm:text-base md:text-lg truncate {myMessage ? 'font-bold' : ''}"
|
||||
<!-- Conteneur pour l'image et le nom d'utilisateur -->
|
||||
<div class="flex items-center gap-3 {myMessage ? 'flex-row-reverse' : 'flex-row'}">
|
||||
<div
|
||||
class="relative"
|
||||
on:click={toggleProfileInfo}
|
||||
>
|
||||
{myMessage ? "(Moi)" : ""} {message.user.username}
|
||||
</Card.Title>
|
||||
<!-- Image de profil -->
|
||||
<img
|
||||
src={`http://localhost:5173/${user.profilePicture}`}
|
||||
alt="Profile Picture"
|
||||
class="h-10 w-10 rounded-full border border-gray-300 cursor-pointer"
|
||||
/>
|
||||
|
||||
<!-- Infos du profil (affichées au survol) -->
|
||||
<ProfileInfo user={user} show={activeProfileId === message.id} position={myMessage} />
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col text-right {myMessage ? 'text-right' : 'text-left'}">
|
||||
<Card.Title
|
||||
class="text-gray-800 text-sm sm:text-base md:text-lg truncate {myMessage ? 'font-bold' : ''}"
|
||||
>
|
||||
{myMessage ? "(Moi)" : ""} {user.username}
|
||||
</Card.Title>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card.Header>
|
||||
</Card.Header>
|
||||
|
||||
<!-- Contenu du message -->
|
||||
<Card.Content class="text-sm sm:text-base md:text-lg text-gray-700">
|
||||
<p>{message.text}</p>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
<!-- Contenu du message -->
|
||||
<Card.Content class="text-sm sm:text-base md:text-lg text-gray-700">
|
||||
<p>{message.text}</p>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
|
||||
|
||||
{/if}
|
||||
<style>
|
||||
img {
|
||||
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';
|
||||
|
||||
// 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") != ""){
|
||||
const name = url.searchParams.get("name");
|
||||
try {
|
||||
|
|
|
@ -14,7 +14,7 @@ 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.zRange(
|
||||
const redisMessageKeys = await redisClient.zRangeWithScores(
|
||||
`channel:${channelId}:messages`,
|
||||
offset,
|
||||
offset + limit - 1,
|
||||
|
@ -24,10 +24,23 @@ export async function GET({ params, url }) {
|
|||
if (redisMessageKeys.length > 0) {
|
||||
const messages = await Promise.all(
|
||||
redisMessageKeys.map(async (key) => {
|
||||
const message = await redisClient.get(key);
|
||||
const message = await redisClient.get(key.value);
|
||||
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() });
|
||||
}
|
||||
|
||||
|
@ -41,10 +54,6 @@ export async function GET({ params, url }) {
|
|||
user: {
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
surname: true,
|
||||
name: true,
|
||||
profilePicture: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -57,7 +66,7 @@ export async function GET({ params, url }) {
|
|||
const redisPipeline = redisClient.multi();
|
||||
for (const message of messagesFromDB) {
|
||||
const messageKey = `message:${message.id}`;
|
||||
redisPipeline.set(messageKey, JSON.stringify(message));
|
||||
redisPipeline.set(messageKey, JSON.stringify(message), {EX: 1800});
|
||||
redisPipeline.zAdd(`channel:${channelId}:messages`, {
|
||||
score: new Date(message.createdAt).getTime(),
|
||||
value: messageKey,
|
||||
|
@ -93,10 +102,6 @@ export async function POST({ params, request }) {
|
|||
user: {
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
surname: true,
|
||||
name: true,
|
||||
profilePicture: true,
|
||||
},
|
||||
},
|
||||
channel: {
|
||||
|
|
|
@ -7,6 +7,7 @@ export async function load({ fetch, params, locals }) {
|
|||
}
|
||||
});
|
||||
const messages = await res.json();
|
||||
|
||||
return {
|
||||
messages,
|
||||
channelId: params.id,
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
import UserChat from '$lib/components/ui/UserChat.svelte';
|
||||
import { onMount, tick } from 'svelte';
|
||||
import { initSocket } from '$lib/stores/socket';
|
||||
import { ArrowLeft } from 'lucide-svelte';
|
||||
|
||||
export let data;
|
||||
export let messages = data.messages.messages;
|
||||
|
@ -95,11 +96,10 @@
|
|||
}
|
||||
|
||||
onMount(() => {
|
||||
scrollToBottom(scrollContainer);
|
||||
|
||||
socket.on("new-message", (message) => {
|
||||
messages = [...messages , message ];
|
||||
});
|
||||
scrollToBottom(scrollContainer);
|
||||
});
|
||||
|
||||
async function handleEnter(event: KeyboardEvent) {
|
||||
|
@ -123,7 +123,10 @@
|
|||
<div class="h-full flex">
|
||||
<!-- Liste des utilisateurs (colonne gauche) -->
|
||||
<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">
|
||||
{#each users as user}
|
||||
<UserChat
|
||||
|
@ -151,7 +154,7 @@
|
|||
{#if messages !== undefined && messages.length > 0}
|
||||
{#each messages as message}
|
||||
<Message
|
||||
myMessage={data.userId == message.user.id}
|
||||
myMessage={data.userId === message.user.id}
|
||||
message={message}
|
||||
activeProfileId={activeProfileId}
|
||||
setActiveProfile={setActiveProfile}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import ChoosePicture from "$lib/components/ui/ChoosePicture.svelte"; // Import du composant
|
||||
import ChoosePicture from "$lib/components/ui/ChoosePicture.svelte";
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
|
||||
export let data;
|
||||
const user = data.user;
|
||||
|
@ -50,7 +50,7 @@
|
|||
|
||||
const res = await fetch(`/api/users/${user.id}`, {
|
||||
method: 'PUT',
|
||||
body: formData, // Transmet les données comme multipart/form-data
|
||||
body: formData,
|
||||
});
|
||||
const result = await res.json();
|
||||
console.log(result);
|
||||
|
@ -120,16 +120,20 @@
|
|||
<ChoosePicture bind:profilePicture={profilePicture} />
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex justify-center">
|
||||
<div class="mt-6 flex flex-col gap-6 items-center justify-center">
|
||||
<button
|
||||
type="submit"
|
||||
class="bg-blue-500 text-white px-6 py-2 rounded-md hover:bg-blue-600 focus:outline-none"
|
||||
>
|
||||
Mettre à jour
|
||||
</button>
|
||||
|
||||
|
||||
<Button href="/chats" variant="secondary">Retour au menu principal</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
|
Loading…
Add table
Reference in a new issue