feat: cache everything in node store not only wasm
This commit is contained in:
@@ -1,22 +1,22 @@
|
|||||||
import type { AsyncCache } from '@nodarium/types';
|
import type { AsyncCache } from '@nodarium/types';
|
||||||
import { openDB, type IDBPDatabase } from 'idb';
|
import { openDB, type IDBPDatabase } from 'idb';
|
||||||
|
|
||||||
export class IndexDBCache implements AsyncCache<ArrayBuffer> {
|
export class IndexDBCache implements AsyncCache<unknown> {
|
||||||
|
|
||||||
size: number = 100;
|
size: number = 100;
|
||||||
|
|
||||||
db: Promise<IDBPDatabase<ArrayBuffer>>;
|
db: Promise<IDBPDatabase<unknown>>;
|
||||||
private _cache = new Map<string, ArrayBuffer>();
|
private _cache = new Map<string, unknown>();
|
||||||
|
|
||||||
constructor(id: string) {
|
constructor(id: string) {
|
||||||
this.db = openDB<ArrayBuffer>('cache/' + id, 1, {
|
this.db = openDB<unknown>('cache/' + id, 1, {
|
||||||
upgrade(db) {
|
upgrade(db) {
|
||||||
db.createObjectStore('keyval');
|
db.createObjectStore('keyval');
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async get(key: string) {
|
async get<T>(key: string): Promise<T> {
|
||||||
let res = this._cache.get(key);
|
let res = this._cache.get(key);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
res = await (await this.db).get('keyval', key);
|
res = await (await this.db).get('keyval', key);
|
||||||
@@ -24,13 +24,33 @@ export class IndexDBCache implements AsyncCache<ArrayBuffer> {
|
|||||||
if (res) {
|
if (res) {
|
||||||
this._cache.set(key, res);
|
this._cache.set(key, res);
|
||||||
}
|
}
|
||||||
return res;
|
return res as T;
|
||||||
}
|
}
|
||||||
async set(key: string, value: ArrayBuffer) {
|
|
||||||
|
async getArrayBuffer(key: string) {
|
||||||
|
const res = await this.get(key);
|
||||||
|
if (!res) return;
|
||||||
|
if (res instanceof ArrayBuffer) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
async getString(key: string) {
|
||||||
|
const res = await this.get(key);
|
||||||
|
if (!res) return;
|
||||||
|
if (typeof res === "string") {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
async set(key: string, value: unknown) {
|
||||||
this._cache.set(key, value);
|
this._cache.set(key, value);
|
||||||
const db = await this.db;
|
const db = await this.db;
|
||||||
await db.put('keyval', value, key);
|
await db.put('keyval', value, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
clear() {
|
clear() {
|
||||||
this.db.then(db => db.clear('keyval'));
|
this.db.then(db => db.clear('keyval'));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,32 +13,63 @@ export class RemoteNodeRegistry implements NodeRegistry {
|
|||||||
status: "loading" | "ready" | "error" = "loading";
|
status: "loading" | "ready" | "error" = "loading";
|
||||||
private nodes: Map<string, NodeDefinition> = new Map();
|
private nodes: Map<string, NodeDefinition> = new Map();
|
||||||
|
|
||||||
async fetchJson(url: string) {
|
|
||||||
const response = await fetch(`${this.url}/${url}`);
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
log.error(`Failed to load ${url}`, { response, url, host: this.url });
|
|
||||||
throw new Error(`Failed to load ${url}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.json();
|
|
||||||
}
|
|
||||||
|
|
||||||
async fetchArrayBuffer(url: string) {
|
|
||||||
const response = await fetch(`${this.url}/${url}`);
|
|
||||||
if (!response.ok) {
|
|
||||||
log.error(`Failed to load ${url}`, { response, url, host: this.url });
|
|
||||||
throw new Error(`Failed to load ${url}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.arrayBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private url: string,
|
private url: string,
|
||||||
private cache?: AsyncCache<ArrayBuffer>,
|
private cache?: AsyncCache<ArrayBuffer | string>,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
|
async fetchJson(url: string, skipCache = false) {
|
||||||
|
|
||||||
|
const finalUrl = `${this.url}/${url}`;
|
||||||
|
|
||||||
|
if (!skipCache && this.cache) {
|
||||||
|
const cachedValue = await this.cache?.get<string>(finalUrl);
|
||||||
|
if (cachedValue) {
|
||||||
|
// fetch again in the background, maybe implement that only refetch after a certain time
|
||||||
|
this.fetchJson(url, true)
|
||||||
|
return JSON.parse(cachedValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(finalUrl);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
log.error(`Failed to load ${url}`, { response, url, host: this.url });
|
||||||
|
throw new Error(`Failed to load ${url}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
this.cache?.set(finalUrl, JSON.stringify(result));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fetchArrayBuffer(url: string, skipCache = false) {
|
||||||
|
|
||||||
|
const finalUrl = `${this.url}/${url}`;
|
||||||
|
|
||||||
|
if (!skipCache && this.cache) {
|
||||||
|
const cachedNode = await this.cache?.get<ArrayBuffer>(finalUrl);
|
||||||
|
if (cachedNode) {
|
||||||
|
// fetch again in the background, maybe implement that only refetch after a certain time
|
||||||
|
this.fetchArrayBuffer(url, true)
|
||||||
|
return cachedNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(finalUrl);
|
||||||
|
if (!response.ok) {
|
||||||
|
log.error(`Failed to load ${url}`, { response, url, host: this.url });
|
||||||
|
throw new Error(`Failed to load ${url}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const buffer = await response.arrayBuffer();
|
||||||
|
this.cache?.set(finalUrl, buffer);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
async fetchUsers() {
|
async fetchUsers() {
|
||||||
return this.fetchJson(`nodes/users.json`);
|
return this.fetchJson(`nodes/users.json`);
|
||||||
}
|
}
|
||||||
@@ -48,7 +79,8 @@ export class RemoteNodeRegistry implements NodeRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fetchCollection(userCollectionId: `${string}/${string}`) {
|
async fetchCollection(userCollectionId: `${string}/${string}`) {
|
||||||
return this.fetchJson(`nodes/${userCollectionId}.json`);
|
const col = await this.fetchJson(`nodes/${userCollectionId}.json`);
|
||||||
|
return col
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchNodeDefinition(nodeId: `${string}/${string}/${string}`) {
|
async fetchNodeDefinition(nodeId: `${string}/${string}/${string}`) {
|
||||||
@@ -56,10 +88,6 @@ export class RemoteNodeRegistry implements NodeRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async fetchNodeWasm(nodeId: `${string}/${string}/${string}`) {
|
private async fetchNodeWasm(nodeId: `${string}/${string}/${string}`) {
|
||||||
const cachedNode = await this.cache?.get(nodeId);
|
|
||||||
if (cachedNode) {
|
|
||||||
return cachedNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
const node = await this.fetchArrayBuffer(`nodes/${nodeId}.wasm`);
|
const node = await this.fetchArrayBuffer(`nodes/${nodeId}.wasm`);
|
||||||
if (!node) {
|
if (!node) {
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ export interface AsyncCache<T = unknown> {
|
|||||||
* @param key - The key to get the value for
|
* @param key - The key to get the value for
|
||||||
* @returns The value for the given key, or undefined if no such value exists
|
* @returns The value for the given key, or undefined if no such value exists
|
||||||
*/
|
*/
|
||||||
get: (key: string) => Promise<T | undefined>;
|
get: <A = T>(key: string) => Promise<A | undefined>;
|
||||||
/**
|
/**
|
||||||
* Set the value for the given key
|
* Set the value for the given key
|
||||||
* @param key - The key to set the value for
|
* @param key - The key to set the value for
|
||||||
|
|||||||
Reference in New Issue
Block a user