forked from mirrors/homebox
feat: WebSocket based implementation of server sent events for cache busting (#527)
* rough implementation of WS based event system for server side notifications of mutation * fix test construction * fix deadlock on event bus * disable linter error * add item mutation events * remove old event bus code * refactor event system to use composables * refresh items table when new item is added * fix create form errors * cleanup unnecessary calls * fix importer erorrs + limit fn calls on import
This commit is contained in:
parent
cceec06148
commit
2cbcc8bb1d
31 changed files with 458 additions and 208 deletions
|
@ -1,38 +0,0 @@
|
|||
export enum EventTypes {
|
||||
// ClearStores event is used to inform the stores that _all_ the data they are using
|
||||
// is now out of date and they should refresh - This is used when the user makes large
|
||||
// changes to the data such as bulk actions or importing a CSV file
|
||||
InvalidStores,
|
||||
}
|
||||
|
||||
export type EventFn = () => void;
|
||||
|
||||
export interface IEventBus {
|
||||
on(event: EventTypes, fn: EventFn, key: string): void;
|
||||
off(event: EventTypes, key: string): void;
|
||||
emit(event: EventTypes): void;
|
||||
}
|
||||
|
||||
class EventBus implements IEventBus {
|
||||
private listeners: Record<EventTypes, Record<string, EventFn>> = {
|
||||
[EventTypes.InvalidStores]: {},
|
||||
};
|
||||
|
||||
on(event: EventTypes, fn: EventFn, key: string): void {
|
||||
this.listeners[event][key] = fn;
|
||||
}
|
||||
|
||||
off(event: EventTypes, key: string): void {
|
||||
delete this.listeners[event][key];
|
||||
}
|
||||
|
||||
emit(event: EventTypes): void {
|
||||
Object.values(this.listeners[event]).forEach(fn => fn());
|
||||
}
|
||||
}
|
||||
|
||||
const bus = new EventBus();
|
||||
|
||||
export function useEventBus(): IEventBus {
|
||||
return bus;
|
||||
}
|
78
frontend/composables/use-server-events.ts
Normal file
78
frontend/composables/use-server-events.ts
Normal file
|
@ -0,0 +1,78 @@
|
|||
export enum ServerEvent {
|
||||
LocationMutation = "location.mutation",
|
||||
ItemMutation = "item.mutation",
|
||||
LabelMutation = "label.mutation",
|
||||
}
|
||||
|
||||
export type EventMessage = {
|
||||
event: ServerEvent;
|
||||
};
|
||||
|
||||
let socket: WebSocket | null = null;
|
||||
|
||||
const listeners = new Map<ServerEvent, (() => void)[]>();
|
||||
|
||||
function connect(onmessage: (m: EventMessage) => void) {
|
||||
const ws = new WebSocket(`ws://${window.location.host}/api/v1/ws/events`);
|
||||
|
||||
ws.onopen = () => {
|
||||
console.debug("connected to server");
|
||||
};
|
||||
|
||||
ws.onclose = () => {
|
||||
console.debug("disconnected from server");
|
||||
setTimeout(() => {
|
||||
connect(onmessage);
|
||||
}, 3000);
|
||||
};
|
||||
|
||||
ws.onerror = err => {
|
||||
console.error("websocket error", err);
|
||||
};
|
||||
|
||||
const thorttled = new Map<ServerEvent, any>();
|
||||
|
||||
thorttled.set(ServerEvent.LocationMutation, useThrottleFn(onmessage, 1000));
|
||||
thorttled.set(ServerEvent.ItemMutation, useThrottleFn(onmessage, 1000));
|
||||
thorttled.set(ServerEvent.LabelMutation, useThrottleFn(onmessage, 1000));
|
||||
|
||||
ws.onmessage = msg => {
|
||||
const pm = JSON.parse(msg.data);
|
||||
const fn = thorttled.get(pm.event);
|
||||
if (fn) {
|
||||
fn(pm);
|
||||
}
|
||||
};
|
||||
|
||||
socket = ws;
|
||||
}
|
||||
|
||||
export function onServerEvent(event: ServerEvent, callback: () => void) {
|
||||
if (socket === null) {
|
||||
connect(e => {
|
||||
console.debug("received event", e);
|
||||
listeners.get(e.event)?.forEach(c => c());
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (!listeners.has(event)) {
|
||||
listeners.set(event, []);
|
||||
}
|
||||
listeners.get(event)?.push(callback);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
const got = listeners.get(event);
|
||||
if (got) {
|
||||
listeners.set(
|
||||
event,
|
||||
got.filter(c => c !== callback)
|
||||
);
|
||||
}
|
||||
|
||||
if (listeners.get(event)?.length === 0) {
|
||||
listeners.delete(event);
|
||||
}
|
||||
});
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue