waffle/frontend/src/stores.js

182 lines
5.1 KiB
JavaScript
Raw Normal View History

import { writable } from "svelte/store";
import gateway, { GatewayEventType } from "./gateway";
import request from "./request";
import { apiRoute } from "./storage";
class Store {
constructor(value=null) {
this._handlers = [];
this.value = value;
}
subscribe(handler) {
const newLength = this._handlers.push(handler);
const handlerIndex = newLength - 1;
handler(this.value);
return () => {
this._handlers.splice(handlerIndex, 1);
};
}
updated() {
this._handlers.forEach(e => {
e(this.value);
});
}
}
class ChannelsStore extends Store {
constructor() {
super(gateway.channels || []);
gateway.subscribe(GatewayEventType.Ready, ({ channels }) => {
this.value = channels;
this.updated();
});
gateway.subscribe(GatewayEventType.ChannelCreate, (channel) => {
this.value.push(channel);
this.updated();
});
gateway.subscribe(GatewayEventType.ChannelDelete, ({ id }) => {
const index = this.value.findIndex(e => e.id === id);
if (index === -1)
return;
this.value.splice(index, 1);
this.updated();
});
gateway.subscribe(GatewayEventType.ChannelUpdate, (data) => {
const index = this.value.findIndex(e => e.id === data.id);
if (index === -1)
return;
if (!this.value[index])
return;
this.value[index] = data;
this.updated();
});
}
}
class GatewayStatusStore extends Store {
constructor() {
super({ open: gateway.open, ready: gateway.authenticated });
gateway.subscribe(GatewayEventType.Open, () => {
this.value.open = true;
this.updated();
});
gateway.subscribe(GatewayEventType.Close, () => {
this.value.open = false;
this.value.ready = false;
this.updated();
});
gateway.subscribe(GatewayEventType.Ready, () => {
this.value.ready = true;
this.updated();
});
}
}
class MessageStore extends Store {
constructor(channelId) {
super([]);
this.channelId = channelId;
this.isCollectingOldMessages = true;
this.didDoInitialLoad = false;
}
addMessage(message) {
this.value.push(message);
// only dispatch update if collectOldMessages didn't
if (!this.collectOldMessages()) {
this.updated();
}
}
updateMessage(message) {
const index = this.value.findIndex(e => e.id === message.id);
if (index === -1)
return;
this.value[index] = message;
this.updated();
}
deleteMessage({ id }) {
const index = this.value.findIndex(e => e.id === id);
if (index === -1)
return;
this.value.splice(index, 1);
this.updated();
}
collectOldMessages() {
if (!this.isCollectingOldMessages)
return false;
const target = 50;
const delta = this.value.length - target;
if (delta >= 1) {
this.value.splice(0, delta);
this.updated();
return true;
} else {
return false;
}
}
setIsCollectingOldMessages(isCollectingOldMessages) {
this.isCollectingOldMessages = isCollectingOldMessages;
this.collectOldMessages();
}
async loadOlderMessages() {
const oldestMessage = this.value[0];
const endpoint = oldestMessage ? `channels/${this.channelId}/messages/?before=${oldestMessage.id}` : `channels/${this.channelId}/messages`;
const res = await request("GET", apiRoute(endpoint), true, null);
if (res.success && res.ok && res.json && res.json.length > 0) {
this.value = res.json.concat(this.value);
this.updated();
}
}
async doInitialLoad() {
await this.loadOlderMessages();
this.didDoInitialLoad = true;
}
}
class MessagesStoreProvider {
constructor() {
this.storeByChannel = new Map();
gateway.subscribe(GatewayEventType.MessageCreate, (message) => {
this.getStore(message.channel_id).addMessage(message);
});
gateway.subscribe(GatewayEventType.MessageUpdate, (message) => {
this.getStore(message.channel_id).updateMessage(message);
});
gateway.subscribe(GatewayEventType.MessageDelete, (message) => {
this.getStore(message.channel_id).deleteMessage(message);
});
}
getStore(channelId) {
if (!this.storeByChannel[channelId]) {
this.storeByChannel[channelId] = new MessageStore(channelId);
}
return this.storeByChannel[channelId];
}
}
export const channels = new ChannelsStore();
export const gatewayStatus = new GatewayStatusStore();
export const messagesStoreProvider = new MessagesStoreProvider();
export const selectedChannel = writable({ id: -1, name: "none", creator_id: -1 });