feat: Sync chat presence with auth data
This commit is contained in:
parent
9a28fdcf13
commit
ee1eac23ab
2
.gitignore
vendored
2
.gitignore
vendored
@ -28,4 +28,4 @@ vite.config.js.timestamp-*
|
|||||||
vite.config.ts.timestamp-*
|
vite.config.ts.timestamp-*
|
||||||
|
|
||||||
# Sqlite
|
# Sqlite
|
||||||
src/lib/server/db/users.db
|
src/lib/server/db/users.db*
|
||||||
|
2
TODO.md
2
TODO.md
@ -10,4 +10,4 @@ A more complex version of this list is available [here](https://trello.com/b/kJw
|
|||||||
- [ ] Reactive channels list
|
- [ ] Reactive channels list
|
||||||
- [ ] Show characters before message gets cut off in textarea
|
- [ ] Show characters before message gets cut off in textarea
|
||||||
- [x] User Auth
|
- [x] User Auth
|
||||||
- [ ] Usernames / Displaynames in chat
|
- [x] Usernames / Displaynames in chat
|
||||||
|
@ -3,6 +3,7 @@ import express from 'express';
|
|||||||
import { createServer } from 'http';
|
import { createServer } from 'http';
|
||||||
import { Server } from 'socket.io';
|
import { Server } from 'socket.io';
|
||||||
import { db } from './src/lib/server/db';
|
import { db } from './src/lib/server/db';
|
||||||
|
import { authdb } from './src/lib/server/db/sqlite';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
const app = express();
|
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}`);
|
console.log(`\x1b[35m[ws:kit]\x1b[0m message from ${socket.id}: ${msg.content}`);
|
||||||
// Store the message in the database
|
// Store the message in the database
|
||||||
await db.sendMessage(msg.channel, msg.content, msg.id, uuidv4());
|
await db.sendMessage(msg.channel, msg.content, msg.id, uuidv4());
|
||||||
|
const sender = authdb.getUser(msg.id);
|
||||||
io!.emit('message', {
|
io!.emit('message', {
|
||||||
user: msg.id,
|
user: sender.username,
|
||||||
message: msg.content,
|
message: msg.content,
|
||||||
imageSrc: `https://api.dicebear.com/9.x/identicon/svg?seed=${msg.id}`,
|
imageSrc: sender.image,
|
||||||
channel: msg.channel,
|
channel: msg.channel,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { PageData } from '../../routes/$types';
|
import type { PageData } from '../../routes/(main)/$types';
|
||||||
const { data }: { data: PageData } = $props();
|
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>
|
</script>
|
||||||
|
|
||||||
{#if data.session}
|
{#if data.session}
|
||||||
|
@ -4,6 +4,7 @@ import type { HttpServer } from 'vite';
|
|||||||
// file gets loaded as a vite plugin, it will crash
|
// file gets loaded as a vite plugin, it will crash
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
import { db } from '../server/db';
|
import { db } from '../server/db';
|
||||||
|
import { authdb } from '../server/db/sqlite';
|
||||||
|
|
||||||
let io: SocketIOServer | undefined;
|
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}`);
|
console.log(`\x1b[35m[ws:kit]\x1b[0m message from ${socket.id}: ${msg.content}`);
|
||||||
// Store the message in the database
|
// Store the message in the database
|
||||||
await db.sendMessage(msg.channel, msg.content, msg.id, uuidv4());
|
await db.sendMessage(msg.channel, msg.content, msg.id, uuidv4());
|
||||||
|
const sender = authdb.getUser(msg.id);
|
||||||
io!.emit('message', {
|
io!.emit('message', {
|
||||||
user: msg.id,
|
user: sender.username,
|
||||||
message: msg.content,
|
message: msg.content,
|
||||||
imageSrc: `https://api.dicebear.com/9.x/identicon/svg?seed=${msg.id}`,
|
imageSrc: sender.image,
|
||||||
channel: msg.channel,
|
channel: msg.channel,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ class Db {
|
|||||||
message_content TEXT,
|
message_content TEXT,
|
||||||
channel_name TEXT,
|
channel_name TEXT,
|
||||||
timestamp TIMESTAMP,
|
timestamp TIMESTAMP,
|
||||||
sender UUID,
|
sender TEXT,
|
||||||
PRIMARY KEY (channel_name, timestamp)
|
PRIMARY KEY (channel_name, timestamp)
|
||||||
) WITH CLUSTERING ORDER BY (timestamp DESC);`);
|
) WITH CLUSTERING ORDER BY (timestamp DESC);`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -67,7 +67,7 @@ class Db {
|
|||||||
sender,
|
sender,
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(`Error storing messages: ${e as Error}`);
|
console.log(`Error storing message: ${e as Error}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
28
src/lib/server/db/sqlite.ts
Normal file
28
src/lib/server/db/sqlite.ts
Normal 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 };
|
@ -1,9 +1,10 @@
|
|||||||
import { db } from '$lib/server/db';
|
import { db } from '$lib/server/db';
|
||||||
|
import { authdb } from '$lib/server/db/sqlite.js';
|
||||||
import type { TypeMessage } from '$lib/types';
|
import type { TypeMessage } from '$lib/types';
|
||||||
import { error, redirect } from '@sveltejs/kit';
|
import { error, redirect } from '@sveltejs/kit';
|
||||||
import { auth } from '$lib/server/db/auth';
|
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({
|
const session = await auth.api.getSession({
|
||||||
headers: request.headers,
|
headers: request.headers,
|
||||||
});
|
});
|
||||||
@ -18,10 +19,11 @@ export async function load({ params, request }): Promise<{ messages: TypeMessage
|
|||||||
if (rows.messages !== null) {
|
if (rows.messages !== null) {
|
||||||
messages = rows
|
messages = rows
|
||||||
? rows.messages.map((value) => {
|
? rows.messages.map((value) => {
|
||||||
|
const sender = authdb.getUser(value.sender);
|
||||||
return {
|
return {
|
||||||
message: value.message_content,
|
message: value.message_content,
|
||||||
user: value.sender.toString(),
|
user: sender.username,
|
||||||
imageSrc: `https://api.dicebear.com/9.x/identicon/svg?seed=${value.sender.toString()}`,
|
imageSrc: sender.image,
|
||||||
channel: value.channel,
|
channel: value.channel,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
@ -32,5 +34,6 @@ export async function load({ params, request }): Promise<{ messages: TypeMessage
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
messages: messages ?? [],
|
messages: messages ?? [],
|
||||||
|
currentUser: session.user.id!,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -10,12 +10,10 @@
|
|||||||
import Send from 'lucide-svelte/icons/send';
|
import Send from 'lucide-svelte/icons/send';
|
||||||
import { io } from 'socket.io-client';
|
import { io } from 'socket.io-client';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
|
|
||||||
const { data }: { data: PageData } = $props();
|
const { data }: { data: PageData } = $props();
|
||||||
|
|
||||||
let user: string = uuidv4();
|
|
||||||
let socket: Websocket | undefined = $state();
|
let socket: Websocket | undefined = $state();
|
||||||
let msg: string = $state('');
|
let msg: string = $state('');
|
||||||
let showDialog: boolean = $state(false);
|
let showDialog: boolean = $state(false);
|
||||||
@ -25,7 +23,7 @@
|
|||||||
|
|
||||||
function submit() {
|
function submit() {
|
||||||
if (msg.length <= 2000) {
|
if (msg.length <= 2000) {
|
||||||
socket?.sendMessage(user!, msg);
|
socket?.sendMessage(data.currentUser, msg);
|
||||||
if (textareaRef) textareaRef.style.height = '40px';
|
if (textareaRef) textareaRef.style.height = '40px';
|
||||||
msg = '';
|
msg = '';
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user