Some checks failed
/ golint (push) Failing after 10s
These changes are meant to make it possible for new events that come in to immediately render in the components that depend on them.
162 lines
4.1 KiB
TypeScript
162 lines
4.1 KiB
TypeScript
import { defineStore } from "pinia";
|
|
import { ref, shallowRef, shallowReactive } from "vue";
|
|
|
|
import { log } from "@/log";
|
|
import { SSEManager, SSEMessageResource } from "@/SSEManager";
|
|
|
|
import { apiClient } from "@/client";
|
|
import {
|
|
Communication,
|
|
type CommunicationDTO,
|
|
Contact,
|
|
type ContactDTO,
|
|
PublicReport,
|
|
type PublicReportDTO,
|
|
} from "@/type/api";
|
|
|
|
interface uriHaver {
|
|
uri: string;
|
|
}
|
|
type jsonConverter<dto, full> = (arg: dto) => full;
|
|
function createResourceStore<dto, full extends uriHaver>(
|
|
resource_name: string,
|
|
api_base: string,
|
|
from_json: jsonConverter<dto, full>,
|
|
) {
|
|
const byURI = shallowReactive<Map<string, full>>(new Map());
|
|
const _resourceFetchAll = ref<Promise<full[]> | null>(null);
|
|
const _resourceFetchByURI = shallowRef<Map<string, Promise<full> | null>>(
|
|
new Map(),
|
|
);
|
|
|
|
// Subscription
|
|
SSEManager.subscribe((msg: SSEMessageResource) => {
|
|
if (msg.resource.startsWith(resource_name)) {
|
|
if (msg.type == "created") {
|
|
console.log("New resource", resource_name, msg.resource, msg.uri);
|
|
fetchByURI(msg.uri);
|
|
} else if (msg.type == "updated") {
|
|
console.log("Updated resource", resource_name, msg.resource, msg.uri);
|
|
fetchByURI(msg.uri);
|
|
}
|
|
}
|
|
});
|
|
|
|
async function byID(id: string): Promise<full> {
|
|
const uri = uriFromID(id);
|
|
return ensureURI(uri);
|
|
}
|
|
async function ensureURI(uri: string): Promise<full> {
|
|
// Check if we already have the data
|
|
const existing = byURI.get(uri);
|
|
if (existing) {
|
|
return existing;
|
|
}
|
|
|
|
// Check if we're already fetching it
|
|
let fetchPromise = _resourceFetchByURI.value.get(uri);
|
|
if (fetchPromise) {
|
|
return fetchPromise;
|
|
}
|
|
|
|
// Start fetching
|
|
fetchPromise = fetchByURI(uri);
|
|
_resourceFetchByURI.value.set(uri, fetchPromise);
|
|
|
|
try {
|
|
const result = await fetchPromise;
|
|
return result;
|
|
} finally {
|
|
// Clean up the promise after it resolves
|
|
_resourceFetchByURI.value.delete(uri);
|
|
}
|
|
}
|
|
async function fetchAll(): Promise<full[]> {
|
|
/*
|
|
const sessionStore = useSessionStore();
|
|
const session = await sessionStore.get();
|
|
const params = new URLSearchParams();
|
|
params.append("sort", "-created");
|
|
const url = `${session.urls.api.mailer}?${params}`;
|
|
*/
|
|
const url = `/api${api_base}`;
|
|
const dtos = (await apiClient.JSONGet(url)) as dto[];
|
|
const resources = dtos.map((m: dto) => from_json(m));
|
|
//let new_all = new Map<string, full>();
|
|
resources.forEach((r: full) => {
|
|
byURI.set(r.uri, r);
|
|
//new_all.set(r.uri, r);
|
|
log.info("Set", resource_name, r);
|
|
});
|
|
//byURI.value = new_all;
|
|
return resources;
|
|
}
|
|
async function fetchByID(id: string): Promise<full> {
|
|
const uri = uriFromID(id);
|
|
return fetchByURI(uri);
|
|
}
|
|
async function fetchByURI(uri: string): Promise<full> {
|
|
try {
|
|
const response = await fetch(uri);
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
const body: dto = await response.json();
|
|
const report = from_json(body);
|
|
//let new_all = new Map<string, full>(byURI.value);
|
|
//new_all.set(report.uri, report);
|
|
byURI.set(report.uri, report);
|
|
//byURI.value = new_all;
|
|
return report;
|
|
} catch (err) {
|
|
console.error("Error loading users:", err);
|
|
throw err;
|
|
}
|
|
}
|
|
function hasAll(): boolean {
|
|
return !!_resourceFetchAll.value;
|
|
}
|
|
function loadingAll(): boolean {
|
|
return !!_resourceFetchAll.value;
|
|
}
|
|
function loadingURI(uri: string | undefined): boolean {
|
|
if (uri === undefined) {
|
|
return false;
|
|
}
|
|
return !!_resourceFetchByURI.value.get(uri);
|
|
}
|
|
function uriFromID(id: string): string {
|
|
return `${api_base}/${id}`;
|
|
}
|
|
return {
|
|
byID,
|
|
byURI,
|
|
ensureURI,
|
|
fetchAll,
|
|
fetchByID,
|
|
fetchByURI,
|
|
hasAll,
|
|
loadingAll,
|
|
loadingURI,
|
|
};
|
|
}
|
|
export const useStoreResource = defineStore("resource", () => {
|
|
return {
|
|
communication: createResourceStore<CommunicationDTO, Communication>(
|
|
"sync:communication",
|
|
"/communication",
|
|
Communication.fromJSON,
|
|
),
|
|
contact: createResourceStore<ContactDTO, Contact>(
|
|
"sync:contact",
|
|
"/contact",
|
|
Contact.fromJSON,
|
|
),
|
|
publicreport: createResourceStore<PublicReportDTO, PublicReport>(
|
|
"sync:publicreport",
|
|
"/publicreport",
|
|
PublicReport.fromJSON,
|
|
),
|
|
};
|
|
});
|