fix: sync image - add mimeType, add manual sync in options-ui

This commit is contained in:
Michal Szczepanski 2023-09-25 23:41:14 +02:00
parent 2863a878e6
commit 50b27e731e
30 changed files with 392 additions and 190 deletions

@ -17,8 +17,6 @@
import { BrowserStorage } from '@pinmenote/browser-api';
import { ICommand } from '../../../model/shared/common.dto';
import { ObjectStoreKeys } from '../../../keys/object.store.keys';
import { SegmentData } from '@pinmenote/page-compute';
import { fnConsoleLog } from '../../../fn/fn-console';
export class PageSegmentAddRefCommand implements ICommand<Promise<boolean>> {
constructor(private hash: string) {}

@ -33,7 +33,7 @@ export class PageSegmentAddCommand<T> implements ICommand<Promise<void>> {
const key = `${ObjectStoreKeys.CONTENT_HASH_COUNT}:${this.content.hash}`;
let count = (await BrowserStorage.get<number | undefined>(key)) || 0;
count++;
fnConsoleLog('PageSegmentAddCommand->incrementCount', count);
// fnConsoleLog('PageSegmentAddCommand->incrementCount', count);
await BrowserStorage.set(key, count);
}
}

@ -56,6 +56,8 @@ export enum BusMessageType {
CONTENT_TAKE_SCREENSHOT = 'content.take.screenshot',
CONTENT_FETCH_PDF = 'content.fetch.pdf',
CONTENT_THEME = 'content.theme',
// Iframe
OPTIONS_SYNC_OUTGOING_OBJECT = 'options.sync.outgoing.object',
// Iframe content script
IFRAME_INDEX = 'iframe.index',
IFRAME_INDEX_REGISTER = 'iframe.index.register',

@ -48,9 +48,11 @@ export const AccountDetailsComponent: FunctionComponent<Props> = (props) => {
if (PopupTokenStore.token) {
setTokenData(jwtDecode<TokenDataDto>(PopupTokenStore.token.access_token));
quotaKey = dispatcher.addListener<ServerQuotaResponse>(
quotaKey = dispatcher.addListener<ServerQuotaResponse | ServerErrorDto>(
BusMessageType.POPUP_SERVER_QUOTA,
(event, key, value) => {
// TODO fix server error handling
if ('code' in value) return;
LogManager.log(`${event} - ${JSON.stringify(value)}`);
setServerQuota(value);
},

@ -0,0 +1,100 @@
/*
* This file is part of the pinmenote-extension distribution (https://github.com/pinmenote/pinmenote-extension).
* Copyright (c) 2023 Michal Szczepanski.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, { FunctionComponent, useEffect, useRef } from 'react';
import { BrowserApi } from '@pinmenote/browser-api';
import CircularProgress from '@mui/material/CircularProgress';
import IconButton from '@mui/material/IconButton';
import DownloadIcon from '@mui/icons-material/Download';
import ClearIcon from '@mui/icons-material/Clear';
import { ObjDto } from '../../../common/model/obj/obj.dto';
import { ObjPageDto } from '../../../common/model/obj/obj-page.dto';
import { PageSnapshotDto } from '../../../common/model/obj/page-snapshot.dto';
import dayjs from 'dayjs';
import { DATE_YEAR_SECOND } from '../../../common/date-format.constraints';
import CloudSyncIcon from '@mui/icons-material/CloudSync';
import { BusMessageType } from '../../../common/model/bus.model';
import { TinyDispatcher } from '@pinmenote/tiny-dispatcher';
import { SyncObjectStatus } from '../../../common/model/sync.model';
import { fnConsoleLog } from '../../../common/fn/fn-console';
export interface Props {
obj?: ObjDto<ObjPageDto>;
isLoading: boolean;
handleDownload: () => void;
handleClose: () => void;
}
export const HtmlPreviewHeaderComponent: FunctionComponent<Props> = (props) => {
const titleRef = useRef<HTMLHeadingElement>(null);
const urlRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!titleRef.current) return;
if (!urlRef.current) return;
if (props.obj) renderHeader(props.obj);
const dispatcher = TinyDispatcher.getInstance();
const syncKey = dispatcher.addListener<SyncObjectStatus>(
BusMessageType.OPTIONS_SYNC_OUTGOING_OBJECT,
(event, key, value) => {
fnConsoleLog('HtmlPreviewHeaderComponent->SYNC !!!!!!!', event, key, value);
},
true
);
return () => {
dispatcher.removeListener(BusMessageType.OPTIONS_SYNC_OUTGOING_OBJECT, syncKey);
};
}, [props]);
const renderHeader = (obj: ObjDto<ObjPageDto>): void => {
const snapshot: PageSnapshotDto = obj.data.snapshot;
if (titleRef.current) {
titleRef.current.innerHTML = snapshot.info.title;
}
if (urlRef.current) {
urlRef.current.innerHTML = `
<a href="${snapshot.info.url.href}" target="_blank" style="word-break: break-all">
${snapshot.info.url.href}
</a><span style="margin-left: 10px;">Created At : ${dayjs(obj.createdAt).format(DATE_YEAR_SECOND)}</span>`;
}
};
const handleManualSync = async () => {
await BrowserApi.sendRuntimeMessage({ type: BusMessageType.OPTIONS_SYNC_OUTGOING_OBJECT, data: props.obj?.id });
};
return (
<div style={{ backgroundColor: '#ffffff', width: '100%', display: 'flex', justifyContent: 'space-between' }}>
<div style={{ marginLeft: '10px', marginBottom: '5px' }}>
<h2 style={{ marginTop: '5px', marginBottom: '5px' }} ref={titleRef}></h2>
<div ref={urlRef}></div>
</div>
<div style={{ display: 'flex', alignItems: 'center' }}>
<div style={{ display: props.isLoading ? 'flex' : 'none' }}>
<CircularProgress />
</div>
<IconButton onClick={handleManualSync}>
<CloudSyncIcon />
</IconButton>
<IconButton onClick={props.handleDownload}>
<DownloadIcon />
</IconButton>
<IconButton onClick={props.handleClose}>
<ClearIcon />
</IconButton>
</div>
</div>
);
};

@ -19,10 +19,6 @@ import React, { FunctionComponent, useEffect, useRef, useState } from 'react';
import { SegmentImg, SegmentPage, SegmentType } from '@pinmenote/page-compute';
import { BrowserApi } from '@pinmenote/browser-api';
import CircularProgress from '@mui/material/CircularProgress';
import ClearIcon from '@mui/icons-material/Clear';
import { DATE_YEAR_SECOND } from '../../../common/date-format.constraints';
import DownloadIcon from '@mui/icons-material/Download';
import IconButton from '@mui/material/IconButton';
import { IframeHtmlFactory } from '../../../common/factory/iframe-html.factory';
import { LinkHrefStore } from '../../../common/store/link-href.store';
import { ObjGetCommand } from '../../../common/command/obj/obj-get.command';
@ -33,10 +29,10 @@ import { PageSnapshotDto } from '../../../common/model/obj/page-snapshot.dto';
import { PinComponent } from '../../../common/components/pin/pin.component';
import { SettingsStore } from '../../store/settings.store';
import { XpathFactory } from '../../../common/factory/xpath.factory';
import dayjs from 'dayjs';
import { fnConsoleLog } from '../../../common/fn/fn-console';
import { fnSleep } from '../../../common/fn/fn-sleep';
import { fnUid } from '../../../common/fn/fn-uid';
import { HtmlPreviewHeaderComponent } from './html-preview-header.component';
interface Props {
visible: boolean;
@ -45,13 +41,11 @@ interface Props {
export const HtmlPreviewComponent: FunctionComponent<Props> = (props) => {
const containerRef = useRef<HTMLDivElement>(null);
const htmlRef = useRef<HTMLDivElement>(null);
const titleRef = useRef<HTMLHeadingElement>(null);
const urlRef = useRef<HTMLDivElement>(null);
const [visible, setVisible] = useState<boolean>(props.visible);
const [pageSegment, setPageSegment] = useState<SegmentPage | undefined>();
const [pageSnapshot, setPageSnapshot] = useState<PageSnapshotDto | undefined>();
const [objData, setObjData] = useState<ObjDto<ObjPageDto> | undefined>();
const [isLoading, setIsLoading] = useState<boolean>(false);
const [isPreLoading, setIsPreLoading] = useState<boolean>(true);
@ -62,37 +56,33 @@ export const HtmlPreviewComponent: FunctionComponent<Props> = (props) => {
if (!idhash[0].startsWith('#obj')) return;
try {
fnConsoleLog('HtmlPreviewComponent->useEffect->render', props.visible, visible);
render(parseInt(idhash[1]));
render(parseInt(idhash[1])).catch((e) => fnConsoleLog('HtmlPreviewComponent->useEffect->render->ERROR', e));
} catch (e) {
fnConsoleLog('Error render or parseInt', e);
}
}
});
}, [props]);
const render = (id: number) => {
if (titleRef.current) titleRef.current.innerHTML = '';
if (urlRef.current) urlRef.current.innerHTML = '';
setTimeout(async () => {
setIsPreLoading(true);
setIsLoading(true);
const obj = await new ObjGetCommand<ObjPageDto>(id).execute();
setPageSnapshot(obj.data.snapshot);
const pageSegment = await new PageSegmentGetCommand<SegmentPage>(obj.data.snapshot.segment).execute();
if (pageSegment) {
setPageSegment(pageSegment.content);
} else {
fnConsoleLog('NOT FOUND ', obj.data.snapshot, 'hash', obj.data.snapshot.segment);
}
if (obj.data.snapshot.data.canvas) {
renderCanvas(obj);
} else {
await renderSnapshot(obj, pageSegment?.content);
}
if (obj.type === ObjTypeDto.PageSnapshot) {
const pinIds = await LinkHrefStore.pinIds(obj.data.snapshot.info.url.href);
await renderPins(pinIds);
}
});
const render = async (id: number) => {
setIsPreLoading(true);
setIsLoading(true);
const obj = await new ObjGetCommand<ObjPageDto>(id).execute();
setObjData(obj);
const pageSegment = await new PageSegmentGetCommand<SegmentPage>(obj.data.snapshot.segment).execute();
if (pageSegment) {
setPageSegment(pageSegment.content);
} else {
fnConsoleLog('NOT FOUND ', obj.data.snapshot, 'hash', obj.data.snapshot.segment);
}
if (obj.data.snapshot.data.canvas) {
renderCanvas(obj);
} else {
await renderSnapshot(obj, pageSegment?.content);
}
if (obj.type === ObjTypeDto.PageSnapshot) {
const pinIds = await LinkHrefStore.pinIds(obj.data.snapshot.info.url.href);
await renderPins(pinIds);
}
};
const renderPins = async (ids: number[]) => {
@ -160,8 +150,6 @@ export const HtmlPreviewComponent: FunctionComponent<Props> = (props) => {
const renderCanvas = (obj: ObjDto<ObjPageDto>, content?: SegmentPage) => {
const snapshot: PageSnapshotDto = obj.data.snapshot;
renderHeader(obj);
if (!htmlRef.current) return;
if (!containerRef.current) return;
const iframe = document.createElement('iframe');
@ -187,7 +175,6 @@ export const HtmlPreviewComponent: FunctionComponent<Props> = (props) => {
const renderSnapshot = async (obj: ObjDto<ObjPageDto>, segment?: SegmentPage): Promise<void> => {
const snapshot: PageSnapshotDto = obj.data.snapshot;
renderHeader(obj);
if (!htmlRef.current) return;
if (!containerRef.current) return;
if (!segment) return;
@ -210,19 +197,6 @@ export const HtmlPreviewComponent: FunctionComponent<Props> = (props) => {
setIsLoading(false);
};
const renderHeader = (obj: ObjDto<ObjPageDto>): void => {
const snapshot: PageSnapshotDto = obj.data.snapshot;
if (titleRef.current) {
titleRef.current.innerHTML = snapshot.info.title;
}
if (urlRef.current) {
urlRef.current.innerHTML = `
<a href="${snapshot.info.url.href}" target="_blank" style="word-break: break-all">
${snapshot.info.url.href}
</a><span style="margin-left: 10px;">Created At : ${dayjs(obj.createdAt).format(DATE_YEAR_SECOND)}</span>`;
}
};
const writeDoc = async (doc: Document, html: string, assets: string[], cleanLoader = false): Promise<void> => {
doc.write(html);
doc.close();
@ -310,7 +284,7 @@ export const HtmlPreviewComponent: FunctionComponent<Props> = (props) => {
};
const handleDownload = async () => {
if (!pageSegment || !pageSnapshot) return;
if (!pageSegment || !objData) return;
if (!htmlRef.current) return;
const iframe = htmlRef.current.lastChild as HTMLIFrameElement;
// TODO gather all iframe hashes and pass here with content
@ -347,23 +321,12 @@ export const HtmlPreviewComponent: FunctionComponent<Props> = (props) => {
left: '0px'
}}
>
<div style={{ backgroundColor: '#ffffff', width: '100%', display: 'flex', justifyContent: 'space-between' }}>
<div style={{ marginLeft: '10px', marginBottom: '5px' }}>
<h2 style={{ marginTop: '5px', marginBottom: '5px' }} ref={titleRef}></h2>
<div ref={urlRef}></div>
</div>
<div style={{ display: 'flex', alignItems: 'center' }}>
<div style={{ display: isLoading ? 'flex' : 'none' }}>
<CircularProgress />
</div>
<IconButton onClick={handleDownload}>
<DownloadIcon />
</IconButton>
<IconButton onClick={handleClose}>
<ClearIcon />
</IconButton>
</div>
</div>
<HtmlPreviewHeaderComponent
obj={objData}
handleDownload={handleDownload}
handleClose={handleClose}
isLoading={isLoading}
/>
<div style={{ width: '100%', height: '100%', backgroundColor: '#ffffff' }} ref={htmlRef}>
<div
style={{

@ -36,7 +36,6 @@ export class ApiStoreCommitCommand extends ApiCallBase implements ICommand<Promi
},
this.refreshParams()
);
fnConsoleLog('ApiStoreCommitCommand->response', resp);
return resp.ok;
} catch (e) {
fnConsoleLog('ApiStoreBeginCommand->Error', e);

@ -58,8 +58,9 @@ export enum SyncHashType {
}
export interface SegmentSingleHash {
hash: string;
type: SyncHashType;
hash: string;
mimeType?: string;
}
export interface SegmentHashListResponse {

@ -16,27 +16,36 @@
*/
import { ApiCallBase } from '../../api-call.base';
import { FetchService } from '@pinmenote/fetch-service';
import { ICommand } from '../../../../../common/model/shared/common.dto';
import { ICommand, ServerErrorDto } from '../../../../../common/model/shared/common.dto';
import { fnConsoleLog } from '../../../../../common/fn/fn-console';
import { ObjChangesResponse } from '../api-store.model';
import { ApiErrorCode } from '../../../../../common/model/shared/api.error-code';
export class ApiObjGetChangesCommand extends ApiCallBase implements ICommand<Promise<ObjChangesResponse | undefined>> {
constructor(private serverId?: number) {
const errorResponse: ServerErrorDto = { code: ApiErrorCode.INTERNAL, message: 'Send request problem' };
export class ApiObjGetChangesCommand
extends ApiCallBase
implements ICommand<Promise<ObjChangesResponse | ServerErrorDto>>
{
constructor(private serverId: number) {
super();
}
async execute(): Promise<ObjChangesResponse | undefined> {
async execute(): Promise<ObjChangesResponse | ServerErrorDto> {
await this.initTokenData();
if (!this.storeUrl) return;
if (!this.storeUrl) return errorResponse;
try {
const resp = await FetchService.fetch<ObjChangesResponse>(
`${this.storeUrl}/api/v1/obj/changes?serverId=${this.serverId || 0}`,
const resp = await FetchService.fetch<ObjChangesResponse | ServerErrorDto>(
`${this.storeUrl}/api/v1/obj/changes?serverId=${this.serverId}`,
{ headers: this.getAuthHeaders() },
this.refreshParams()
);
fnConsoleLog('ApiStoreChangesCommand->response', resp);
return resp.data;
if (resp.status === 200) return resp.data;
fnConsoleLog(resp);
errorResponse.message = (resp.data as ServerErrorDto).message;
return errorResponse;
} catch (e) {
fnConsoleLog('ApiStoreChangesCommand->Error', e);
fnConsoleLog('ApiObjGetChangesCommand->Error', e);
}
return errorResponse;
}
}

@ -36,15 +36,16 @@ export class ApiSegmentAddCommand extends ApiCallBase implements ICommand<Promis
async execute(): Promise<boolean> {
await this.initTokenData();
if (!this.storeUrl) return false;
if (await this.hasSegment()) return true;
return await this.addSegment();
// if (await this.hasSegment(this.storeUrl)) return true;
return await this.addSegment(this.storeUrl);
}
async hasSegment(): Promise<boolean> {
async hasSegment(storeUrl: string): Promise<boolean> {
if (!this.storeUrl) return false;
const authHeaders = this.getAuthHeaders();
const params = this.data.parent ? `?parent=${this.data.parent}` : '';
const resp = await FetchService.fetch<BeginTxResponse>(
`${this.storeUrl!}/api/v1/segment/has/${this.tx.tx}/${this.data.hash}${params}`,
`${storeUrl}/api/v1/segment/has/${this.tx.tx}/${this.data.hash}${params}`,
{
type: 'TEXT',
headers: {
@ -56,22 +57,26 @@ export class ApiSegmentAddCommand extends ApiCallBase implements ICommand<Promis
return resp.status === 200;
}
async addSegment(): Promise<boolean> {
async addSegment(storeUrl: string): Promise<boolean> {
const formData = new FormData();
if (this.data.type.toString() === SyncHashType.Img) {
if (this.file === 'data:') {
fnConsoleLog('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', this.file);
fnConsoleLog('ApiSegmentAddCommand->addSegment->EMPTY', this.file);
formData.append('file', new Blob([this.file], { type: 'image/svg+xml' }));
} else {
try {
formData.append('file', fnB64toBlob(this.file));
const blob = fnB64toBlob(this.file);
formData.append('mimeType', blob.type);
formData.append('file', blob);
} catch (e) {
console.log(this.file, this.data, e);
throw new Error('aaaaaaaaaaaaaaaaaaaaa');
fnConsoleLog(this.file, this.data, e);
throw new Error('ApiSegmentAddCommand->addSegment->Error->Img->base64');
}
}
} else if (this.data.type.toString() === SyncHashType.ObjPdf) {
formData.append('file', fnB64toBlob(this.file));
const blob = fnB64toBlob(this.file);
formData.append('mimeType', blob.type);
formData.append('file', blob);
} else {
const fileData = deflate(this.file);
formData.append('file', new Blob([fileData], { type: 'application/zip' }));
@ -85,7 +90,7 @@ export class ApiSegmentAddCommand extends ApiCallBase implements ICommand<Promis
const authHeaders = this.getAuthHeaders(false);
const resp = await FetchService.fetch(
`${this.storeUrl!}/api/v1/segment/add/${this.tx.tx}`,
`${storeUrl}/api/v1/segment/add/${this.tx.tx}`,
{
headers: {
...authHeaders

@ -20,15 +20,16 @@ import { ICommand } from '../../../../../common/model/shared/common.dto';
import { fnConsoleLog } from '../../../../../common/fn/fn-console';
export class ApiSegmentGetCommand extends ApiCallBase implements ICommand<Promise<Blob | undefined>> {
constructor(private hash: string) {
constructor(private hash: string, private mimeType?: string) {
super();
}
async execute(): Promise<Blob | undefined> {
await this.initTokenData();
if (!this.storeUrl) return;
try {
const mimeType = this.mimeType ? `?mimeType=${encodeURI(this.mimeType)}` : '';
const resp = await FetchService.fetch<Blob>(
`${this.storeUrl}/api/v1/segment/${this.hash}`,
`${this.storeUrl}/api/v1/segment/${this.hash}${mimeType}`,
{ headers: this.getAuthHeaders(), type: 'BLOB' },
this.refreshParams()
);

@ -16,23 +16,34 @@
*/
import { ApiCallBase } from '../../api-call.base';
import { FetchService } from '@pinmenote/fetch-service';
import { ICommand } from '../../../../../common/model/shared/common.dto';
import { ICommand, ServerErrorDto } from '../../../../../common/model/shared/common.dto';
import { ServerQuotaResponse } from '../../../../../common/model/sync-server.model';
import { ApiErrorCode } from '../../../../../common/model/shared/api.error-code';
import { fnConsoleLog } from '../../../../../common/fn/fn-console';
export class ApiSegmentQuotaGetCommand extends ApiCallBase implements ICommand<Promise<ServerQuotaResponse>> {
export class ApiSegmentQuotaGetCommand
extends ApiCallBase
implements ICommand<Promise<ServerQuotaResponse | ServerErrorDto>>
{
constructor() {
super();
}
async execute(): Promise<ServerQuotaResponse> {
async execute(): Promise<ServerQuotaResponse | ServerErrorDto> {
await this.initTokenData();
const resp = await FetchService.fetch<ServerQuotaResponse>(
`${this.storeUrl!}/api/v1/segment/quota`,
{
type: 'JSON',
headers: this.getAuthHeaders(true)
},
this.refreshParams()
);
return resp.data;
if (!this.storeUrl) return { code: ApiErrorCode.INTERNAL, message: 'ApiSegmentQuotaGetCommand' };
try {
const resp = await FetchService.fetch<ServerQuotaResponse>(
`${this.storeUrl}/api/v1/segment/quota`,
{
type: 'JSON',
headers: this.getAuthHeaders(true)
},
this.refreshParams()
);
return resp.data;
} catch (e) {
fnConsoleLog('ApiSegmentQuotaGetCommand', e);
}
return { code: ApiErrorCode.INTERNAL, message: 'ApiSegmentQuotaGetCommand' };
}
}

@ -14,14 +14,18 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { ApiSegmentQuotaGetCommand, ServerQuotaResponse } from '../api/store/segment/api-segment-quota-get.command';
import { ApiSegmentQuotaGetCommand } from '../api/store/segment/api-segment-quota-get.command';
import { BrowserApi } from '@pinmenote/browser-api';
import { BusMessageType } from '../../../common/model/bus.model';
import { ICommand } from '../../../common/model/shared/common.dto';
import { ICommand, ServerErrorDto } from '../../../common/model/shared/common.dto';
import { ServerQuotaResponse } from '../../../common/model/sync-server.model';
export class PopupServerQuotaCommand implements ICommand<Promise<void>> {
async execute(): Promise<void> {
const data = await new ApiSegmentQuotaGetCommand().execute();
await BrowserApi.sendRuntimeMessage<ServerQuotaResponse>({ type: BusMessageType.POPUP_SERVER_QUOTA, data });
await BrowserApi.sendRuntimeMessage<ServerQuotaResponse | ServerErrorDto>({
type: BusMessageType.POPUP_SERVER_QUOTA,
data
});
}
}

@ -50,7 +50,7 @@ export class SyncSnapshotIncomingCommand implements ICommand<Promise<boolean>> {
if (!hashList) return false;
const pageSnapshot = await this.getSnapshot(hashList);
if (!pageSnapshot) {
fnConsoleLog('SyncSnapshotIncomingCommand->execute PROBLEM !!!!!!!!!!!!!!!!!!!', this.change);
fnConsoleLog('SyncSnapshotIncomingCommand->execute PROBLEM !!!!!!!!!!!!!!!!!!!', this.change, hashList);
return false;
}
// sleep 1s for now
@ -108,7 +108,7 @@ export class SyncSnapshotIncomingCommand implements ICommand<Promise<boolean>> {
let info: PageSnapshotInfoDto | undefined;
let segment: string | undefined = undefined;
for (const child of hashList.children) {
const segmentData = await new ApiSegmentGetCommand(child.hash).execute();
const segmentData = await new ApiSegmentGetCommand(child.hash, child.mimeType).execute();
if (!segmentData) continue;
switch (child.type.toString()) {
case SyncHashType.Img: {
@ -117,10 +117,13 @@ export class SyncSnapshotIncomingCommand implements ICommand<Promise<boolean>> {
let src = 'data:';
try {
src = await UrlFactory.toDataUri(segmentData);
// @vane WORKAROUND FIX convert image/svg -> image/svg+xml to render correctly inside <img> tag
const check = 'data:image/svg';
if (src.startsWith(check)) src = 'data:image/svg+xml' + src.substring(check.length);
} catch (e) {
const buffer = await segmentData.arrayBuffer();
const textData = new TextDecoder().decode(buffer);
console.log('ERROR !!!!!!!!! AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa !!!!!!!!!!!!!!!!!!!!!!!!!!!', textData);
fnConsoleLog('SyncSnapshotIncomingCommand->getSnapshot->Img->Error !!!', textData);
}
const content: SegmentImg = { src };
await new PageSegmentAddCommand({ type: SegmentType.IMG, hash: child.hash, content }).execute();
@ -162,7 +165,6 @@ export class SyncSnapshotIncomingCommand implements ICommand<Promise<boolean>> {
segment = child.hash;
const content = await this.getString(segmentData);
const html: SegmentHtml = JSON.parse(content);
fnConsoleLog('SyncSnapshotIncomingCommand->getSnapshot->PageSnapshotFirstHash', html, child.hash);
await new PageSegmentAddCommand({
type: SegmentType.SNAPSHOT,
content: html,

@ -0,0 +1,93 @@
/*
* This file is part of the pinmenote-extension distribution (https://github.com/pinmenote/pinmenote-extension).
* Copyright (c) 2023 Michal Szczepanski.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { BrowserApi } from '@pinmenote/browser-api';
import { ICommand } from '../../../../common/model/shared/common.dto';
import { ObjGetCommand } from '../../../../common/command/obj/obj-get.command';
import { fnConsoleLog } from '../../../../common/fn/fn-console';
import { BusMessageType } from '../../../../common/model/bus.model';
import { ObjDto, ObjRemovedDto, ObjTypeDto } from '../../../../common/model/obj/obj.dto';
import { SyncSnapshotCommand } from '../outgoing/sync-snapshot.command';
import { ObjPageDto } from '../../../../common/model/obj/obj-page.dto';
import { SyncPinCommand } from '../outgoing/sync-pin.command';
import { ObjPinDto } from '../../../../common/model/obj/obj-pin.dto';
import { SyncPdfCommand } from '../outgoing/sync-pdf.command';
import { ObjPdfDto } from '../../../../common/model/obj/obj-pdf.dto';
import { SyncNoteCommand } from '../outgoing/sync-note.command';
import { ObjNoteDto, ObjPageNoteDto } from '../../../../common/model/obj/obj-note.dto';
import { SyncPageNoteCommand } from '../outgoing/sync-page-note.command';
import { SyncRemovedCommand } from '../outgoing/sync-removed.command';
import { SyncTxHelper } from '../sync-tx.helper';
import { BeginTxResponse } from '../../api/store/api-store.model';
import { SyncObjectStatus } from '../../../../common/model/sync.model';
export class SyncManualOutgoingCommand implements ICommand<Promise<void>> {
constructor(private id: number) {}
async execute(): Promise<void> {
fnConsoleLog('SyncManualOutgoingCommand !!!!!!!!!!');
const obj = await new ObjGetCommand(this.id).execute();
if (!obj) {
fnConsoleLog('SyncObjectCommand->syncObject EMPTY', this.id, obj);
await this.sendResponse(SyncObjectStatus.OBJECT_NOT_EXISTS);
return;
}
const tx = await SyncTxHelper.begin();
if (!tx) {
fnConsoleLog('SyncManualOutgoingCommand !!!!!!!!!! TX', tx);
await this.sendResponse(SyncObjectStatus.TX_LOCKED);
return;
}
const status = await this.syncObj(obj, tx);
await this.sendResponse(status);
fnConsoleLog('SyncManualOutgoingCommand->execute id', obj.id, 'serverId', obj.server?.id);
await SyncTxHelper.commit();
}
private sendResponse = async (status: SyncObjectStatus) => {
await BrowserApi.sendRuntimeMessage<SyncObjectStatus>({
type: BusMessageType.OPTIONS_SYNC_OUTGOING_OBJECT,
data: status
});
};
private syncObj = async (obj: ObjDto, tx: BeginTxResponse) => {
switch (obj.type) {
case ObjTypeDto.PageSnapshot:
case ObjTypeDto.PageElementSnapshot: {
return await new SyncSnapshotCommand(obj as ObjDto<ObjPageDto>, tx).execute();
}
case ObjTypeDto.PageElementPin: {
return await new SyncPinCommand(obj as ObjDto<ObjPinDto>, tx).execute();
}
case ObjTypeDto.Pdf: {
return await new SyncPdfCommand(obj as ObjDto<ObjPdfDto>, tx).execute();
}
case ObjTypeDto.Note: {
return await new SyncNoteCommand(obj as ObjDto<ObjNoteDto>, tx).execute();
}
case ObjTypeDto.PageNote: {
return await new SyncPageNoteCommand(obj as ObjDto<ObjPageNoteDto>, tx).execute();
}
case ObjTypeDto.Removed: {
return await new SyncRemovedCommand(obj as ObjDto<ObjRemovedDto>, tx).execute();
}
default: {
fnConsoleLog('SyncObjectCommand->PROBLEM', obj, 'index', this.id);
return SyncObjectStatus.SERVER_ERROR;
}
}
};
}

@ -18,9 +18,9 @@ import { ICommand } from '../../../../common/model/shared/common.dto';
import { ObjDto } from '../../../../common/model/obj/obj.dto';
import { ObjNoteDto } from '../../../../common/model/obj/obj-note.dto';
import { SyncObjectCommand } from './sync-object.command';
import { SyncObjectStatus } from '../sync.model';
import { fnConsoleLog } from '../../../../common/fn/fn-console';
import { BeginTxResponse } from '../../api/store/api-store.model';
import { SyncObjectStatus } from '../../../../common/model/sync.model';
export class SyncNoteCommand implements ICommand<Promise<SyncObjectStatus>> {
constructor(private obj: ObjDto<ObjNoteDto>, private tx: BeginTxResponse) {}

@ -36,7 +36,7 @@ export class SyncObjectCommand implements ICommand<Promise<void>> {
} else if ('code' in resp && resp.code === ApiErrorCode.SYNC_DUPLICATED_HASH) {
return await this.setByHash();
}
fnConsoleLog('SyncObjectCommand', 'tx', this.tx, 'resp', resp);
fnConsoleLog('SyncObjectCommand', 'tx', this.tx, 'resp', resp, 'obj', this.obj);
throw new Error('PROBLEM !!!!!!!!!!!!!!!');
}

@ -19,7 +19,7 @@ import { ICommand } from '../../../../common/model/shared/common.dto';
import { ObjDto } from '../../../../common/model/obj/obj.dto';
import { ObjPageNoteDto } from '../../../../common/model/obj/obj-note.dto';
import { SyncObjectCommand } from './sync-object.command';
import { SyncObjectStatus } from '../sync.model';
import { SyncObjectStatus } from '../../../../common/model/sync.model';
import { fnConsoleLog } from '../../../../common/fn/fn-console';
import { BeginTxResponse, SyncHashType } from '../../api/store/api-store.model';
import { ObjectStoreKeys } from '../../../../common/keys/object.store.keys';
@ -41,10 +41,9 @@ export class SyncPageNoteCommand implements ICommand<Promise<SyncObjectStatus>>
private async syncNote(data: ObjPageNoteDto): Promise<void> {
const content = JSON.stringify(data);
await new ApiSegmentAddCommand(this.tx, content, {
hash: data.hash,
parent: data.hash,
key: await SyncCryptoFactory.newKey(),
type: SyncHashType.ObjPdfDataDto,
key: await SyncCryptoFactory.newKey()
hash: data.hash
}).execute();
if (data.prev) {
const prevData = await BrowserStorage.get<ObjPageNoteDto>(`${ObjectStoreKeys.NOTE_HASH}:${data.prev}`);

@ -18,7 +18,7 @@ import { ICommand } from '../../../../common/model/shared/common.dto';
import { ObjDto } from '../../../../common/model/obj/obj.dto';
import { ObjPdfDataDto, ObjPdfDto } from '../../../../common/model/obj/obj-pdf.dto';
import { SyncObjectCommand } from './sync-object.command';
import { SyncObjectStatus } from '../sync.model';
import { SyncObjectStatus } from '../../../../common/model/sync.model';
import { BeginTxResponse, SyncHashType } from '../../api/store/api-store.model';
import { ObjectStoreKeys } from '../../../../common/keys/object.store.keys';
import { BrowserStorage } from '@pinmenote/browser-api';
@ -40,21 +40,20 @@ export class SyncPdfCommand implements ICommand<Promise<SyncObjectStatus>> {
private async syncData(data: ObjPdfDataDto, parent: string): Promise<void> {
const content = JSON.stringify(data);
await new ApiSegmentAddCommand(this.tx, content, {
hash: data.hash,
parent,
key: await SyncCryptoFactory.newKey(),
type: SyncHashType.ObjPdfDataDto,
key: await SyncCryptoFactory.newKey()
hash: data.hash,
parent
}).execute();
}
private async syncPdf(parent: string): Promise<void> {
const pdfData = await BrowserStorage.get<string | undefined>(`${ObjectStoreKeys.PDF_DATA}:${parent}`);
private async syncPdf(hash: string): Promise<void> {
const pdfData = await BrowserStorage.get<string | undefined>(`${ObjectStoreKeys.PDF_DATA}:${hash}`);
if (!pdfData) return;
await new ApiSegmentAddCommand(this.tx, pdfData, {
hash: parent,
parent,
key: await SyncCryptoFactory.newKey(),
type: SyncHashType.ObjPdf,
key: await SyncCryptoFactory.newKey()
hash
}).execute();
}
}

@ -18,7 +18,7 @@ import { ICommand } from '../../../../common/model/shared/common.dto';
import { ObjDto } from '../../../../common/model/obj/obj.dto';
import { ObjPinDataDto, ObjPinDescription, ObjPinDto } from '../../../../common/model/obj/obj-pin.dto';
import { SyncObjectCommand } from './sync-object.command';
import { SyncObjectStatus } from '../sync.model';
import { SyncObjectStatus } from '../../../../common/model/sync.model';
import { BeginTxResponse, SyncHashType } from '../../api/store/api-store.model';
import { ApiSegmentAddCommand } from '../../api/store/segment/api-segment-add.command';
import { PinGetCommentCommand } from '../../../../common/command/pin/comment/pin-get-comment.command';
@ -45,10 +45,10 @@ export class SyncPinCommand implements ICommand<Promise<SyncObjectStatus>> {
if (!data) return;
const content = JSON.stringify(data);
await new ApiSegmentAddCommand(this.tx, content, {
hash: data.hash,
parent,
key: await SyncCryptoFactory.newKey(),
type: SyncHashType.ObjVideoDataDto,
key: await SyncCryptoFactory.newKey()
hash: data.hash,
parent
}).execute();
};
@ -57,10 +57,10 @@ export class SyncPinCommand implements ICommand<Promise<SyncObjectStatus>> {
// TODO SYNC DRAW LIKE COMMENTS
const content = JSON.stringify(draw);
await new ApiSegmentAddCommand(this.tx, content, {
hash: draw.hash,
parent,
key: await SyncCryptoFactory.newKey(),
type: SyncHashType.ObjDrawDto,
key: await SyncCryptoFactory.newKey()
hash: draw.hash,
parent
}).execute();
}
};
@ -71,10 +71,10 @@ export class SyncPinCommand implements ICommand<Promise<SyncObjectStatus>> {
if (!comment) continue;
const content = JSON.stringify(comment);
await new ApiSegmentAddCommand(this.tx, content, {
hash: comment.hash,
parent,
key: await SyncCryptoFactory.newKey(),
type: SyncHashType.ObjCommentDto,
key: await SyncCryptoFactory.newKey()
hash: comment.hash,
parent
}).execute();
}
};
@ -82,20 +82,19 @@ export class SyncPinCommand implements ICommand<Promise<SyncObjectStatus>> {
private syncPinData = async (data: ObjPinDataDto) => {
const content = JSON.stringify(data);
await new ApiSegmentAddCommand(this.tx, content, {
hash: data.hash,
parent: data.hash,
key: await SyncCryptoFactory.newKey(),
type: SyncHashType.ObjPinDataDto,
key: await SyncCryptoFactory.newKey()
hash: data.hash
}).execute();
};
private syncPinDescription = async (data: ObjPinDescription, parent: string) => {
const content = JSON.stringify(data);
await new ApiSegmentAddCommand(this.tx, content, {
hash: data.hash,
parent,
key: await SyncCryptoFactory.newKey(),
type: SyncHashType.ObjPinDescription,
key: await SyncCryptoFactory.newKey()
hash: data.hash,
parent
}).execute();
};
}

@ -16,7 +16,7 @@
*/
import { ObjDto, ObjRemovedDto } from '../../../../common/model/obj/obj.dto';
import { ICommand } from '../../../../common/model/shared/common.dto';
import { SyncObjectStatus } from '../sync.model';
import { SyncObjectStatus } from '../../../../common/model/sync.model';
import { fnConsoleLog } from '../../../../common/fn/fn-console';
import { BeginTxResponse } from '../../api/store/api-store.model';

@ -20,7 +20,7 @@ import { ObjDto } from '../../../../common/model/obj/obj.dto';
import { ObjPageDto } from '../../../../common/model/obj/obj-page.dto';
import { PageSegmentGetCommand } from '../../../../common/command/snapshot/segment/page-segment-get.command';
import { SyncObjectCommand } from './sync-object.command';
import { SyncObjectStatus } from '../sync.model';
import { SyncObjectStatus } from '../../../../common/model/sync.model';
import { fnConsoleLog } from '../../../../common/fn/fn-console';
import { BeginTxResponse, SyncHashType } from '../../api/store/api-store.model';
import { PageSnapshotDto } from '../../../../common/model/obj/page-snapshot.dto';
@ -55,10 +55,10 @@ export class SyncSnapshotCommand implements ICommand<Promise<SyncObjectStatus>>
const content = this.getSegmentContent(segment);
if (!content) return;
await new ApiSegmentAddCommand(this.tx, content, {
hash: segment.hash,
parent,
key: await SyncCryptoFactory.newKey(),
type: SyncHashType.PageSnapshotFirstHash,
key: await SyncCryptoFactory.newKey()
hash: segment.hash,
parent
}).execute();
await this.syncSegmentSnapshot(segment.content as SegmentPage, parent);
};
@ -66,17 +66,17 @@ export class SyncSnapshotCommand implements ICommand<Promise<SyncObjectStatus>>
private async syncSnapshot(snapshot: PageSnapshotDto, parent: string): Promise<void> {
// snapshot->info
await new ApiSegmentAddCommand(this.tx, JSON.stringify(snapshot.info), {
hash: snapshot.info.hash,
parent,
key: await SyncCryptoFactory.newKey(),
type: SyncHashType.PageSnapshotInfoDto,
key: await SyncCryptoFactory.newKey()
hash: snapshot.info.hash,
parent
}).execute();
// snapshot->data
await new ApiSegmentAddCommand(this.tx, JSON.stringify(snapshot.data), {
hash: snapshot.data.hash,
parent,
key: await SyncCryptoFactory.newKey(),
type: SyncHashType.PageSnapshotDataDto,
key: await SyncCryptoFactory.newKey()
hash: snapshot.data.hash,
parent
}).execute();
}
// eslint-disable-next-line @typescript-eslint/require-await
@ -91,10 +91,10 @@ export class SyncSnapshotCommand implements ICommand<Promise<SyncObjectStatus>>
if (!content) return;
await new ApiSegmentAddCommand(this.tx, content, {
hash,
parent,
key: await SyncCryptoFactory.newKey(),
type: this.convertSegmentTypeSyncHashType(segment.type),
key: await SyncCryptoFactory.newKey()
hash,
parent
}).execute();
switch (segment.type) {

@ -19,7 +19,7 @@ import { ICommand } from '../../../../common/model/shared/common.dto';
import { ObjDto } from '../../../../common/model/obj/obj.dto';
import { ObjGetCommand } from '../../../../common/command/obj/obj-get.command';
import { ObjectStoreKeys } from '../../../../common/keys/object.store.keys';
import { SyncProgress } from '../sync.model';
import { SyncProgress } from '../../../../common/model/sync.model';
export class SyncGetProgressCommand implements ICommand<Promise<SyncProgress>> {
async execute(): Promise<SyncProgress> {

@ -18,13 +18,14 @@ import { BrowserStorage } from '@pinmenote/browser-api';
import { ICommand } from '../../../../common/model/shared/common.dto';
import { ObjectStoreKeys } from '../../../../common/keys/object.store.keys';
import { SyncGetProgressCommand } from './sync-get-progress.command';
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';
import { SyncProgress } from '../../../../common/model/sync.model';
export class SyncResetProgressCommand implements ICommand<Promise<void>> {
constructor(private refreshUpdateList = false) {}
async execute(): Promise<void> {
const obj = await SyncGetProgressCommand.getFirstObject();
const timestamp = obj?.createdAt || -1;
@ -58,17 +59,20 @@ export class SyncResetProgressCommand implements ICommand<Promise<void>> {
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);
if (this.refreshUpdateList) await this.updateList(yearMonth, obj);
}
listId -= 1;
fnConsoleLog('SyncResetProgressCommand', listId);
}
// sort objects inside
if (this.refreshUpdateList) await this.sortUpdateList(toSortSet);
// clear tx
await BrowserStorage.remove(ObjectStoreKeys.SYNC_TX);
fnConsoleLog('SyncResetProgressCommand->complete in ', Date.now() - a);
}
private sortUpdateList = async (toSortSet: Set<string>) => {
for (const yearMonth of toSortSet) {
const list = await this.getList(yearMonth);
const s = new Set<number>();
@ -88,11 +92,16 @@ export class SyncResetProgressCommand implements ICommand<Promise<void>> {
});
await this.setList(yearMonth, newList);
}
};
// clear tx
await BrowserStorage.remove(ObjectStoreKeys.SYNC_TX);
fnConsoleLog('SyncResetProgressCommand->complete in ', Date.now() - a);
}
private updateList = async (yearMonth: string, obj: ObjDto) => {
const updateList = await this.getList(yearMonth);
if (updateList.findIndex((o) => o.id === obj.id) > 0) return;
updateList.push({ id: obj.id, dt: obj.updatedAt });
await this.setList(yearMonth, updateList);
};
private async setList(yearMonth: string, list: ObjDateIndex[]): Promise<void> {
const updateListKey = `${ObjectStoreKeys.UPDATED_DT}:${yearMonth}`;

@ -17,7 +17,7 @@
import { BrowserStorage } from '@pinmenote/browser-api';
import { ICommand } from '../../../../common/model/shared/common.dto';
import { ObjectStoreKeys } from '../../../../common/keys/object.store.keys';
import { SyncProgress } from '../sync.model';
import { SyncProgress } from '../../../../common/model/sync.model';
export class SyncSetProgressCommand implements ICommand<Promise<void>> {
constructor(protected progress: SyncProgress) {}

@ -25,15 +25,14 @@ import { SyncNoteCommand } from './outgoing/sync-note.command';
import { SyncPageNoteCommand } from './outgoing/sync-page-note.command';
import { SyncPdfCommand } from './outgoing/sync-pdf.command';
import { SyncPinCommand } from './outgoing/sync-pin.command';
import { SyncObjectStatus, SyncProgress } from './sync.model';
import { SyncObjectStatus } from '../../../common/model/sync.model';
import { SyncRemovedCommand } from './outgoing/sync-removed.command';
import { SyncSnapshotCommand } from './outgoing/sync-snapshot.command';
import { fnConsoleLog } from '../../../common/fn/fn-console';
import { BeginTxResponse } from '../api/store/api-store.model';
import { fnSleep } from '../../../common/fn/fn-sleep';
export class SyncIndexCommand implements ICommand<Promise<SyncObjectStatus>> {
constructor(private progress: SyncProgress, private tx: BeginTxResponse, private id: number) {}
constructor(private tx: BeginTxResponse, private id: number) {}
async execute(): Promise<SyncObjectStatus> {
const obj = await new ObjGetCommand(this.id).execute();

@ -17,7 +17,7 @@
import { SyncIndexCommand } from './sync-index.command';
import { ICommand } from '../../../common/model/shared/common.dto';
import { ObjectStoreKeys } from '../../../common/keys/object.store.keys';
import { SyncObjectStatus, SyncProgress } from './sync.model';
import { SyncObjectStatus, SyncProgress } from '../../../common/model/sync.model';
import { SyncTxHelper } from './sync-tx.helper';
import { fnConsoleLog } from '../../../common/fn/fn-console';
import { ObjDateIndex } from '../../../common/command/obj/index/obj-update-index-add.command';
@ -56,7 +56,7 @@ export class SyncMonthCommand implements ICommand<Promise<SyncObjectStatus>> {
let i = start;
let status = SyncObjectStatus.OK;
for (i; i < indexList.length; i++) {
status = await new SyncIndexCommand(this.progress, begin, indexList[i].id).execute();
status = await new SyncIndexCommand(begin, indexList[i].id).execute();
switch (status) {
case SyncObjectStatus.SERVER_ERROR: {
fnConsoleLog('SERVER_ERROR !!!!!!!!!!!!!!!!!!!');

@ -18,7 +18,7 @@ import { fnDateToMonthFirstDay, fnMonthLastDay } from '../../../common/fn/fn-dat
import { ICommand } from '../../../common/model/shared/common.dto';
import { SyncGetProgressCommand } from './progress/sync-get-progress.command';
import { SyncMonthCommand } from './sync-month.command';
import { SyncProgress } from './sync.model';
import { SyncProgress } from '../../../common/model/sync.model';
import { SyncTxHelper } from './sync-tx.helper';
import { fnConsoleLog } from '../../../common/fn/fn-console';
import { fnDateKeyFormat } from '../../../common/fn/fn-date-format';
@ -34,16 +34,13 @@ export class SyncServerCommand implements ICommand<Promise<void>> {
if (SyncServerCommand.isInSync) return;
if (!(await SyncTxHelper.shouldSync())) return;
try {
// await new SyncResetProgressCommand().execute();
/*const token = await new TokenStorageGetCommand().execute();
if (token) console.log(jwtDecode<TokenDataDto>(token.access_token));*/
await new SyncResetProgressCommand(false).execute();
SyncServerCommand.isInSync = true;
const a = Date.now();
const progress = await new SyncGetProgressCommand().execute();
await this.syncOutgoing(progress);
// await this.syncOutgoing(progress);
await this.syncIncoming(progress);
fnConsoleLog('SyncServerCommand->execute', progress, 'in', Date.now() - a);
@ -53,9 +50,9 @@ export class SyncServerCommand implements ICommand<Promise<void>> {
}
private async syncIncoming(progress: SyncProgress): Promise<void> {
fnConsoleLog('SyncServerCommand->syncIncoming');
const changesResp = await new ApiObjGetChangesCommand(progress.serverId).execute();
if (!changesResp) return;
fnConsoleLog('SyncServerCommand->syncIncoming', changesResp);
if ('code' in changesResp) return;
for (let i = 0; i < changesResp.data.length; i++) {
const change = changesResp.data[i];
if (progress.serverId > change.serverId) continue;
@ -69,9 +66,11 @@ export class SyncServerCommand implements ICommand<Promise<void>> {
return;
}
}
fnConsoleLog('SyncServerCommand->syncIncoming->COMPLETE !!!');
}
private async syncOutgoing(progress: SyncProgress): Promise<void> {
fnConsoleLog('SyncServerCommand->syncOutgoing');
// Empty list - fresh install
if (progress.id == -1) return;
const dt = fnDateToMonthFirstDay(new Date(progress.timestamp));
@ -88,5 +87,6 @@ export class SyncServerCommand implements ICommand<Promise<void>> {
dt.setMonth(dt.getMonth() + 1);
}
fnConsoleLog('SyncServerCommand->syncOutgoing->COMPLETE !!!');
}
}

@ -37,6 +37,7 @@ import { SwInitSettingsCommand } from './command/sw/sw-init-settings.command';
import { SyncServerCommand } from './command/sync/sync-server.command';
import { TaskExecutor } from './task/task.executor';
import { fnConsoleLog } from '../common/fn/fn-console';
import { SyncManualOutgoingCommand } from './command/sync/manual/sync-manual-outgoing.command';
const handleMessage = async (
msg: BusMessage<any>,
@ -93,6 +94,10 @@ const handleMessage = async (
case BusMessageType.POPUP_SERVER_QUOTA:
await new PopupServerQuotaCommand().execute();
break;
case BusMessageType.OPTIONS_SYNC_OUTGOING_OBJECT: {
await new SyncManualOutgoingCommand(msg.data).execute();
break;
}
case BusMessageType.IFRAME_INDEX:
case BusMessageType.IFRAME_INDEX_REGISTER:
case BusMessageType.IFRAME_START_LISTENERS:
@ -109,9 +114,11 @@ const handleMessage = async (
}
// Sync command
if (
![PageComputeMessage.CONTENT_FETCH_CSS, PageComputeMessage.CONTENT_FETCH_IMAGE].includes(
msg.type as PageComputeMessage
)
![
PageComputeMessage.CONTENT_FETCH_CSS,
PageComputeMessage.CONTENT_FETCH_IMAGE,
BusMessageType.OPTIONS_SYNC_OUTGOING_OBJECT
].includes(msg.type as any)
) {
await new SyncServerCommand().execute();
}