feat: Add support for mutiple channels

This commit is contained in:
April Hall 2025-02-06 13:50:46 -05:00
parent edfd65335c
commit 39bb7418c9
No known key found for this signature in database
GPG Key ID: A49AC35CB186266C
5 changed files with 102 additions and 79 deletions

View File

@ -1,5 +1,10 @@
import cassandra from 'cassandra-driver'; import cassandra from 'cassandra-driver';
interface Messages {
messages: cassandra.types.Row[] | null;
error: Error | null;
}
class Db { class Db {
private client: cassandra.Client; private client: cassandra.Client;
@ -47,15 +52,21 @@ class Db {
} }
// Get messages method // Get messages method
async getMessages(channelName: string, limit: number): Promise<cassandra.types.Row[] | undefined> { async getMessages(channelName: string, limit: number): Promise<Messages> {
try { try {
const res = await this.client.execute( const res = await this.client.execute(
`SELECT * FROM channels.${channelName} WHERE channel_name = '${channelName}' ORDER BY timestamp DESC LIMIT ${limit}`, `SELECT * FROM channels.${channelName} WHERE channel_name = '${channelName}' ORDER BY timestamp DESC LIMIT ${limit}`,
); );
return res.rows; return {
messages: res.rows,
error: null,
};
} catch (e) { } catch (e) {
console.log(`Error fetching messages: ${(e as Error).message}`); console.log(`Error fetching messages: ${(e as Error).message}`);
return; return {
messages: null,
error: e as Error,
};
} }
} }
} }
@ -85,4 +96,4 @@ try {
const db = new Db(client); const db = new Db(client);
await db.createChannel('general'); await db.createChannel('general');
export { db }; export { db, type Messages };

View File

@ -1,19 +1,5 @@
import type { TypeMessage } from '$lib'; import { redirect } from '@sveltejs/kit';
import { db } from '$lib/server/db';
export async function load(): Promise<{ messages: TypeMessage[] }> { export function load(): void {
const rows = await db.getMessages('general', 50); redirect(308, '/channel/general');
const messages: TypeMessage[] = rows
? rows.map((value) => {
return {
message: value.message_content,
user: value.sender.toString(),
imageSrc: `https://api.dicebear.com/9.x/identicon/svg?seed=${value.sender.toString()}`,
};
})
: [];
return {
messages: messages ?? [],
};
} }

View File

@ -1,58 +0,0 @@
<script lang="ts">
import { io } from 'socket.io-client';
import { onMount } from 'svelte';
import { v4 as uuidv4 } from 'uuid';
import { type TypeMessage } from '$lib';
import type { PageData } from './$types';
import { Input } from '$lib/components/ui/input/index';
import { Button } from '$lib/components/ui/button/index';
import Send from 'lucide-svelte/icons/send';
import Message from '$lib/components/message.svelte';
let { data }: { data: PageData } = $props();
let user: string | undefined;
let socket: ReturnType<typeof io> | null = null;
let log: TypeMessage[] = $state([]);
let msg: string = $state('');
function logEvent(newMsg: TypeMessage) {
log = [newMsg, ...log];
}
function establishSocketIOConnection() {
if (socket) return;
socket = io();
socket.on('message', (data: TypeMessage) => {
console.log('[ws] message received', data);
logEvent(data);
});
}
function sendMessage() {
if (!socket) return;
socket.emit('message', { id: user, content: msg });
msg = '';
}
onMount(() => {
establishSocketIOConnection();
user = uuidv4();
});
</script>
{#snippet message(messages: TypeMessage[])}
{#each messages as message}
<Message imageSrc={message.imageSrc} user={message.user} message={message.message} />
{/each}
{/snippet}
<div class="flex flex-1 flex-col items-center justify-center rounded-lg shadow-sm gap-1 h-full">
<div class="flex-grow flex-col-reverse flex flex-auto overflow-y-scroll overflow-x-hidden rounded-lg border w-full">
{@render message(log)}
{@render message(data.messages)}
</div>
<form class="flex gap-1 w-full" onsubmit={sendMessage}>
<Input type="text" placeholder="Type Here" bind:value={msg} />
<Button class="h-9 w-14"><Send class="size-full" /></Button>
</form>
</div>

View File

@ -0,0 +1,26 @@
import type { TypeMessage } from '$lib';
import { error } from '@sveltejs/kit';
import { db } from '$lib/server/db';
export async function load({ params }): Promise<{ messages: TypeMessage[] }> {
let messages: TypeMessage[];
const rows = await db.getMessages(params.channel, 50);
if (rows.messages !== null) {
messages = rows
? rows.messages.map((value) => {
return {
message: value.message_content,
user: value.sender.toString(),
imageSrc: `https://api.dicebear.com/9.x/identicon/svg?seed=${value.sender.toString()}`,
};
})
: [];
} else {
return error(404, `Channel '${params.channel}' does not exist`);
}
return {
messages: messages ?? [],
};
}

View File

@ -0,0 +1,58 @@
<script lang="ts">
import { io } from 'socket.io-client';
import { onMount } from 'svelte';
import { v4 as uuidv4 } from 'uuid';
import { type TypeMessage } from '$lib';
import type { PageData } from './$types';
import { Input } from '$lib/components/ui/input/index';
import { Button } from '$lib/components/ui/button/index';
import Send from 'lucide-svelte/icons/send';
import Message from '$lib/components/message.svelte';
let { data }: { data: PageData } = $props();
let user: string | undefined;
let socket: ReturnType<typeof io> | null = null;
let log: TypeMessage[] = $state([]);
let msg: string = $state('');
function logEvent(newMsg: TypeMessage) {
log = [newMsg, ...log];
}
function establishSocketIOConnection() {
if (socket) return;
socket = io();
socket.on('message', (data: TypeMessage) => {
console.log('[ws] message received', data);
logEvent(data);
});
}
function sendMessage() {
if (!socket) return;
socket.emit('message', { id: user, content: msg });
msg = '';
}
onMount(() => {
establishSocketIOConnection();
user = uuidv4();
});
</script>
{#snippet message(messages: TypeMessage[])}
{#each messages as message}
<Message imageSrc={message.imageSrc} user={message.user} message={message.message} />
{/each}
{/snippet}
<div class="flex flex-1 flex-col items-center justify-center rounded-lg shadow-sm gap-1 h-full">
<div class="flex-grow flex-col-reverse flex flex-auto overflow-y-scroll overflow-x-hidden rounded-lg border w-full">
{@render message(log)}
{@render message(data.messages)}
</div>
<form class="flex gap-1 w-full" onsubmit={sendMessage}>
<Input type="text" placeholder="Type Here" bind:value={msg} />
<Button class="h-9 w-14"><Send class="size-full" /></Button>
</form>
</div>