feat: Sync chat presence with auth data

This commit is contained in:
April Hall 2025-02-09 23:39:57 -05:00
parent 9a28fdcf13
commit ee1eac23ab
Signed by: arithefirst
GPG Key ID: 4508A15C4DB91C5B
9 changed files with 49 additions and 16 deletions

2
.gitignore vendored
View File

@ -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*

View File

@ -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

View File

@ -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,
});
}

View File

@ -1,8 +1,8 @@
<script lang="ts">
import type { PageData } from '../../routes/$types';
import type { PageData } from '../../routes/(main)/$types';
const { data }: { data: PageData } = $props();
const imageSrc = data.session?.user.image ?? `https://api.dicebear.com/9.x/identicon/svg?seed=${data.session?.user.name}`;
const imageSrc = data.session?.user.image ?? `https://api.dicebear.com/9.x/identicon/svg?seed=${data.session?.user.id}`;
</script>
{#if data.session}

View File

@ -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,
});
}

View File

@ -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}`);
}
}

View File

@ -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 };

View File

@ -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!,
};
}

View File

@ -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 {