@abextm/cache2
Version:
Utilities for reading OSRS "caches"
152 lines (139 loc) • 4.32 kB
text/typescript
import { CacheProvider } from "./Cache.js";
import { Reader } from "./Reader.js";
type LoadableType<I extends Loadable, ARGS extends unknown[]> = {
decode(reader: Reader, ...args: ARGS): I;
loadData(cache: CacheProvider, ...args: ARGS): Promise<Reader | undefined>;
};
type OrNumber<T extends unknown[]> = T;
export abstract class Loadable {
public static load<I extends Loadable, ARGS extends unknown[]>(
this: LoadableType<I, ARGS>,
cache: CacheProvider | Promise<CacheProvider>,
...args: OrNumber<ARGS>
): Promise<I | undefined>;
public static load<I extends Loadable, ARGS extends unknown[]>(
this: LoadableType<I, ARGS>,
reader: Reader | ArrayBufferView | ArrayBuffer,
...args: OrNumber<ARGS>
): I;
public static load<I extends Loadable, ARGS extends unknown[]>(
this: LoadableType<I, ARGS>,
reader: Reader | ArrayBufferView | ArrayBuffer | CacheProvider | Promise<CacheProvider>,
...args: OrNumber<ARGS>
): Promise<I | undefined> | I {
if (reader instanceof ArrayBuffer || ArrayBuffer.isView(reader)) {
reader = new Reader(reader);
}
if (reader instanceof Reader) {
return this.decode(reader, ...args);
} else {
return (async () => {
let data = await this.loadData(await reader, ...args);
if (data) {
return this.decode(data, ...args);
}
})();
}
}
}
export abstract class PerArchiveLoadable extends Loadable {
public static async loadData(
this: { index: number; },
cache: CacheProvider,
id: number,
): Promise<Reader | undefined> {
let archive = await cache.getArchive(this.index, id as number);
let version = await cache.getVersion(this.index);
let data = archive?.getFile(0)?.data;
return data ? new Reader(data, version) : undefined;
}
public static async all<
I extends PerArchiveLoadable,
ID extends number,
>(this: {
index: number;
decode(reader: Reader, id: ID): I;
}, cache0: CacheProvider | Promise<CacheProvider>): Promise<I[]> {
let cache = await cache0;
let ids = await cache.getArchives(this.index);
if (!ids) {
return [];
}
let archives = await Promise.all(ids.map(id => cache.getArchive(this.index, id)));
let version = await cache.getVersion(this.index);
return archives
.filter(v => v)
.map(v => {
try {
return this.decode(new Reader(v!.getFile(0)!.data, version), v!.archive as ID);
} catch (e) {
if (typeof e === "object" && e && "message" in e) {
let ea = e as any;
ea.message = v!.archive + ": " + ea.message;
}
throw e;
}
});
}
}
export abstract class NamedPerArchiveLoadable extends PerArchiveLoadable {
public static async loadByName<
I extends PerArchiveLoadable,
ID extends number,
>(
this: {
index: number;
decode(reader: Reader, id: ID): I;
},
cache0: CacheProvider | Promise<CacheProvider>,
name: string | number,
): Promise<I | undefined> {
let cache = await cache0;
let ar = await cache.getArchiveByName(this.index, name);
let version = await cache.getVersion(this.index);
let data = ar?.getFile(0)?.data;
if (data) {
return this.decode(new Reader(data, version), ar!.archive as ID);
}
}
}
export class PerFileLoadable extends Loadable {
public static async loadData(
this: { index: number; archive: number; },
cache: CacheProvider,
id: number,
): Promise<Reader | undefined> {
let archive = await cache.getArchive(this.index, this.archive);
let version = await cache.getVersion(this.index);
let data = archive?.getFile(id)?.data;
return data ? new Reader(data, version) : undefined;
}
public static async all<
I extends PerFileLoadable,
ID extends number,
>(this: {
index: number;
archive: number;
decode(reader: Reader, id: ID): I;
}, cache0: CacheProvider | Promise<CacheProvider>): Promise<I[]> {
let cache = await cache0;
let ad = await cache.getArchive(this.index, this.archive);
if (!ad) {
return [];
}
let version = await cache.getVersion(this.index);
return [...ad.getFiles().values()]
.filter(v => v.data.length > 1 && v.data[0] != 0)
.map(v => {
try {
return this.decode(new Reader(v.data, version), v.id as ID);
} catch (e) {
if (typeof e === "object" && e && "message" in e) {
let ea = e as any;
ea.message = v.id + ": " + ea.message;
}
throw e;
}
});
}
}