Skip to content

Commit

Permalink
Merge branch 'feat/manual-sync' into feat/rebrand-pc-loud
Browse files Browse the repository at this point in the history
  • Loading branch information
miguelsw committed Apr 5, 2024
2 parents f5fe501 + b96e514 commit f280744
Show file tree
Hide file tree
Showing 14 changed files with 144 additions and 21 deletions.
8 changes: 8 additions & 0 deletions src/apps/main/background-processes/sync-engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,14 @@ export function updateSyncEngine() {
}
}

export function fallbackSyncEngine() {
try {
worker?.webContents.send('FALLBACK_SYNC_ENGINE_PROCESS');
} catch (err) {
Logger.error(err);
}
}

eventBus.on('USER_LOGGED_OUT', stopAndClearSyncEngineWatcher);
eventBus.on('USER_WAS_UNAUTHORIZED', stopAndClearSyncEngineWatcher);
eventBus.on('INITIAL_SYNC_READY', spawnSyncEngineWorker);
2 changes: 2 additions & 0 deletions src/apps/main/preload.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,5 +167,7 @@ declare interface Window {
startRemoteSync: () => Promise<void>;
openUrl: (url: string) => Promise<void>;
getPreferredAppLanguage: () => Promise<Array<string>>;
syncManually: () => Promise<void>;
getRecentlywasSyncing: () => Promise<boolean>;
};
}
7 changes: 7 additions & 0 deletions src/apps/main/preload.js
Original file line number Diff line number Diff line change
Expand Up @@ -296,5 +296,12 @@ contextBridge.exposeInMainWorld('electron', {
getPreferredAppLanguage() {
return ipcRenderer.invoke('APP:PREFERRED_LANGUAGE');
},
syncManually() {
return ipcRenderer.invoke('SYNC_MANUALLY');
},
getRecentlywasSyncing() {
return ipcRenderer.invoke('CHECK_SYNC_IN_PROGRESS');
},

path,
});
27 changes: 27 additions & 0 deletions src/apps/main/remote-sync/RemoteSyncManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
RemoteSyncedFile,
SyncConfig,
SYNC_OFFSET_MS,
WAITING_AFTER_SYNCING
} from './helpers';
import { reportError } from '../bug-report/service';

