fix: onchange bug

This commit is contained in:
monoid 2022-07-06 16:43:57 +09:00
parent b510c7419f
commit 6dd1d4d83a
3 changed files with 67 additions and 44 deletions

View File

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

View File

@ -39,12 +39,15 @@ export class ContentList{
async deleteByPath(p:string){ async deleteByPath(p:string){
const o = this.getByPath(p); const o = this.getByPath(p);
if(o === undefined) return false; if(o === undefined) return false;
return this.delete(o); return await this.delete(o);
} }
async deleteByHash(s:string){ deleteByHash(s:string){
const o = this.getByHash(s); const o = this.getByHash(s);
if(o === undefined) return false; if(o === undefined) return false;
return this.delete(o); let r = true;
r = this.cl.delete(o.path) && r;
r = this.hl.delete(s) && r;
return r;
} }
clear(){ clear(){
this.cl.clear(); this.cl.clear();

View File

@ -73,6 +73,7 @@ const ContentQueryHandler = (controller : DocumentAccessor) => async (ctx: Conte
} }
const UpdateContentHandler = (controller : DocumentAccessor) => async (ctx: Context, next: Next) => { const UpdateContentHandler = (controller : DocumentAccessor) => async (ctx: Context, next: Next) => {
const num = Number.parseInt(ctx.params['num']); const num = Number.parseInt(ctx.params['num']);
if(ctx.request.type !== 'json'){ if(ctx.request.type !== 'json'){
return sendError(400,"update fail. invalid document type: it is not json."); return sendError(400,"update fail. invalid document type: it is not json.");
} }