140 lines
3.6 KiB
TypeScript
140 lines
3.6 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/watch/%s/%s", ApiConfig.getWsBase(), 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", ApiConfig.getHttpBase(), 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;
|
|
}
|
|
} |