feat: sync progress

This commit is contained in:
Michal Szczepanski 2023-09-19 02:01:52 +02:00
parent 2930d99d80
commit 3a649bce51
13 changed files with 96 additions and 55 deletions

@ -24,7 +24,7 @@
], ],
"rules": { "rules": {
"max-len": ["error", {"code": 120, "ignoreComments": true, "ignoreTemplateLiterals": true}], "max-len": ["error", {"code": 120, "ignoreComments": true, "ignoreTemplateLiterals": true}],
"no-console": "error", "no-console": "warn",
"semi": [ "error", "always" ], "semi": [ "error", "always" ],
"@typescript-eslint/no-unsafe-member-access": "off", "@typescript-eslint/no-unsafe-member-access": "off",
"@typescript-eslint/no-unsafe-assignment": "off", "@typescript-eslint/no-unsafe-assignment": "off",
@ -36,7 +36,7 @@
"@typescript-eslint/no-unsafe-return": "off", "@typescript-eslint/no-unsafe-return": "off",
"@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-explicit-any": "off",
"sort-imports": [ "sort-imports": [
"error", "off",
{ {
"ignoreCase": false, "ignoreCase": false,
"ignoreDeclarationSort": false, "ignoreDeclarationSort": false,

@ -28,7 +28,7 @@ export interface ObjAddRequest {
} }
export class ApiStoreSyncObjCommand extends ApiCallBase implements ICommand<Promise<void>> { export class ApiStoreSyncObjCommand extends ApiCallBase implements ICommand<Promise<void>> {
constructor(private obj: ObjDto, private initialHash: string) { constructor(private obj: ObjDto, private hash: string, private tx: string) {
super(); super();
} }
async execute(): Promise<void> { async execute(): Promise<void> {
@ -42,7 +42,7 @@ export class ApiStoreSyncObjCommand extends ApiCallBase implements ICommand<Prom
body: JSON.stringify({ body: JSON.stringify({
type: this.obj.type, type: this.obj.type,
localId: this.obj.id, localId: this.obj.id,
initialHash: this.initialHash hash: this.hash
}) })
}, },
this.refreshParams() this.refreshParams()

@ -32,6 +32,7 @@ import { SyncSetProgressCommand } from '../progress/sync-set-progress.command';
import { SyncSnapshotCommand } from './sync-snapshot.command'; import { SyncSnapshotCommand } from './sync-snapshot.command';
import { fnConsoleLog } from '../../../../common/fn/fn-console'; import { fnConsoleLog } from '../../../../common/fn/fn-console';
import { fnSleep } from '../../../../common/fn/fn-sleep'; import { fnSleep } from '../../../../common/fn/fn-sleep';
import { BeginTxResponse } from '../../api/store/api-store.model';
export enum SyncObjectStatus { export enum SyncObjectStatus {
TX_LOCKED, TX_LOCKED,
@ -48,7 +49,7 @@ export interface SyncIndex extends ObjDateIndex {
} }
export class SyncIndexCommand implements ICommand<Promise<SyncObjectStatus>> { export class SyncIndexCommand implements ICommand<Promise<SyncObjectStatus>> {
constructor(private progress: SyncProgress, private index?: ObjDateIndex) {} constructor(private progress: SyncProgress, private tx: BeginTxResponse, private index?: ObjDateIndex) {}
async execute(): Promise<SyncObjectStatus> { async execute(): Promise<SyncObjectStatus> {
if (!this.index) { if (!this.index) {
@ -64,8 +65,7 @@ export class SyncIndexCommand implements ICommand<Promise<SyncObjectStatus>> {
case ObjTypeDto.PageSnapshot: case ObjTypeDto.PageSnapshot:
case ObjTypeDto.PageElementSnapshot: { case ObjTypeDto.PageElementSnapshot: {
fnConsoleLog('SyncSnapshotCommand', obj.type, obj.id, 'index', this.index, 'obj', obj); fnConsoleLog('SyncSnapshotCommand', obj.type, obj.id, 'index', this.index, 'obj', obj);
await new SyncSnapshotCommand(obj as ObjDto<ObjPageDto>, this.progress, this.index).execute(); return await new SyncSnapshotCommand(obj as ObjDto<ObjPageDto>, this.progress).execute();
break;
} }
case ObjTypeDto.PageElementPin: { case ObjTypeDto.PageElementPin: {
fnConsoleLog('SyncPinCommand', obj.type, obj.id, 'index', this.index, 'obj', obj); fnConsoleLog('SyncPinCommand', obj.type, obj.id, 'index', this.index, 'obj', obj);

@ -28,6 +28,6 @@ export class SyncNoteCommand implements ICommand<Promise<void>> {
async execute(): Promise<void> { async execute(): Promise<void> {
fnConsoleLog('SyncNoteCommand'); fnConsoleLog('SyncNoteCommand');
const data = this.obj.data; const data = this.obj.data;
await new SyncObjectCommand(this.obj, data.hash, this.progress, this.index).execute(); await new SyncObjectCommand(this.obj, data.hash, this.progress).execute();
} }
} }

@ -19,24 +19,14 @@ import { ObjDateIndex } from '../../../../common/command/obj/index/obj-update-in
import { ObjDto } from '../../../../common/model/obj/obj.dto'; import { ObjDto } from '../../../../common/model/obj/obj.dto';
import { SyncProgress } from '../sync.model'; import { SyncProgress } from '../sync.model';
import { fnConsoleLog } from '../../../../common/fn/fn-console'; import { fnConsoleLog } from '../../../../common/fn/fn-console';
import { ApiStoreSyncObjCommand } from '../../api/store/api-store-sync-obj.command';
import { BeginTxResponse } from '../../api/store/api-store.model';
export class SyncObjectCommand implements ICommand<Promise<void>> { export class SyncObjectCommand implements ICommand<Promise<void>> {
constructor( constructor(private obj: ObjDto, private hash: string, private tx: BeginTxResponse) {}
private obj: ObjDto,
private initialHash: string,
private progress: SyncProgress,
private index: ObjDateIndex
) {}
// eslint-disable-next-line @typescript-eslint/require-await // eslint-disable-next-line @typescript-eslint/require-await
async execute(): Promise<void> { async execute(): Promise<void> {
fnConsoleLog( fnConsoleLog('SyncObjectDataCommand');
'SyncObjectDataCommand', await new ApiStoreSyncObjCommand(this.obj, this.hash, this.tx.tx).execute();
this.obj.id,
this.obj.type,
this.obj.createdAt,
this.obj.updatedAt,
this.obj.version,
this.initialHash
);
} }
} }

@ -27,6 +27,6 @@ export class SyncPageNoteCommand implements ICommand<Promise<void>> {
async execute(): Promise<void> { async execute(): Promise<void> {
fnConsoleLog('SyncPageNoteCommand'); fnConsoleLog('SyncPageNoteCommand');
const data = this.obj.data; const data = this.obj.data;
await new SyncObjectCommand(this.obj, data.hash, this.progress, this.index).execute(); await new SyncObjectCommand(this.obj, data.hash, this.progress).execute();
} }
} }

@ -27,6 +27,6 @@ export class SyncPdfCommand implements ICommand<Promise<void>> {
async execute(): Promise<void> { async execute(): Promise<void> {
fnConsoleLog('SyncPdfCommand'); fnConsoleLog('SyncPdfCommand');
const data = this.obj.data; const data = this.obj.data;
await new SyncObjectCommand(this.obj, data.hash, this.progress, this.index).execute(); await new SyncObjectCommand(this.obj, data.hash, this.progress).execute();
} }
} }

@ -21,12 +21,13 @@ import { ObjPinDto } from '../../../../common/model/obj/obj-pin.dto';
import { SyncObjectCommand } from './sync-object.command'; import { SyncObjectCommand } from './sync-object.command';
import { SyncProgress } from '../sync.model'; import { SyncProgress } from '../sync.model';
import { fnConsoleLog } from '../../../../common/fn/fn-console'; import { fnConsoleLog } from '../../../../common/fn/fn-console';
import { BeginTxResponse } from '../../api/store/api-store.model';
export class SyncPinCommand implements ICommand<Promise<void>> { export class SyncPinCommand implements ICommand<Promise<void>> {
constructor(private obj: ObjDto<ObjPinDto>, private progress: SyncProgress, private index: ObjDateIndex) {} constructor(private obj: ObjDto<ObjPinDto>, private progress: SyncProgress, private tx: BeginTxResponse) {}
async execute(): Promise<void> { async execute(): Promise<void> {
fnConsoleLog('SyncPinCommand'); fnConsoleLog('SyncPinCommand');
const data = this.obj.data; const data = this.obj.data;
await new SyncObjectCommand(this.obj, data.data.hash, this.progress, this.index).execute(); await new SyncObjectCommand(this.obj, data.data.hash, this.progress).execute();
} }
} }

@ -16,28 +16,28 @@
*/ */
import { SegmentCss, SegmentImg, SegmentPage, SegmentType } from '@pinmenote/page-compute'; import { SegmentCss, SegmentImg, SegmentPage, SegmentType } from '@pinmenote/page-compute';
import { ICommand } from '../../../../common/model/shared/common.dto'; import { ICommand } from '../../../../common/model/shared/common.dto';
import { ObjDateIndex } from '../../../../common/command/obj/index/obj-update-index-add.command';
import { ObjDto } from '../../../../common/model/obj/obj.dto'; import { ObjDto } from '../../../../common/model/obj/obj.dto';
import { ObjPageDto } from '../../../../common/model/obj/obj-page.dto'; import { ObjPageDto } from '../../../../common/model/obj/obj-page.dto';
import { PageSegmentGetCommand } from '../../../../common/command/snapshot/segment/page-segment-get.command'; import { PageSegmentGetCommand } from '../../../../common/command/snapshot/segment/page-segment-get.command';
import { SyncObjectCommand } from './sync-object.command'; import { SyncObjectCommand } from './sync-object.command';
import { SyncObjectStatus } from './sync-index.command';
import { SyncProgress } from '../sync.model'; import { SyncProgress } from '../sync.model';
import { fnConsoleLog } from '../../../../common/fn/fn-console'; import { fnConsoleLog } from '../../../../common/fn/fn-console';
export class SyncSnapshotCommand implements ICommand<Promise<void>> { export class SyncSnapshotCommand implements ICommand<Promise<SyncObjectStatus>> {
constructor(private obj: ObjDto<ObjPageDto>, private progress: SyncProgress, private index: ObjDateIndex) {} constructor(private obj: ObjDto<ObjPageDto>, private progress: SyncProgress) {}
async execute(): Promise<void> { async execute(): Promise<SyncObjectStatus> {
const snapshot = this.obj.data.snapshot; const snapshot = this.obj.data.snapshot;
// fnConsoleLog('SyncSnapshotCommand->comments', this.obj.data.comments); if (!snapshot.segmentHash) {
// fnConsoleLog('SyncSnapshotCommand->snapshot', this.obj.id, 'index', this.index, 'obj', this.obj); console.log('PROBLEM !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!', snapshot);
if (!snapshot.segmentHash) return; return SyncObjectStatus.SERVER_ERROR;
}
await new SyncObjectCommand(this.obj, snapshot.segmentHash, this.progress, this.index).execute(); await new SyncObjectCommand(this.obj, snapshot.segmentHash, this.progress).execute();
return SyncObjectStatus.SERVER_ERROR;
await this.syncSegment(snapshot.segmentHash); // await this.syncSegment(snapshot.segmentHash);
} }
private async syncSegment(hash: string, nested = false) { private async syncSegment(hash: string) {
const segment = await new PageSegmentGetCommand(hash).execute(); const segment = await new PageSegmentGetCommand(hash).execute();
if (!segment) return; if (!segment) return;
switch (segment.type) { switch (segment.type) {
@ -64,15 +64,11 @@ export class SyncSnapshotCommand implements ICommand<Promise<void>> {
} }
case SegmentType.IFRAME: { case SegmentType.IFRAME: {
const content = segment.content as SegmentPage; const content = segment.content as SegmentPage;
const matched = content.html.html.matchAll(/(data-pin-hash=")([a-z\d]+")/g);
const a = Array.from(matched);
// if (content.assets.length > 0) fnConsoleLog('IFRAME', a, content);
if (a.length > 0) fnConsoleLog('IFRAME', nested, content, 'MATCHED', a);
for (const css of content.css) { for (const css of content.css) {
await this.syncSegment(css); await this.syncSegment(css);
} }
for (const asset of content.assets) { for (const asset of content.assets) {
await this.syncSegment(asset, true); await this.syncSegment(asset);
} }
break; break;
} }

@ -19,6 +19,10 @@ import { ICommand } from '../../../../common/model/shared/common.dto';
import { ObjectStoreKeys } from '../../../../common/keys/object.store.keys'; import { ObjectStoreKeys } from '../../../../common/keys/object.store.keys';
import { SyncGetProgressCommand } from './sync-get-progress.command'; import { SyncGetProgressCommand } from './sync-get-progress.command';
import { SyncProgress } from '../sync.model'; import { SyncProgress } from '../sync.model';
import { ObjDto } from '../../../../common/model/obj/obj.dto';
import { fnDateKeyFormat } from '../../../../common/fn/fn-date-format';
import { ObjDateIndex } from '../../../../common/command/obj/index/obj-update-index-add.command';
import { fnConsoleLog } from '../../../../common/fn/fn-console';
export class SyncResetProgressCommand implements ICommand<Promise<void>> { export class SyncResetProgressCommand implements ICommand<Promise<void>> {
async execute(): Promise<void> { async execute(): Promise<void> {
@ -28,5 +32,56 @@ export class SyncResetProgressCommand implements ICommand<Promise<void>> {
timestamp: obj.createdAt, timestamp: obj.createdAt,
id: obj.id id: obj.id
}); });
await this.resetObjects();
}
async resetObjects(): Promise<void> {
let listId = await BrowserStorage.get<number>(ObjectStoreKeys.OBJECT_LIST_ID);
const a = Date.now();
console.log('SyncResetProgressCommand->start !!!!', listId);
const toSortSet: Set<string> = new Set<string>();
while (listId > 0) {
const list = await BrowserStorage.get<number[]>(`${ObjectStoreKeys.OBJECT_LIST}:${listId}`);
for (const id of list) {
const obj = await BrowserStorage.get<ObjDto>(`${ObjectStoreKeys.OBJECT_ID}:${id}`);
const yearMonth = fnDateKeyFormat(new Date(obj.updatedAt));
toSortSet.add(yearMonth);
const updateList = await this.getList(yearMonth);
if (updateList.findIndex((o) => o.id === obj.id) > 0) continue;
updateList.push({ id: obj.id, dt: obj.updatedAt });
await this.setList(yearMonth, updateList);
}
listId -= 1;
}
// sort objects inside
for (const yearMonth of toSortSet) {
let list = await this.getList(yearMonth);
list = list.sort((a, b) => {
if (a.dt > b.dt) return 1;
if (a.dt < b.dt) return -1;
if (a.id > b.id) return 1;
if (a.id < b.id) return -1;
return 0;
});
}
fnConsoleLog('SyncResetProgressCommand->complete in ', Date.now() - a);
}
private async setList(yearMonth: string, list: ObjDateIndex[]): Promise<void> {
const updateListKey = `${ObjectStoreKeys.UPDATED_DT}:${yearMonth}`;
await BrowserStorage.set(updateListKey, list);
}
private async getList(yearMonth: string): Promise<ObjDateIndex[]> {
const updateListKey = `${ObjectStoreKeys.UPDATED_DT}:${yearMonth}`;
const updateList = await BrowserStorage.get<ObjDateIndex[] | undefined>(updateListKey);
if (!updateList) return [];
return updateList;
} }
} }

@ -54,17 +54,19 @@ export class SyncMonthCommand implements ICommand<Promise<SyncIndex>> {
const begin = await SyncTxHelper.begin(); const begin = await SyncTxHelper.begin();
if (!begin) return { ...index, status: SyncObjectStatus.TX_LOCKED }; if (!begin) return { ...index, status: SyncObjectStatus.TX_LOCKED };
const newIndexList = [];
for (let i = nextObjectIndex; i < indexList.length; i++) { for (let i = nextObjectIndex; i < indexList.length; i++) {
index = { ...indexList[i], status: SyncObjectStatus.OK }; index = { ...indexList[i], status: SyncObjectStatus.OK };
const status = await new SyncIndexCommand(this.progress, index).execute(); const status = await new SyncIndexCommand(this.progress, begin, index).execute();
if (![SyncObjectStatus.INDEX_NOT_EXISTS, SyncObjectStatus.OBJECT_NOT_EXISTS].includes(status)) {
newIndexList.push(index);
}
}
await SyncTxHelper.setList(indexListKey, newIndexList); if ([SyncObjectStatus.SERVER_ERROR].includes(status)) {
index = { ...index, status: SyncObjectStatus.SERVER_ERROR };
await SyncTxHelper.commit();
return index;
}
if (![SyncObjectStatus.INDEX_NOT_EXISTS, SyncObjectStatus.OBJECT_NOT_EXISTS].includes(status)) {
console.log('PROBLEM !!!!!!!!!!!!!!!!!!!!!!!!', status);
}
}
await SyncTxHelper.commit(); await SyncTxHelper.commit();
return index; return index;

@ -19,6 +19,7 @@ import { ICommand } from '../../../common/model/shared/common.dto';
import { SyncGetProgressCommand } from './progress/sync-get-progress.command'; import { SyncGetProgressCommand } from './progress/sync-get-progress.command';
import { SyncMonthCommand } from './sync-month.command'; import { SyncMonthCommand } from './sync-month.command';
import { SyncProgress } from './sync.model'; import { SyncProgress } from './sync.model';
import { SyncResetProgressCommand } from './progress/sync-reset-progress.command';
import { SyncSetProgressCommand } from './progress/sync-set-progress.command'; import { SyncSetProgressCommand } from './progress/sync-set-progress.command';
import { SyncTxHelper } from './sync-tx.helper'; import { SyncTxHelper } from './sync-tx.helper';
import { fnConsoleLog } from '../../../common/fn/fn-console'; import { fnConsoleLog } from '../../../common/fn/fn-console';
@ -31,7 +32,7 @@ export class SyncServerCommand implements ICommand<Promise<void>> {
if (SyncServerCommand.isInSync) return; if (SyncServerCommand.isInSync) return;
if (!(await SyncTxHelper.shouldSync())) return; if (!(await SyncTxHelper.shouldSync())) return;
try { try {
// await new SyncResetProgressCommand().execute(); await new SyncResetProgressCommand().execute();
SyncServerCommand.isInSync = true; SyncServerCommand.isInSync = true;

@ -66,8 +66,4 @@ export class SyncTxHelper {
const value = await BrowserStorage.get<ObjDateIndex[] | undefined>(key); const value = await BrowserStorage.get<ObjDateIndex[] | undefined>(key);
return value || []; return value || [];
} }
static async setList(key: string, value: ObjDateIndex[]) {
await BrowserStorage.set(key, value);
}
} }