feat: fs object metadata cache and validation

This commit is contained in:
Huskydog9988
2025-05-14 17:19:39 -04:00
parent b551788c4c
commit 2cc3f1329c
2 changed files with 28 additions and 9 deletions

View File

@ -1,5 +1,5 @@
import type { ObjectMetadata, ObjectReference, Source } from "./objectHandler"; import type { ObjectMetadata, ObjectReference, Source } from "./objectHandler";
import { ObjectBackend } from "./objectHandler"; import { ObjectBackend, objectMetadata } from "./objectHandler";
import fs from "fs"; import fs from "fs";
import path from "path"; import path from "path";
@ -8,12 +8,15 @@ import { createHash } from "crypto";
import prisma from "../db/database"; import prisma from "../db/database";
import cacheHandler from "../cache"; import cacheHandler from "../cache";
import { systemConfig } from "../config/sys-conf"; import { systemConfig } from "../config/sys-conf";
import { type } from "arktype";
export class FsObjectBackend extends ObjectBackend { export class FsObjectBackend extends ObjectBackend {
private baseObjectPath: string; private baseObjectPath: string;
private baseMetadataPath: string; private baseMetadataPath: string;
private hashStore = new FsHashStore(); private hashStore = new FsHashStore();
private metadataCache =
cacheHandler.createCache<ObjectMetadata>("ObjectMetadata");
constructor() { constructor() {
super(); super();
@ -102,17 +105,27 @@ export class FsObjectBackend extends ObjectBackend {
const metadataPath = path.join(this.baseMetadataPath, `${id}.json`); const metadataPath = path.join(this.baseMetadataPath, `${id}.json`);
if (!fs.existsSync(metadataPath)) return true; if (!fs.existsSync(metadataPath)) return true;
fs.rmSync(metadataPath); fs.rmSync(metadataPath);
// remove item from cache // remove item from caches
await this.metadataCache.remove(id);
await this.hashStore.delete(id); await this.hashStore.delete(id);
return true; return true;
} }
async fetchMetadata( async fetchMetadata(
id: ObjectReference, id: ObjectReference,
): Promise<ObjectMetadata | undefined> { ): Promise<ObjectMetadata | undefined> {
const cacheResult = await this.metadataCache.get(id);
if (cacheResult !== null) return cacheResult;
const metadataPath = path.join(this.baseMetadataPath, `${id}.json`); const metadataPath = path.join(this.baseMetadataPath, `${id}.json`);
if (!fs.existsSync(metadataPath)) return undefined; if (!fs.existsSync(metadataPath)) return undefined;
const metadata = JSON.parse(fs.readFileSync(metadataPath, "utf-8")); const metadataRaw = JSON.parse(fs.readFileSync(metadataPath, "utf-8"));
return metadata as ObjectMetadata; const metadata = objectMetadata(metadataRaw);
if (metadata instanceof type.errors) {
console.error("FsObjectBackend#fetchMetadata", metadata.summary);
return undefined;
}
await this.metadataCache.set(id, metadata);
return metadata;
} }
async writeMetadata( async writeMetadata(
id: ObjectReference, id: ObjectReference,
@ -121,6 +134,7 @@ export class FsObjectBackend extends ObjectBackend {
const metadataPath = path.join(this.baseMetadataPath, `${id}.json`); const metadataPath = path.join(this.baseMetadataPath, `${id}.json`);
if (!fs.existsSync(metadataPath)) return false; if (!fs.existsSync(metadataPath)) return false;
fs.writeFileSync(metadataPath, JSON.stringify(metadata)); fs.writeFileSync(metadataPath, JSON.stringify(metadata));
await this.metadataCache.set(id, metadata);
return true; return true;
} }
async fetchHash(id: ObjectReference): Promise<string | undefined> { async fetchHash(id: ObjectReference): Promise<string | undefined> {

View File

@ -14,17 +14,22 @@
* anotherUserId:write * anotherUserId:write
*/ */
import { type } from "arktype";
import { parse as getMimeTypeBuffer } from "file-type-mime"; import { parse as getMimeTypeBuffer } from "file-type-mime";
import type { Writable } from "stream"; import type { Writable } from "stream";
import { Readable } from "stream"; import { Readable } from "stream";
import { getMimeType as getMimeTypeStream } from "stream-mime-type"; import { getMimeType as getMimeTypeStream } from "stream-mime-type";
export type ObjectReference = string; export type ObjectReference = string;
export type ObjectMetadata = {
mime: string; export const objectMetadata = type({
permissions: string[]; mime: "string",
userMetadata: { [key: string]: string }; permissions: "string[]",
}; userMetadata: {
"[string]": "string",
},
});
export type ObjectMetadata = typeof objectMetadata.infer;
export enum ObjectPermission { export enum ObjectPermission {
Read = "read", Read = "read",