Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

channel persistence #8

Merged
merged 15 commits into from
Jul 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"editor.tabSize": 2,
"editor.detectIndentation": false,
"editor.formatOnSave": true,
"cSpell.enabled": false,
"css.lint.unknownAtRules": "ignore",

"[svelte]": {
Expand Down
9 changes: 9 additions & 0 deletions frontend/src/components/Channels.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<script lang="ts">
import { SendMessage } from '$lib/grpc';
import { pb, writeChannel } from '$lib/pocketbase';
import { channel, channels } from '$lib/stores/channel';

let newChannelActive = false;
Expand All @@ -20,6 +22,13 @@

const addChannel = (name: string) => {
channels.add(name);
writeChannel(name);
SendMessage({
channelId: 'system',
text: `channel_add ${name}`,
jwt: pb.authStore.token,
userId: pb.authStore.model?.name || ''
});
newChannelActive = false;
newChannelName = '';
};
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/components/Input.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import { channel } from '$lib/stores/channel';
import { status } from '$lib/stores/status';
import { currentUser } from '$lib/pocketbase';
import { currentUser, pb } from '$lib/pocketbase';
import { SendMessage } from '$lib/grpc';
import type { OutgoingMessage } from '$lib/types';

Expand All @@ -13,7 +13,8 @@
let msg: OutgoingMessage = {
channelId: $channel,
userId: $currentUser?.username,
text: message
text: message,
jwt: pb.authStore.token
};
SendMessage(msg);
message = '';
Expand Down
16 changes: 13 additions & 3 deletions frontend/src/components/Login.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,27 @@
import { server } from '$lib/stores/server';
import { currentUser, pb } from '$lib/pocketbase';
import { Connect } from '$lib/grpc';

import Toast from './Toast.svelte';
let toast: Toast;
let password = '';
let username = '';

async function login() {
await pb.collection('users').authWithPassword(username, password);
await Connect($server, username, '0', pb.authStore.token);
await pb
.collection('users')
.authWithPassword(username, password)
.then((_) => {
toast.callToast('Login successful', 'success');
Connect($server, username, '0', pb.authStore.token);
})
.catch((err) => {
toast.callToast(err.message, 'error');
});
}
</script>

<div>
<Toast bind:this={toast} />
{#if !$currentUser}
<form on:submit|preventDefault>
<input class="input input-secondary" type="text" bind:value={username} placeholder="Email" />
Expand Down
35 changes: 35 additions & 0 deletions frontend/src/components/Toast.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<script lang="ts">
let message = '';
let alerttype = 'alert-error';

// https://akashmittal.com/svelte-calling-function-child-parent/
// call from parent as:
// let toast: Toast;
// toast.callToast(message, alerttype);
// <Toast bind:this={toast} />

export function callToast(msg: string, type?: string | undefined, ms?: number | undefined) {
let milliseconds: number = 1200;
if (ms) {
milliseconds = ms;
}
if (type) {
alerttype = `alert-${type}`;
}
message = msg;

setTimeout(() => {
message = '';
}, milliseconds);
}
</script>

<div class="toast toast-center z-40">
{#if message}
<div class="alert {alerttype}">
<div>
<span>{message}</span>
</div>
</div>
{/if}
</div>
22 changes: 21 additions & 1 deletion frontend/src/lib/grpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { status } from '$lib/stores/status';
import { ChatServiceClient } from '$lib/proto/chat/v1/chat.client';
import type { ChatMessage } from '$lib/proto/chat/v1/chat';
import type { Message, OutgoingMessage } from './types';
import { currentUser, pb } from './pocketbase';
import { channels } from './stores/channel';

export const chat_cache = persisted(
'chatmessages', // storage
Expand Down Expand Up @@ -75,7 +77,8 @@ export const Connect = async (serverId: string, userId: string, timestamp: strin

}
} catch (_) {
// Stream closed
// Stream closed, force user to log in again
currentUser.set(null);
}

// await sub.headers;
Expand All @@ -99,6 +102,7 @@ export const SendMessage = (msg: OutgoingMessage) => {
userId: msg.userId,
text: msg.text,
ts: "0", // The server will set the timestamp
jwt: msg.jwt,
};

client.send(request).then((response) => {
Expand All @@ -125,6 +129,10 @@ const filtered = (msg: ChatMessage, lastTs: string): boolean => {
return true;
}

if (msg.channelId === "system" && msg.userId !== pb.authStore.model?.name) {
return filter_system_messages(msg);
}

// Deduplicate messages with the same timestamp
if (msg.ts === lastTs) {
return true;
Expand All @@ -142,3 +150,15 @@ const timestampToDate = (timestamp: string): string => {
return timestamp;
}
}

const filter_system_messages = (msg: ChatMessage): boolean => {

// Tell UI to show new channel when another user adds one
if (msg.text.startsWith("channel_add")) {
const channel_name = msg.text.split(" ")[1]
console.log(channel_name)
channels.add(channel_name);
}

return true;
}
33 changes: 30 additions & 3 deletions frontend/src/lib/pocketbase.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,40 @@
import { env } from '$env/dynamic/public';

import PocketBase from 'pocketbase';

import { writable } from 'svelte/store';
import { channels } from './stores/channel';
import { users } from './stores/users';

export const pb = new PocketBase(env.PUBLIC_POCKETBASE_URL);

export const currentUser = writable(pb.authStore.model);

pb.authStore.onChange(() => {
currentUser.set(pb.authStore.model);
});

export const fetchChannels = async () => {
const records = await pb.collection('channels').getFullList({
sort: 'created',
});

// convert records to array and set in channels store
channels.set(records.map((record) => {
return record.name;
}));
}

export const writeChannel = async (channelName: string) => {
await pb.collection('channels').create({
name: channelName,
});
}

export const fetchUsers = async () => {
const records = await pb.collection('users').getFullList({
sort: 'created',
});

// convert records to array and set in channels store
users.set(records.map((record) => {
return record.name;
}));
}
15 changes: 13 additions & 2 deletions frontend/src/lib/proto/chat/v1/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ export interface ChatMessage {
* @generated from protobuf field: string ts = 4;
*/
ts: string; // timestamp
/**
* @generated from protobuf field: string jwt = 5;
*/
jwt: string;
}
/**
* The response payload after sending a notification
Expand Down Expand Up @@ -148,11 +152,12 @@ class ChatMessage$Type extends MessageType<ChatMessage> {
{ no: 1, name: "channel_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 2, name: "user_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 3, name: "text", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 4, name: "ts", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
{ no: 4, name: "ts", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 5, name: "jwt", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
]);
}
create(value?: PartialMessage<ChatMessage>): ChatMessage {
const message = { channelId: "", userId: "", text: "", ts: "" };
const message = { channelId: "", userId: "", text: "", ts: "", jwt: "" };
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
if (value !== undefined)
reflectionMergePartial<ChatMessage>(this, message, value);
Expand All @@ -175,6 +180,9 @@ class ChatMessage$Type extends MessageType<ChatMessage> {
case /* string ts */ 4:
message.ts = reader.string();
break;
case /* string jwt */ 5:
message.jwt = reader.string();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
Expand All @@ -199,6 +207,9 @@ class ChatMessage$Type extends MessageType<ChatMessage> {
/* string ts = 4; */
if (message.ts !== "")
writer.tag(4, WireType.LengthDelimited).string(message.ts);
/* string jwt = 5; */
if (message.jwt !== "")
writer.tag(5, WireType.LengthDelimited).string(message.jwt);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/lib/stores/channel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ function createChannelSelector() {
}

function createChannelList() {
const { subscribe, update } = writable<string[]>(['general']);
const { subscribe, update } = writable<string[]>([]);
return {
subscribe,
add: (channel: string) => update(channels => [...channels, channel]),
remove: (channel: string) => update(channels => channels.filter(c => c !== channel)),
set: (channels: string[]) => update(_ => channels),
};
}

Expand Down
13 changes: 13 additions & 0 deletions frontend/src/lib/stores/users.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { writable } from 'svelte/store';

function createUserList() {
const { subscribe, update } = writable<string[]>([]);
return {
subscribe,
add: (user: string) => update(users => [...users, user]),
remove: (user: string) => update(users => users.filter(c => c !== user)),
set: (users: string[]) => update(_ => users),
};
}

export const users = createUserList();
1 change: 1 addition & 0 deletions frontend/src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ export interface OutgoingMessage {
channelId: string;
userId: string;
text: string;
jwt: string;
}
4 changes: 3 additions & 1 deletion frontend/src/routes/+layout.svelte
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
<script>
import '../app.css';
import { onDestroy, onMount } from 'svelte';
import { currentUser, pb } from '$lib/pocketbase';
import { currentUser, fetchChannels, fetchUsers, pb } from '$lib/pocketbase';
import { Connect, Disconnect } from '$lib/grpc';
import { server } from '$lib/stores/server';

onMount(() => {
if ($currentUser) {
fetchChannels();
fetchUsers();
Connect($server, $currentUser.username, '0', pb.authStore.token);
}
});
Expand Down
4 changes: 3 additions & 1 deletion migrations/1688903842_create_admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@ migrate(
return Dao(db).saveAdmin(admin);
}
},
(db) => { }
(db) => {
return null;
}
);
Loading
Loading