2023-05-23 18:53:53 +00:00
|
|
|
import type { SpacePrimitives } from "./space_primitives.ts";
|
|
|
|
import { mime } from "../deps.ts";
|
2023-08-20 15:51:00 +00:00
|
|
|
import { FileMeta } from "$sb/types.ts";
|
2023-10-03 12:16:33 +00:00
|
|
|
import { DataStore } from "../../plugos/lib/datastore.ts";
|
2023-05-23 18:53:53 +00:00
|
|
|
|
|
|
|
export type FileContent = {
|
|
|
|
name: string;
|
2023-07-02 09:25:32 +00:00
|
|
|
meta: FileMeta;
|
2023-05-23 18:53:53 +00:00
|
|
|
data: Uint8Array;
|
|
|
|
};
|
|
|
|
|
2023-10-03 12:16:33 +00:00
|
|
|
const filesMetaPrefix = ["file", "meta"];
|
|
|
|
const filesContentPrefix = ["file", "content"];
|
2023-05-23 18:53:53 +00:00
|
|
|
|
2023-10-03 12:16:33 +00:00
|
|
|
export class DataStoreSpacePrimitives implements SpacePrimitives {
|
2023-05-23 18:53:53 +00:00
|
|
|
constructor(
|
2023-10-03 12:16:33 +00:00
|
|
|
private ds: DataStore,
|
2023-05-23 18:53:53 +00:00
|
|
|
) {
|
|
|
|
}
|
|
|
|
|
2023-10-03 12:16:33 +00:00
|
|
|
async fetchFileList(): Promise<FileMeta[]> {
|
|
|
|
return (await this.ds.query<FileMeta>({ prefix: filesMetaPrefix }))
|
|
|
|
.map((kv) => kv.value);
|
2023-05-23 18:53:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
async readFile(
|
|
|
|
name: string,
|
|
|
|
): Promise<{ data: Uint8Array; meta: FileMeta }> {
|
2023-10-03 12:16:33 +00:00
|
|
|
const fileContent = await this.ds.get<FileContent>([
|
|
|
|
...filesContentPrefix,
|
|
|
|
name,
|
|
|
|
]);
|
2023-05-23 18:53:53 +00:00
|
|
|
if (!fileContent) {
|
|
|
|
throw new Error("Not found");
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
data: fileContent.data,
|
2023-07-02 09:25:32 +00:00
|
|
|
meta: fileContent.meta,
|
2023-05-23 18:53:53 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
async writeFile(
|
|
|
|
name: string,
|
|
|
|
data: Uint8Array,
|
|
|
|
_selfUpdate?: boolean,
|
2023-07-02 09:25:32 +00:00
|
|
|
suggestedMeta?: FileMeta,
|
2023-05-23 18:53:53 +00:00
|
|
|
): Promise<FileMeta> {
|
2023-07-02 09:25:32 +00:00
|
|
|
const meta: FileMeta = {
|
2023-05-23 18:53:53 +00:00
|
|
|
name,
|
2023-11-03 08:38:04 +00:00
|
|
|
created: suggestedMeta?.lastModified || Date.now(),
|
2023-07-02 09:25:32 +00:00
|
|
|
lastModified: suggestedMeta?.lastModified || Date.now(),
|
2023-05-23 18:53:53 +00:00
|
|
|
contentType: mime.getType(name) || "application/octet-stream",
|
|
|
|
size: data.byteLength,
|
2023-07-02 09:25:32 +00:00
|
|
|
perm: suggestedMeta?.perm || "rw",
|
2023-05-23 18:53:53 +00:00
|
|
|
};
|
2023-10-03 12:16:33 +00:00
|
|
|
await this.ds.batchSet<FileMeta | FileContent>([
|
|
|
|
{
|
|
|
|
key: [...filesContentPrefix, name],
|
|
|
|
value: { name, data, meta },
|
|
|
|
},
|
|
|
|
{
|
|
|
|
key: [...filesMetaPrefix, name],
|
|
|
|
value: meta,
|
|
|
|
},
|
|
|
|
]);
|
2023-07-02 09:25:32 +00:00
|
|
|
return meta;
|
2023-05-23 18:53:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
async deleteFile(name: string): Promise<void> {
|
2023-10-03 12:16:33 +00:00
|
|
|
const fileMeta = await this.ds.get<FileMeta>([
|
|
|
|
...filesMetaPrefix,
|
|
|
|
name,
|
|
|
|
]);
|
2023-05-23 18:53:53 +00:00
|
|
|
if (!fileMeta) {
|
|
|
|
throw new Error("Not found");
|
|
|
|
}
|
2023-10-03 12:16:33 +00:00
|
|
|
return this.ds.batchDelete([
|
|
|
|
[...filesMetaPrefix, name],
|
|
|
|
[...filesContentPrefix, name],
|
|
|
|
]);
|
2023-05-23 18:53:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
async getFileMeta(name: string): Promise<FileMeta> {
|
2023-10-03 12:16:33 +00:00
|
|
|
const fileMeta = await this.ds.get([...filesMetaPrefix, name]);
|
2023-05-23 18:53:53 +00:00
|
|
|
if (!fileMeta) {
|
|
|
|
throw new Error("Not found");
|
|
|
|
}
|
|
|
|
return fileMeta;
|
|
|
|
}
|
|
|
|
}
|