126 lines
3.9 KiB
TypeScript
126 lines
3.9 KiB
TypeScript
import { basename, dirname } from "node:path";
|
|
import { createContentFile } from "../content/mod.ts";
|
|
import type { Document, DocumentAccessor } from "../model/mod.ts";
|
|
import { ContentList } from "./content_list.ts";
|
|
import type { IDiffWatcher } from "./watcher.ts";
|
|
|
|
// refactoring needed.
|
|
export class ContentDiffHandler {
|
|
/** content file list waiting to add */
|
|
waiting_list: ContentList;
|
|
/** deleted contents */
|
|
tombstone: Map<string, Document>; // hash, contentfile
|
|
doc_cntr: DocumentAccessor;
|
|
/** content type of handle */
|
|
content_type: string;
|
|
constructor(cntr: DocumentAccessor, content_type: string) {
|
|
this.waiting_list = new ContentList();
|
|
this.tombstone = new Map<string, Document>();
|
|
this.doc_cntr = cntr;
|
|
this.content_type = content_type;
|
|
}
|
|
async setup() {
|
|
const deleted = await this.doc_cntr.findDeleted(this.content_type);
|
|
for (const it of deleted) {
|
|
if (it.deleted_at === null) {
|
|
// it should not be happened. but when it happens, ignore it.
|
|
console.error("It should not happen");
|
|
continue;
|
|
}
|
|
this.tombstone.set(it.content_hash, it);
|
|
}
|
|
}
|
|
register(diff: IDiffWatcher) {
|
|
diff
|
|
.on("create", (path) => this.OnCreated(path))
|
|
.on("delete", (path) => this.OnDeleted(path))
|
|
.on("change", (prev, cur) => this.OnChanged(prev, cur));
|
|
}
|
|
private async OnDeleted(cpath: string) {
|
|
const basepath = dirname(cpath);
|
|
const filename = basename(cpath);
|
|
console.log("deleted ", cpath);
|
|
// if it wait to add, delete it from waiting list.
|
|
if (this.waiting_list.hasByPath(cpath)) {
|
|
this.waiting_list.deleteByPath(cpath);
|
|
return;
|
|
}
|
|
const dbc = await this.doc_cntr.findByPath(basepath, filename);
|
|
// when there is no related content in db, ignore.
|
|
if (dbc.length === 0) {
|
|
console.log("its not in waiting_list and db!!!: ", cpath);
|
|
return;
|
|
}
|
|
const content_hash = dbc[0].content_hash;
|
|
// When a path is changed, it takes into account when the
|
|
// creation event occurs first and the deletion occurs, not
|
|
// the change event.
|
|
const cf = this.waiting_list.getByHash(content_hash);
|
|
if (cf) {
|
|
// if a path is changed, update the changed path.
|
|
console.log("update path from", cpath, "to", cf.path);
|
|
const newFilename = basename(cf.path);
|
|
const newBasepath = dirname(cf.path);
|
|
this.waiting_list.deleteByHash(content_hash);
|
|
await this.doc_cntr.update({
|
|
id: dbc[0].id,
|
|
deleted_at: null,
|
|
filename: newFilename,
|
|
basepath: newBasepath,
|
|
});
|
|
return;
|
|
}
|
|
// invalidate db and add it to tombstone.
|
|
await this.doc_cntr.update({
|
|
id: dbc[0].id,
|
|
deleted_at: Date.now(),
|
|
});
|
|
this.tombstone.set(content_hash, dbc[0]);
|
|
}
|
|
private async OnCreated(cpath: string) {
|
|
const basepath = dirname(cpath);
|
|
const filename = basename(cpath);
|
|
console.log("createContentFile", cpath);
|
|
const content = createContentFile(this.content_type, cpath);
|
|
const hash = await content.getHash();
|
|
const c = this.tombstone.get(hash);
|
|
if (c !== undefined) {
|
|
await this.doc_cntr.update({
|
|
id: c.id,
|
|
deleted_at: null,
|
|
filename: filename,
|
|
basepath: basepath,
|
|
});
|
|
}
|
|
if (this.waiting_list.hasByHash(hash)) {
|
|
console.log("Hash Conflict!!!");
|
|
}
|
|
this.waiting_list.set(content);
|
|
}
|
|
private async OnChanged(prev_path: string, cur_path: string) {
|
|
const prev_basepath = dirname(prev_path);
|
|
const prev_filename = basename(prev_path);
|
|
const cur_basepath = dirname(cur_path);
|
|
const cur_filename = basename(cur_path);
|
|
console.log("modify", cur_path, "from", prev_path);
|
|
const c = this.waiting_list.getByPath(prev_path);
|
|
if (c !== undefined) {
|
|
await this.waiting_list.delete(c);
|
|
const content = createContentFile(this.content_type, cur_path);
|
|
await this.waiting_list.set(content);
|
|
return;
|
|
}
|
|
const doc = await this.doc_cntr.findByPath(prev_basepath, prev_filename);
|
|
|
|
if (doc.length === 0) {
|
|
await this.OnCreated(cur_path);
|
|
return;
|
|
}
|
|
|
|
await this.doc_cntr.update({
|
|
...doc[0],
|
|
basepath: cur_basepath,
|
|
filename: cur_filename,
|
|
});
|
|
}
|
|
}
|