websocket backend + frontend patching.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
<script lang="ts" context="module">
|
||||
import { fetchUIState } from "$lib/client/lucifer";
|
||||
import type Device from "$lib/models/device";
|
||||
import type { UIStatePatch } from "$lib/models/uistate";
|
||||
import type UIState from "$lib/models/uistate";
|
||||
import { getContext, onMount, setContext } from "svelte";
|
||||
import { derived, writable, type Readable } from "svelte/store";
|
||||
@@ -9,7 +10,7 @@
|
||||
|
||||
export interface StateContextData {
|
||||
reload(): Promise<void>
|
||||
state: Readable<UIState | null>
|
||||
state: Readable<UIState>
|
||||
error: Readable<string | null>
|
||||
deviceList: Readable<Device[]>
|
||||
}
|
||||
@@ -20,7 +21,11 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
const state = writable<UIState | null>(null);
|
||||
const state = writable<UIState>({
|
||||
assignments: {},
|
||||
devices: {},
|
||||
script: {},
|
||||
});
|
||||
const error = writable<string | null>(null);
|
||||
|
||||
const deviceList = derived(state, state => {
|
||||
@@ -33,6 +38,8 @@
|
||||
.sort((a,b) => a.id.localeCompare(b.id));
|
||||
})
|
||||
|
||||
|
||||
|
||||
async function reload() {
|
||||
error.set(null);
|
||||
|
||||
@@ -44,7 +51,97 @@
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => { reload(); });
|
||||
async function connectSocket() {
|
||||
let url = `ws://${window.location.host}/subscribe`;
|
||||
if (import.meta.env.VITE_LUCIFER4_BACKEND_URL != null) {
|
||||
url = import.meta.env.VITE_LUCIFER4_BACKEND_URL.replace("http", "ws") +"/subscribe";
|
||||
}
|
||||
|
||||
const socket = new WebSocket(url);
|
||||
|
||||
socket.onmessage = (msg) => {
|
||||
const patch: UIStatePatch = JSON.parse(msg.data);
|
||||
|
||||
state.update(s => {
|
||||
if (patch.device) {
|
||||
if (patch.device.delete) {
|
||||
const devices = {...s.devices};
|
||||
delete devices[patch.device.id];
|
||||
return {...s, devices};
|
||||
} else {
|
||||
return {
|
||||
...s,
|
||||
devices: {
|
||||
...s.devices,
|
||||
[patch.device.id]: {
|
||||
...s.devices[patch.device.id],
|
||||
...patch.device,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (patch.assignment) {
|
||||
if (patch.assignment.delete) {
|
||||
const assignments = {...s.assignments};
|
||||
delete assignments[patch.assignment.id];
|
||||
return {...s, assignments};
|
||||
} else {
|
||||
return {
|
||||
...s,
|
||||
assignments: {
|
||||
...s.assignments,
|
||||
[patch.assignment.id]: {
|
||||
...s.assignments[patch.assignment.id],
|
||||
...patch.assignment,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (patch.script) {
|
||||
if (patch.script.delete) {
|
||||
const scripts = {...s.scripts};
|
||||
delete scripts[patch.script.id];
|
||||
return {...s, scripts};
|
||||
} else {
|
||||
return {
|
||||
...s,
|
||||
scripts: {
|
||||
...s.scripts,
|
||||
[patch.script.id]: {
|
||||
...s.scripts[patch.script.id],
|
||||
...patch.script,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
})
|
||||
}
|
||||
|
||||
socket.onerror = err => {
|
||||
console.warn("Socket failed:", err);
|
||||
socket.close();
|
||||
}
|
||||
|
||||
socket.onclose = () => {
|
||||
setTimeout(() => connectSocket(), 3000);
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
reload();
|
||||
const interval = setInterval(reload, 60000);
|
||||
|
||||
connectSocket();
|
||||
|
||||
return () => clearInterval(interval);
|
||||
});
|
||||
|
||||
setContext<StateContextData>(ctxKey, {
|
||||
reload,
|
||||
|
||||
Reference in New Issue
Block a user