From ee1eac23abf1f3cdf30d330ace209d1415cf4305 Mon Sep 17 00:00:00 2001 From: April Hall Date: Sun, 9 Feb 2025 23:39:57 -0500 Subject: [PATCH] feat: Sync chat presence with auth data --- .gitignore | 2 +- TODO.md | 2 +- prodServer.ts | 6 ++-- src/lib/components/user.svelte | 4 +-- src/lib/functions/websocketConfig.ts | 6 ++-- src/lib/server/db/index.ts | 4 +-- src/lib/server/db/sqlite.ts | 28 +++++++++++++++++++ .../(main)/channel/[channel]/+page.server.ts | 9 ++++-- .../(main)/channel/[channel]/+page.svelte | 4 +-- 9 files changed, 49 insertions(+), 16 deletions(-) create mode 100644 src/lib/server/db/sqlite.ts diff --git a/.gitignore b/.gitignore index cd41439..1ad6528 100644 --- a/.gitignore +++ b/.gitignore @@ -28,4 +28,4 @@ vite.config.js.timestamp-* vite.config.ts.timestamp-* # Sqlite -src/lib/server/db/users.db +src/lib/server/db/users.db* diff --git a/TODO.md b/TODO.md index 7c7d1ee..a98dd05 100644 --- a/TODO.md +++ b/TODO.md @@ -10,4 +10,4 @@ A more complex version of this list is available [here](https://trello.com/b/kJw - [ ] Reactive channels list - [ ] Show characters before message gets cut off in textarea - [x] User Auth -- [ ] Usernames / Displaynames in chat +- [x] Usernames / Displaynames in chat diff --git a/prodServer.ts b/prodServer.ts index e66c47b..7cfa8aa 100644 --- a/prodServer.ts +++ b/prodServer.ts @@ -3,6 +3,7 @@ import express from 'express'; import { createServer } from 'http'; import { Server } from 'socket.io'; import { db } from './src/lib/server/db'; +import { authdb } from './src/lib/server/db/sqlite'; import { v4 as uuidv4 } from 'uuid'; const app = express(); @@ -19,10 +20,11 @@ io.on('connection', async (socket) => { console.log(`\x1b[35m[ws:kit]\x1b[0m message from ${socket.id}: ${msg.content}`); // Store the message in the database await db.sendMessage(msg.channel, msg.content, msg.id, uuidv4()); + const sender = authdb.getUser(msg.id); io!.emit('message', { - user: msg.id, + user: sender.username, message: msg.content, - imageSrc: `https://api.dicebear.com/9.x/identicon/svg?seed=${msg.id}`, + imageSrc: sender.image, channel: msg.channel, }); } diff --git a/src/lib/components/user.svelte b/src/lib/components/user.svelte index 0019068..32093ee 100644 --- a/src/lib/components/user.svelte +++ b/src/lib/components/user.svelte @@ -1,8 +1,8 @@ {#if data.session} diff --git a/src/lib/functions/websocketConfig.ts b/src/lib/functions/websocketConfig.ts index 104fc2c..eef4a03 100644 --- a/src/lib/functions/websocketConfig.ts +++ b/src/lib/functions/websocketConfig.ts @@ -4,6 +4,7 @@ import type { HttpServer } from 'vite'; // file gets loaded as a vite plugin, it will crash import { v4 as uuidv4 } from 'uuid'; import { db } from '../server/db'; +import { authdb } from '../server/db/sqlite'; let io: SocketIOServer | undefined; @@ -28,10 +29,11 @@ export function startupSocketIOServer(httpServer: HttpServer | null) { console.log(`\x1b[35m[ws:kit]\x1b[0m message from ${socket.id}: ${msg.content}`); // Store the message in the database await db.sendMessage(msg.channel, msg.content, msg.id, uuidv4()); + const sender = authdb.getUser(msg.id); io!.emit('message', { - user: msg.id, + user: sender.username, message: msg.content, - imageSrc: `https://api.dicebear.com/9.x/identicon/svg?seed=${msg.id}`, + imageSrc: sender.image, channel: msg.channel, }); } diff --git a/src/lib/server/db/index.ts b/src/lib/server/db/index.ts index 84d5f2e..fe1a5af 100644 --- a/src/lib/server/db/index.ts +++ b/src/lib/server/db/index.ts @@ -46,7 +46,7 @@ class Db { message_content TEXT, channel_name TEXT, timestamp TIMESTAMP, - sender UUID, + sender TEXT, PRIMARY KEY (channel_name, timestamp) ) WITH CLUSTERING ORDER BY (timestamp DESC);`); } catch (e) { @@ -67,7 +67,7 @@ class Db { sender, }); } catch (e) { - console.log(`Error storing messages: ${e as Error}`); + console.log(`Error storing message: ${e as Error}`); } } diff --git a/src/lib/server/db/sqlite.ts b/src/lib/server/db/sqlite.ts new file mode 100644 index 0000000..d98bdeb --- /dev/null +++ b/src/lib/server/db/sqlite.ts @@ -0,0 +1,28 @@ +import Database from 'better-sqlite3'; + +interface Profile { + username: string; + image: string; +} + +class AuthDb { + private client = new Database('./src/lib/server/db/users.db'); + + init() { + // Set WAL pragma for preformance reasons + this.client.pragma('journal_mode = WAL'); + } + + getUser(userId: string): Profile { + const row = this.client.prepare('SELECT username, image FROM user WHERE id = ?').get(userId); + return { + username: (row as Profile).username, + image: (row as Profile).image ?? `https://api.dicebear.com/9.x/identicon/svg?seed=${userId}`, + }; + } +} + +const authdb = new AuthDb(); +authdb.init(); + +export { authdb }; diff --git a/src/routes/(main)/channel/[channel]/+page.server.ts b/src/routes/(main)/channel/[channel]/+page.server.ts index 371b3fb..833a515 100644 --- a/src/routes/(main)/channel/[channel]/+page.server.ts +++ b/src/routes/(main)/channel/[channel]/+page.server.ts @@ -1,9 +1,10 @@ import { db } from '$lib/server/db'; +import { authdb } from '$lib/server/db/sqlite.js'; import type { TypeMessage } from '$lib/types'; import { error, redirect } from '@sveltejs/kit'; import { auth } from '$lib/server/db/auth'; -export async function load({ params, request }): Promise<{ messages: TypeMessage[] }> { +export async function load({ params, request }): Promise<{ messages: TypeMessage[]; currentUser: string }> { const session = await auth.api.getSession({ headers: request.headers, }); @@ -18,10 +19,11 @@ export async function load({ params, request }): Promise<{ messages: TypeMessage if (rows.messages !== null) { messages = rows ? rows.messages.map((value) => { + const sender = authdb.getUser(value.sender); return { message: value.message_content, - user: value.sender.toString(), - imageSrc: `https://api.dicebear.com/9.x/identicon/svg?seed=${value.sender.toString()}`, + user: sender.username, + imageSrc: sender.image, channel: value.channel, }; }) @@ -32,5 +34,6 @@ export async function load({ params, request }): Promise<{ messages: TypeMessage return { messages: messages ?? [], + currentUser: session.user.id!, }; } diff --git a/src/routes/(main)/channel/[channel]/+page.svelte b/src/routes/(main)/channel/[channel]/+page.svelte index 6dc7c75..39d7e35 100644 --- a/src/routes/(main)/channel/[channel]/+page.svelte +++ b/src/routes/(main)/channel/[channel]/+page.svelte @@ -10,12 +10,10 @@ import Send from 'lucide-svelte/icons/send'; import { io } from 'socket.io-client'; import { onMount } from 'svelte'; - import { v4 as uuidv4 } from 'uuid'; import type { PageData } from './$types'; const { data }: { data: PageData } = $props(); - let user: string = uuidv4(); let socket: Websocket | undefined = $state(); let msg: string = $state(''); let showDialog: boolean = $state(false); @@ -25,7 +23,7 @@ function submit() { if (msg.length <= 2000) { - socket?.sendMessage(user!, msg); + socket?.sendMessage(data.currentUser, msg); if (textareaRef) textareaRef.style.height = '40px'; msg = ''; } else {