summaryrefslogtreecommitdiff
path: root/ui/lib/store/messages.svelte.js
diff options
context:
space:
mode:
authorOwen Jacobson <owen@grimoire.ca>2025-02-25 00:37:33 -0500
committerOwen Jacobson <owen@grimoire.ca>2025-02-26 01:54:44 -0500
commitf788ea84e25a4f7216ca0604aeb216346403b6ef (patch)
treedb62f5d1e15d871f8a73ce20b40cd53053d12f85 /ui/lib/store/messages.svelte.js
parentf1b124a0423cdaf4d8a6bd62a2059722e9afdf2b (diff)
Track state on a per-session basis, rather than via globals.
Sorry about the thousand-line omnibus change; this is functionally a rewrite of the client's state tracking, flavoured to resemble the existing code as far as is possible, rather than something that can be parted out and committed in pieces. Highlights: * No more `store.writeable()`s. All state is now tracked using state runs or derivatives. State is still largely structured the way it was, but several bits of nested state have been rewritten to ensure that their properties are reactive just as much as their containers are. * State is no longer global. `(app)/+layout` manages a stateful session, created via its load hook and started/stopped via component mount and destroy events. The session also tracks an event source for the current state, and feeds events into the state, broadly along the same lines as the previous stores-based approach. Together these two changes fix up several rough spots integrating state with Svelte, and allow for the possibility of multiple states. This is a major step towards restartable states, and thus towards better connection management, which will require the ability to "start over" once a connection is restored.
Diffstat (limited to 'ui/lib/store/messages.svelte.js')
-rw-r--r--ui/lib/store/messages.svelte.js78
1 files changed, 0 insertions, 78 deletions
diff --git a/ui/lib/store/messages.svelte.js b/ui/lib/store/messages.svelte.js
deleted file mode 100644
index e6fe7f3..0000000
--- a/ui/lib/store/messages.svelte.js
+++ /dev/null
@@ -1,78 +0,0 @@
-import { DateTime } from 'luxon';
-import * as markdown from '$lib/markdown.js';
-
-const RUN_COALESCE_MAX_INTERVAL = 10 /* min */ * 60 /* sec */ * 1000; /* ms */
-
-export class Messages {
- channels = $state({}); // Mapping<ChannelId, Message>
-
- inChannel(channel) {
- return this.channels[channel] || [];
- }
-
- addMessage(channel, id, { at, sender, body }) {
- let parsedAt = DateTime.fromISO(at);
- let renderedBody = markdown.render(body);
- const message = { id, at: parsedAt, body, renderedBody };
-
- // You might be thinking, can't this be
- //
- // let runs = (this.channels[channel] ||= []);
- //
- // Let me tell you, I thought that too. Javascript's semantics allow it. It
- // didn't work - the first message in each channel was getting lost as the
- // update to `this.channels` wasn't actually happening. I suspect this is
- // due to the implementation of Svelte's `$state` rune, but I don't know it
- // for sure.
- //
- // In any case, splitting the read and write up like this has the same
- // semantics, and _works_. (This time, for sure!)
- let runs = this.channels[channel] || [];
-
- let currentRun = runs.slice(-1)[0];
- if (currentRun === undefined) {
- currentRun = { sender, messages: [message] };
- runs.push(currentRun);
- } else {
- let lastMessage = currentRun.messages.slice(-1)[0];
- let newRun =
- currentRun.sender !== sender || parsedAt - lastMessage.at > RUN_COALESCE_MAX_INTERVAL;
-
- if (newRun) {
- currentRun = { sender, messages: [message] };
- runs.push(currentRun);
- } else {
- currentRun.messages.push(message);
- }
- }
-
- this.channels[channel] = runs;
-
- return this;
- }
-
- setMessages(messages) {
- this.channels = {};
- for (let { channel, id, at, sender, body } of messages) {
- this.addMessage(channel, id, { at, sender, body });
- }
- return this;
- }
-
- deleteMessage(messageId) {
- for (let channel in this.channels) {
- this.channels[channel] = this.channels[channel]
- .map(({ sender, messages }) => ({
- sender,
- messages: messages.filter(({ id }) => id != messageId)
- }))
- .filter(({ messages }) => messages.length > 0);
- }
- return this;
- }
-
- deleteChannel(id) {
- delete this.channels[id];
- return this;
- }
-}