Expand All @@ -24,6 +25,8 @@ export class RemoteSyncManager {
> = [];
private totalFilesSynced = 0;
private totalFoldersSynced = 0;
private lastSyncingFinishedTimestamp: Date | null = null;

constructor(
private db: {
files: DatabaseCollectionAdapter<DriveFile>;
Expand All @@ -47,10 +50,15 @@ export class RemoteSyncManager {
if (typeof callback !== 'function') return;
this.onStatusChangeCallbacks.push(callback);
}

getSyncStatus(): RemoteSyncStatus {
return this.status;
}

private getLastSyncingFinishedTimestamp() {
return this.lastSyncingFinishedTimestamp;
}

/**
* Check if the RemoteSyncManager is in SYNCED status
*
Expand All @@ -60,10 +68,22 @@ export class RemoteSyncManager {
return this.status === 'SYNCED';
}

/**
* Consult if recently the RemoteSyncManager was syncing
* @returns True if the RemoteSyncManager was syncing recently
* @returns False if the RemoteSyncManager was not syncing recently
*/
recentlyWasSyncing() {
const passedTime = Date.now() - ( this.getLastSyncingFinishedTimestamp()?.getTime() ?? Date.now() );
return passedTime < WAITING_AFTER_SYNCING;
}

resetRemoteSync() {
this.changeStatus('IDLE');
this.filesSyncStatus = 'IDLE';
this.foldersSyncStatus = 'IDLE';
this._placeholdersStatus = 'IDLE';
this.lastSyncingFinishedTimestamp = null;
this.totalFilesSynced = 0;
this.totalFoldersSynced = 0;
}
Expand Down Expand Up @@ -148,6 +168,7 @@ export class RemoteSyncManager {
return true;
}
private changeStatus(newStatus: RemoteSyncStatus) {
this.addLastSyncingFinishedTimestamp();
if (newStatus === this.status) return;
Logger.info(`RemoteSyncManager ${this.status} -> ${newStatus}`);
this.status = newStatus;
Expand All @@ -157,6 +178,12 @@ export class RemoteSyncManager {
});
}

private addLastSyncingFinishedTimestamp() {
if (this.status !== 'SYNCING') return;
Logger.info('Adding last syncing finished timestamp');
this.lastSyncingFinishedTimestamp = new Date();
}

private checkRemoteSyncStatus() {
if (this._placeholdersStatus === 'SYNCING') {
this.changeStatus('SYNCING');
Expand Down
42 changes: 30 additions & 12 deletions src/apps/main/remote-sync/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ import eventBus from '../event-bus';
import { RemoteSyncManager } from './RemoteSyncManager';
import { DriveFilesCollection } from '../database/collections/DriveFileCollection';
import { DriveFoldersCollection } from '../database/collections/DriveFolderCollection';
import { clearRemoteSyncStore } from './helpers';
import { clearRemoteSyncStore, RemoteSyncStatus } from './helpers';
import { getNewTokenClient } from '../../shared/HttpClient/main-process-client';
import Logger from 'electron-log';
import { ipcMain } from 'electron';
import { reportError } from '../bug-report/service';
import { sleep } from '../util';
import { broadcastToWindows } from '../windows';
import { updateSyncEngine } from '../background-processes/sync-engine';
import {
updateSyncEngine,
fallbackSyncEngine,
} from '../background-processes/sync-engine';

let initialSyncReady = false;
const driveFilesCollection = new DriveFilesCollection();
Expand Down Expand Up @@ -77,14 +80,27 @@ ipcMain.handle('get-remote-sync-status', () =>
remoteSyncManager.getSyncStatus()
);

eventBus.on('RECEIVED_REMOTE_CHANGES', async () => {
export async function updateRemoteSync(): Promise<void> {
// Wait before checking for updates, could be possible
// that we received the notification, but if we check
// for new data we don't receive it
await sleep(2_000);

await remoteSyncManager.startRemoteSync();
updateSyncEngine();
}
export async function fallbackRemoteSync(): Promise<void> {
await sleep(2_000);
fallbackSyncEngine();
}

ipcMain.handle('SYNC_MANUALLY', async () => {
Logger.info('[Manual Sync] Received manual sync event');
await updateRemoteSync();
await fallbackRemoteSync();
});

eventBus.on('RECEIVED_REMOTE_CHANGES', async () => {
await updateRemoteSync();
});

eventBus.on('USER_LOGGED_IN', async () => {
Expand All @@ -104,16 +120,18 @@ eventBus.on('USER_LOGGED_OUT', () => {

ipcMain.on('CHECK_SYNC', (event) => {
Logger.info('Checking sync');
event.sender.send(
'CHECK_SYNC_ENGINE_RESPONSE',
'Dato obtenido del proceso de sincronización'
);
event.sender.send('CHECK_SYNC_ENGINE_RESPONSE', '');
});

ipcMain.on('CHECK_SYNC_CHANGE_STATUS', async (_, placeholderStates) => {
await sleep(2_000);
Logger.info('[SYNC ENGINE] Changing status');
remoteSyncManager.placeholderStatus = 'SYNCING';
await sleep(7_00);
Logger.info('[SYNC ENGINE] Changing status', placeholderStates);
await sleep(5_000);
remoteSyncManager.placeholderStatus = placeholderStates;
});

ipcMain.handle('CHECK_SYNC_IN_PROGRESS', async () => {
const syncingStatus: RemoteSyncStatus = 'SYNCING';
const isSyncing = remoteSyncManager.getSyncStatus() === syncingStatus;
const recentlySyncing = remoteSyncManager.recentlyWasSyncing();
return isSyncing || recentlySyncing; // If it's syncing or recently was syncing
});
1 change: 1 addition & 0 deletions src/apps/main/remote-sync/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export type SyncConfig = {
};

export const SYNC_OFFSET_MS = 0;
export const WAITING_AFTER_SYNCING = 1000 * 60 * 3;

export const lastSyncedAtIsNewer = (
itemUpdatedAt: Date,
Expand Down
1 change: 1 addition & 0 deletions src/apps/renderer/localize/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@
},
"dropdown": {
"preferences": "Preferences",
"sync": "Sync",
"issues": "Issues",
"send-feedback": "Send feedback",
"support": "Support",
Expand Down
1 change: 1 addition & 0 deletions src/apps/renderer/localize/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@
},
"dropdown": {
"preferences": "Preferencias",
"sync": "Sincronizar",
"issues": "Lista de errores",
"send-feedback": "Enviar feedback",
"support": "Ayuda",
Expand Down
25 changes: 25 additions & 0 deletions src/apps/renderer/pages/Widget/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import useUsage from '../../hooks/useUsage';
import useVirtualDriveStatus from '../../hooks/VirtualDriveStatus';
import { reportError } from '../../utils/errors';


export default function Header() {
const { translate } = useTranslationContext();
const { virtualDriveCanBeOpened } = useVirtualDriveStatus();
Expand Down Expand Up @@ -45,6 +46,19 @@ export default function Header() {
window.electron.quit();
}

const wasSyncing = () => {
return window.electron.getRecentlywasSyncing();
};

async function onSyncClick() {
const notAllowed = await wasSyncing();
if (notAllowed) {
return;
}
window.electron.syncManually();
}


const handleOpenURL = async (URL: string) => {
try {
await window.electron.openUrl(URL);
Expand Down Expand Up @@ -195,6 +209,17 @@ export default function Header() {
</div>
)}
</Menu.Item>
<Menu.Item>
{({active}) => {

return (<div>
<DropdownItem active={active} onClick={onSyncClick} >
<span>{translate('widget.header.dropdown.sync')}</span>
</DropdownItem>
</div>);
}
}
</Menu.Item>
<Menu.Item>
{({ active }) => (
<div>
Expand Down
4 changes: 3 additions & 1 deletion src/apps/sync-engine/BindingManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -322,16 +322,18 @@ export class BindingsManager {
}

private async pollingStart() {
Logger.debug('[SYNC ENGINE] Starting polling');
return this.container.pollingMonitorStart.run(this.polling.bind(this));
}

private async polling(): Promise<void> {
async polling(): Promise<void> {
try {
Logger.info('[SYNC ENGINE] Monitoring polling...');

const fileInPendingPaths =
(await this.container.virtualDrive.getPlaceholderWithStatePending()) as Array<string>;
Logger.info('[SYNC ENGINE] fileInPendingPaths', fileInPendingPaths);

await this.container.fileSyncOrchestrator.run(fileInPendingPaths);
ipcRenderer.send('CHECK_SYNC');
} catch (error) {
Expand Down
8 changes: 8 additions & 0 deletions src/apps/sync-engine/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ async function setUp() {
Logger.info('[SYNC ENGINE] sync engine updated successfully');
});

ipcRenderer.on('FALLBACK_SYNC_ENGINE_PROCESS', async () => {
Logger.info('[SYNC ENGINE] Fallback sync engine');

await bindings.polling();

Logger.info('[SYNC ENGINE] sync engine fallback successfully');
});

ipcRenderer.on('STOP_AND_CLEAR_SYNC_ENGINE_PROCESS', async (event) => {
Logger.info('[SYNC ENGINE] Stopping and clearing sync engine');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,16 @@ export class FileCheckerStatusInRoot {

const ps = placeholderStatus.pinState;
const ss = placeholderStatus.syncState;
const status =
const notSynced =
ps &&
ss &&
ps !== PinState.AlwaysLocal &&
ps !== PinState.OnlineOnly &&
ss !== SyncState.InSync;

if (status) {
if (notSynced) {
Logger.debug(
`[File Checker Status In Root] item ${path} with status: ${status}`
`[File Checker Status In Root] item ${path} with status: ${notSynced}`
);
finalStatus = 'SYNC_PENDING';
break;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
import { MonitorFn, PollingMonitor } from '../domain/PollingMonitor';
import { ipcRenderer } from 'electron';
import Logger from 'electron-log';

export class PollingMonitorStart {
constructor(private readonly polling: PollingMonitor) {}
run(fn: MonitorFn) {
return this.polling.start(fn);
Logger.info('[START FALLBAK] Starting fallback sync...');

const permission = this.permissionFn.bind(this);
return this.polling.start(fn, permission);
}

private async permissionFn() {
const isSyncing = await ipcRenderer.invoke('CHECK_SYNC_IN_PROGRESS');
Logger.info('[START FALLBAK] Not permitted to start fallback sync: ', isSyncing);

const isPermitted = !isSyncing;
return isPermitted;
}
}
18 changes: 14 additions & 4 deletions src/context/virtual-drive/shared/domain/PollingMonitor.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export type MonitorFn = () => Promise<void>;
export type PermissionFn = () => Promise<boolean>;
export class PollingMonitor {
constructor(private readonly delay: number) {}

Expand All @@ -11,16 +12,25 @@ export class PollingMonitor {
}
}

private setTimeout(fn: MonitorFn) {
private setTimeout(fn: MonitorFn, permissionFn: PermissionFn) {
this.clearTimeout();
this.timeout = setTimeout(async () => {
if (!(await permissionFn())) {
// wait for the next interval
this.repeatDelay(fn, permissionFn);
return;
}
await fn();
this.setTimeout(fn);
this.repeatDelay(fn, permissionFn);
}, this.delay);
}

start(fn: MonitorFn) {
this.setTimeout(fn);
private repeatDelay(fn: MonitorFn, runPermissionFn: PermissionFn) {
this.setTimeout(fn, runPermissionFn);
}

start(fn: MonitorFn, runPermissionFn: PermissionFn) {
this.setTimeout(fn, runPermissionFn);
}

stop() {
Expand Down

0 comments on commit f280744

Please sign in to comment.