frontend/classes/ResourceRepo.ts

140 lines
3.7 KiB
TypeScript

import axios from "axios";
import type { Metadata } from "./Metadata";
export interface HasMetadata {
metadata: Metadata
}
export class ResourceEvent<T extends HasMetadata>
{
constructor (
public type: string,
public resources: T[]
) {}
}
export class ResourceRepo<T extends HasMetadata>
{
private resources: Ref<T[]> = ref([]);
private interval: NodeJS.Timeout | undefined = undefined;
private websocket: WebSocket | undefined = undefined;
static init<T extends HasMetadata>()
{
return new ResourceRepo<T>();
}
listen(resource: string)
{
const websocket = new WebSocket(StringUtils.format("%s/api/watch/%s/%s", useRuntimeConfig().public.apiWsBase, resource, this.getNamespace()));
websocket.addEventListener('open', () => {
console.info("Opened Websocket.");
})
websocket.addEventListener("message", (event) => {
const data = JSON.parse(event.data) as ResourceEvent<T>;
console.info(StringUtils.format("[%s] Resource", data.type));
switch (data.type)
{
case "INIT":
{
this.add(data.resources);
break;
}
case "ADDED":
{
this.add(data.resources);
break;
}
case "MODIFIED":
{
this.update(data.resources);
break;
}
case "DELETED":
{
this.delete(data.resources);
break;
}
}
});
const interval = setInterval(() => {
console.info("[PING]");
websocket.send('[PING]');
}, 5000);
websocket.addEventListener("close", () => {
console.info("Closing websocket.");
clearTimeout(interval);
});
this.websocket = websocket;
}
private add(resources: T[])
{
this.resources.value.push(...resources);
}
private delete(resources: T[])
{
for (const resource of resources)
{
const index = this.resources.value.findIndex(item => item.metadata.uid === resource.metadata.uid);
if (index != null)
{
this.resources.value.splice(index, 1);
}
}
}
private update(resources: T[])
{
for (const resource of resources)
{
const index = this.resources.value.findIndex(item => item.metadata.uid === resource.metadata.uid);
if (index != null)
{
this.resources.value[index] = resource;
}
}
}
load(resourceType: string)
{
this.refresh(resourceType);
return this;
}
clear()
{
clearTimeout(this.interval);
if (this.websocket != null)
{
this.websocket.close();
}
}
get()
{
return computed(() => {
return this.resources.value.toSorted((a, b) => a.metadata.name.localeCompare(b.metadata.name));
})
}
private refresh(resourceType: string)
{
const namespace = this.getNamespace();
let url = StringUtils.format("%s/resources/%s", useRuntimeConfig().public.apiBase, resourceType);
if (namespace)
{
url = StringUtils.format("%s/%s", url, namespace);
}
axios.get<T[]>(url)
.then((response) => {
this.resources.value = response.data;
});
}
private getNamespace()
{
return useRoute().params.namespace as string;
}
}