ionian/packages/server/src/content/file.ts
2024-10-13 23:46:17 +09:00

94 lines
2.7 KiB
TypeScript

import { createHash } from "node:crypto";
import { promises, type Stats } from "node:fs";
import path, { extname } from "node:path";
import type { DocumentBody } from "dbtype";
import { oshash } from "src/util/oshash.ts";
/**
* content file or directory referrer
*/
export interface ContentFile {
getHash(): Promise<string>;
createDocumentBody(): Promise<DocumentBody>;
readonly path: string;
readonly type: string;
}
export type ContentConstructOption = {
hash: string;
};
type ContentFileConstructor = (new (
path: string,
option?: ContentConstructOption,
) => ContentFile) & {
content_type: string;
};
export const createDefaultClass = (type: string): ContentFileConstructor => {
const cons = class implements ContentFile {
readonly path: string;
// type = type;
static content_type = type;
protected hash: string | undefined;
protected stat: Stats | undefined;
protected getStat(){
return this.stat;
}
constructor(path: string, option?: ContentConstructOption) {
this.path = path;
this.hash = option?.hash;
this.stat = undefined;
}
async createDocumentBody(): Promise<DocumentBody> {
console.log(`createDocumentBody: ${this.path}`);
const { base, dir, name } = path.parse(this.path);
const ret = {
title: name,
basepath: dir,
additional: {},
content_type: cons.content_type,
filename: base,
tags: [],
content_hash: await this.getHash(),
modified_at: await this.getMtime(),
pagenum: 0,
} as DocumentBody;
return ret;
}
get type(): string {
return cons.content_type;
}
async getHash(): Promise<string> {
if (this.hash !== undefined) return this.hash;
const hash = await oshash(this.path);
this.hash = hash.toString();
return this.hash;
}
async getMtime(): Promise<number> {
const oldStat = this.getStat();
if (oldStat !== undefined) return oldStat.mtimeMs;
const stat = await promises.stat(this.path);
this.stat = stat;
return stat.mtimeMs;
}
};
return cons;
};
const ContstructorTable: { [k: string]: ContentFileConstructor } = {};
export function registerContentReferrer(s: ContentFileConstructor) {
console.log(`registered content type: ${s.content_type}`);
ContstructorTable[s.content_type] = s;
}
export function createContentFile(type: string, path: string, option?: ContentConstructOption) {
const constructorMethod = ContstructorTable[type];
if (constructorMethod === undefined) {
console.log(`${type} are not in ${JSON.stringify(ContstructorTable)}`);
throw new Error("construction method of the content type is undefined");
}
return new constructorMethod(path, option);
}
export function getContentFileConstructor(type: string): ContentFileConstructor | undefined {
const ret = ContstructorTable[type];
return ret;
}