2023-08-20 15:51:00 +00:00
|
|
|
/// <reference lib="deno.unstable" />
|
|
|
|
|
|
|
|
import { FileMeta } from "$sb/types.ts";
|
|
|
|
import type { SpacePrimitives } from "./space_primitives.ts";
|
|
|
|
import { mime } from "https://deno.land/x/mimetypes@v1.0.0/mod.ts";
|
|
|
|
|
|
|
|
export class DenoKVSpacePrimitives implements SpacePrimitives {
|
|
|
|
private kv!: Deno.Kv;
|
|
|
|
private dataAttribute = "file";
|
|
|
|
private metaAttribute = "meta";
|
|
|
|
|
|
|
|
async init(path?: string) {
|
|
|
|
this.kv = await Deno.openKv(path);
|
|
|
|
}
|
|
|
|
|
|
|
|
close() {
|
|
|
|
this.kv.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
async fetchFileList(): Promise<FileMeta[]> {
|
|
|
|
const results: FileMeta[] = [];
|
|
|
|
for await (
|
|
|
|
const result of this.kv.list({
|
|
|
|
prefix: [this.metaAttribute],
|
|
|
|
})
|
|
|
|
) {
|
|
|
|
results.push(result.value as FileMeta);
|
|
|
|
}
|
|
|
|
return results;
|
|
|
|
}
|
|
|
|
async readFile(name: string): Promise<{ data: Uint8Array; meta: FileMeta }> {
|
|
|
|
const [meta, data] = await this.kv.getMany([[this.metaAttribute, name], [
|
|
|
|
this.dataAttribute,
|
|
|
|
name,
|
|
|
|
]]);
|
|
|
|
if (!meta.value) {
|
|
|
|
throw new Error("Not found");
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
data: data.value as Uint8Array,
|
|
|
|
meta: meta.value as FileMeta,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
async getFileMeta(name: string): Promise<FileMeta> {
|
|
|
|
const result = await this.kv.get([this.metaAttribute, name]);
|
|
|
|
if (result.value) {
|
|
|
|
return result.value as FileMeta;
|
|
|
|
} else {
|
|
|
|
throw new Error("Not found");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
async writeFile(
|
|
|
|
name: string,
|
|
|
|
data: Uint8Array,
|
|
|
|
_selfUpdate?: boolean | undefined,
|
|
|
|
suggestedMeta?: FileMeta | undefined,
|
|
|
|
): Promise<FileMeta> {
|
|
|
|
const meta: FileMeta = {
|
|
|
|
name,
|
2023-11-03 08:38:04 +00:00
|
|
|
created: suggestedMeta?.created || Date.now(),
|
2023-08-20 15:51:00 +00:00
|
|
|
lastModified: suggestedMeta?.lastModified || Date.now(),
|
|
|
|
contentType: mime.getType(name) || "application/octet-stream",
|
|
|
|
size: data.byteLength,
|
|
|
|
perm: suggestedMeta?.perm || "rw",
|
|
|
|
};
|
|
|
|
const res = await this.kv.atomic()
|
|
|
|
.set([this.dataAttribute, name], data)
|
|
|
|
.set([this.metaAttribute, name], meta)
|
|
|
|
.commit();
|
|
|
|
if (!res.ok) {
|
|
|
|
throw res;
|
|
|
|
}
|
|
|
|
return meta;
|
|
|
|
}
|
|
|
|
async deleteFile(name: string): Promise<void> {
|
|
|
|
const res = await this.kv.atomic()
|
|
|
|
.delete([this.dataAttribute, name])
|
|
|
|
.delete([this.metaAttribute, name])
|
|
|
|
.commit();
|
|
|
|
if (!res.ok) {
|
|
|
|
throw res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|