fix: sync image - add mimeType, add manual sync in options-ui
This commit is contained in:
parent
2863a878e6
commit
50b27e731e
@ -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();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user