Adds an api to get asynchronous update events.
This commit is contained in:
73
src/lib/server/dataPolling.ts
Normal file
73
src/lib/server/dataPolling.ts
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
import type { ServiceData, ServicePoller } from '$lib/services/service';
|
||||||
|
import { getServiceRecord } from '$lib/services/services';
|
||||||
|
import { readable, type Readable } from 'svelte/store';
|
||||||
|
import { serverConfig } from './config';
|
||||||
|
|
||||||
|
type MayAsyncServiceData = ServiceData | Promise<ServiceData>;
|
||||||
|
|
||||||
|
let serviceData: MayAsyncServiceData[][] | undefined = undefined;
|
||||||
|
|
||||||
|
function forEachService(
|
||||||
|
fn: (group: number, item: number, pollResult: Promise<ServiceData>) => void
|
||||||
|
): MayAsyncServiceData[][] {
|
||||||
|
const config = serverConfig();
|
||||||
|
|
||||||
|
if (serviceData == undefined) {
|
||||||
|
serviceData = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [idxGroup, group] of config.services.entries()) {
|
||||||
|
if (serviceData[group] == undefined) {
|
||||||
|
serviceData[group] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [idxItem, service] of group.items.entries()) {
|
||||||
|
const poller: ServicePoller = getServiceRecord(service.type || '').poll;
|
||||||
|
fn(idxGroup, idxItem, poller(service));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return serviceData;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCurrentServiceData(): MayAsyncServiceData[][] {
|
||||||
|
if (serviceData != undefined) {
|
||||||
|
return serviceData;
|
||||||
|
}
|
||||||
|
|
||||||
|
return forEachService((group: number, item: number, pollResult: Promise<ServiceData>) => {
|
||||||
|
(serviceData as MayAsyncServiceData[][])[group][item] = pollResult.then(
|
||||||
|
(data: ServiceData) => {
|
||||||
|
(serviceData as MayAsyncServiceData[][])[group][item] = data;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ServiceDataEvent {
|
||||||
|
group: number;
|
||||||
|
item: number;
|
||||||
|
data: ServiceData;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pollInterval = 30000;
|
||||||
|
|
||||||
|
export const serviceDataEvents = readable<ServiceDataEvent>(undefined, (set) => {
|
||||||
|
console.debug('starting ServiceData polling loop every ' + pollInterval / 1000 + 's');
|
||||||
|
const timer = setInterval(() => {
|
||||||
|
forEachService((group: number, item: number, result: Promise<ServiceData>) => {
|
||||||
|
(serviceData as MayAsyncServiceData[][])[group][item] = result.then(
|
||||||
|
(data: ServiceData) => {
|
||||||
|
(serviceData as MayAsyncServiceData[][])[group][item] = data;
|
||||||
|
set({ group, item, data });
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}, pollInterval);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
console.debug('stopping ServiceData polling loop');
|
||||||
|
clearInterval(timer);
|
||||||
|
};
|
||||||
|
});
|
||||||
27
src/routes/api/updates/+server.ts
Normal file
27
src/routes/api/updates/+server.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { serviceDataEvents } from '$lib/server/dataPolling';
|
||||||
|
import type { RequestHandler } from '@sveltejs/kit';
|
||||||
|
import type { Unsubscriber } from 'svelte/store';
|
||||||
|
|
||||||
|
export const GET: RequestHandler = () => {
|
||||||
|
let unsubscribe: Unsubscriber | undefined = undefined;
|
||||||
|
const stream = new ReadableStream({
|
||||||
|
start: (controller) => {
|
||||||
|
console.debug('ServiceDataEvent stream started');
|
||||||
|
unsubscribe = serviceDataEvents.subscribe((event) => {
|
||||||
|
const data = `event:message\ndata:${JSON.stringify(event)}\n\n`;
|
||||||
|
controller.enqueue(data);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
cancel: (reason) => {
|
||||||
|
console.debug('ServiceDataEvent stream canceled: ', reason);
|
||||||
|
if (unsubscribe != undefined) {
|
||||||
|
unsubscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return new Response(stream, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'text/event-stream'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -8,5 +8,6 @@ export default defineConfig({
|
|||||||
include: ['src/**/*.{test,spec}.{js,ts}']
|
include: ['src/**/*.{test,spec}.{js,ts}']
|
||||||
},
|
},
|
||||||
|
|
||||||
build: { target: 'esnext' }
|
build: { target: 'esnext' },
|
||||||
|
logLevel: 'info'
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user