UNPKG

@sussudio/platform

Version:

Internal APIs for VS Code's service injection the base services.

355 lines (354 loc) 13.1 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? (desc = Object.getOwnPropertyDescriptor(target, key)) : desc, d; if (typeof Reflect === 'object' && typeof Reflect.decorate === 'function') r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if ((d = decorators[i])) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); }; }; import { VSBuffer } from '@sussudio/base/common/buffer.mjs'; import { IConfigurationService } from '../../configuration/common/configuration.mjs'; import { IEnvironmentService } from '../../environment/common/environment.mjs'; import { IFileService } from '../../files/common/files.mjs'; import { IStorageService } from '../../storage/common/storage.mjs'; import { ITelemetryService } from '../../telemetry/common/telemetry.mjs'; import { IUriIdentityService } from '../../uriIdentity/common/uriIdentity.mjs'; import { IUserDataProfilesService } from '../../userDataProfile/common/userDataProfile.mjs'; import { AbstractFileSynchroniser, AbstractInitializer } from './abstractSynchronizer.mjs'; import { IUserDataSyncBackupStoreService, IUserDataSyncLogService, IUserDataSyncEnablementService, IUserDataSyncStoreService, USER_DATA_SYNC_SCHEME, } from './userDataSync.mjs'; export function getTasksContentFromSyncContent(syncContent, logService) { try { const parsed = JSON.parse(syncContent); return parsed.tasks ?? null; } catch (e) { logService.error(e); return null; } } let TasksSynchroniser = class TasksSynchroniser extends AbstractFileSynchroniser { version = 1; previewResource = this.extUri.joinPath(this.syncPreviewFolder, 'tasks.json'); baseResource = this.previewResource.with({ scheme: USER_DATA_SYNC_SCHEME, authority: 'base' }); localResource = this.previewResource.with({ scheme: USER_DATA_SYNC_SCHEME, authority: 'local' }); remoteResource = this.previewResource.with({ scheme: USER_DATA_SYNC_SCHEME, authority: 'remote' }); acceptedResource = this.previewResource.with({ scheme: USER_DATA_SYNC_SCHEME, authority: 'accepted' }); constructor( profile, collection, userDataSyncStoreService, userDataSyncBackupStoreService, logService, configurationService, userDataSyncEnablementService, fileService, environmentService, storageService, telemetryService, uriIdentityService, ) { super( profile.tasksResource, { syncResource: 'tasks' /* SyncResource.Tasks */, profile }, collection, fileService, environmentService, storageService, userDataSyncStoreService, userDataSyncBackupStoreService, userDataSyncEnablementService, telemetryService, logService, configurationService, uriIdentityService, ); } async generateSyncPreview( remoteUserData, lastSyncUserData, isRemoteDataFromCurrentMachine, userDataSyncConfiguration, ) { const remoteContent = remoteUserData.syncData ? getTasksContentFromSyncContent(remoteUserData.syncData.content, this.logService) : null; // Use remote data as last sync data if last sync data does not exist and remote data is from same machine lastSyncUserData = lastSyncUserData === null && isRemoteDataFromCurrentMachine ? remoteUserData : lastSyncUserData; const lastSyncContent = lastSyncUserData?.syncData ? getTasksContentFromSyncContent(lastSyncUserData.syncData.content, this.logService) : null; // Get file content last to get the latest const fileContent = await this.getLocalFileContent(); let content = null; let hasLocalChanged = false; let hasRemoteChanged = false; let hasConflicts = false; if (remoteUserData.syncData) { const localContent = fileContent ? fileContent.value.toString() : null; if ( !lastSyncContent || // First time sync lastSyncContent !== localContent || // Local has forwarded lastSyncContent !== remoteContent // Remote has forwarded ) { this.logService.trace(`${this.syncResourceLogLabel}: Merging remote tasks with local tasks...`); const result = merge(localContent, remoteContent, lastSyncContent); content = result.content; hasConflicts = result.hasConflicts; hasLocalChanged = result.hasLocalChanged; hasRemoteChanged = result.hasRemoteChanged; } } // First time syncing to remote else if (fileContent) { this.logService.trace( `${this.syncResourceLogLabel}: Remote tasks does not exist. Synchronizing tasks for the first time.`, ); content = fileContent.value.toString(); hasRemoteChanged = true; } const previewResult = { content: hasConflicts ? lastSyncContent : content, localChange: hasLocalChanged ? fileContent ? 2 /* Change.Modified */ : 1 /* Change.Added */ : 0 /* Change.None */, remoteChange: hasRemoteChanged ? 2 /* Change.Modified */ : 0 /* Change.None */, hasConflicts, }; const localContent = fileContent ? fileContent.value.toString() : null; return [ { fileContent, baseResource: this.baseResource, baseContent: lastSyncContent, localResource: this.localResource, localContent, localChange: previewResult.localChange, remoteResource: this.remoteResource, remoteContent, remoteChange: previewResult.remoteChange, previewResource: this.previewResource, previewResult, acceptedResource: this.acceptedResource, }, ]; } async hasRemoteChanged(lastSyncUserData) { const lastSyncContent = lastSyncUserData?.syncData ? getTasksContentFromSyncContent(lastSyncUserData.syncData.content, this.logService) : null; if (lastSyncContent === null) { return true; } const fileContent = await this.getLocalFileContent(); const localContent = fileContent ? fileContent.value.toString() : null; const result = merge(localContent, lastSyncContent, lastSyncContent); return result.hasLocalChanged || result.hasRemoteChanged; } async getMergeResult(resourcePreview, token) { return resourcePreview.previewResult; } async getAcceptResult(resourcePreview, resource, content, token) { /* Accept local resource */ if (this.extUri.isEqual(resource, this.localResource)) { return { content: resourcePreview.fileContent ? resourcePreview.fileContent.value.toString() : null, localChange: 0 /* Change.None */, remoteChange: 2 /* Change.Modified */, }; } /* Accept remote resource */ if (this.extUri.isEqual(resource, this.remoteResource)) { return { content: resourcePreview.remoteContent, localChange: 2 /* Change.Modified */, remoteChange: 0 /* Change.None */, }; } /* Accept preview resource */ if (this.extUri.isEqual(resource, this.previewResource)) { if (content === undefined) { return { content: resourcePreview.previewResult.content, localChange: resourcePreview.previewResult.localChange, remoteChange: resourcePreview.previewResult.remoteChange, }; } else { return { content, localChange: 2 /* Change.Modified */, remoteChange: 2 /* Change.Modified */, }; } } throw new Error(`Invalid Resource: ${resource.toString()}`); } async applyResult(remoteUserData, lastSyncUserData, resourcePreviews, force) { const { fileContent } = resourcePreviews[0][0]; const { content, localChange, remoteChange } = resourcePreviews[0][1]; if (localChange === 0 /* Change.None */ && remoteChange === 0 /* Change.None */) { this.logService.info(`${this.syncResourceLogLabel}: No changes found during synchronizing tasks.`); } if (localChange !== 0 /* Change.None */) { this.logService.trace(`${this.syncResourceLogLabel}: Updating local tasks...`); if (fileContent) { await this.backupLocal(JSON.stringify(this.toTasksSyncContent(fileContent.value.toString()))); } if (content) { await this.updateLocalFileContent(content, fileContent, force); } else { await this.deleteLocalFile(); } this.logService.info(`${this.syncResourceLogLabel}: Updated local tasks`); } if (remoteChange !== 0 /* Change.None */) { this.logService.trace(`${this.syncResourceLogLabel}: Updating remote tasks...`); const remoteContents = JSON.stringify(this.toTasksSyncContent(content)); remoteUserData = await this.updateRemoteUserData(remoteContents, force ? null : remoteUserData.ref); this.logService.info(`${this.syncResourceLogLabel}: Updated remote tasks`); } // Delete the preview try { await this.fileService.del(this.previewResource); } catch (e) { /* ignore */ } if (lastSyncUserData?.ref !== remoteUserData.ref) { this.logService.trace(`${this.syncResourceLogLabel}: Updating last synchronized tasks...`); await this.updateLastSyncUserData(remoteUserData); this.logService.info(`${this.syncResourceLogLabel}: Updated last synchronized tasks`); } } async hasLocalData() { return this.fileService.exists(this.file); } async resolveContent(uri) { if ( this.extUri.isEqual(this.remoteResource, uri) || this.extUri.isEqual(this.baseResource, uri) || this.extUri.isEqual(this.localResource, uri) || this.extUri.isEqual(this.acceptedResource, uri) ) { return this.resolvePreviewContent(uri); } return null; } toTasksSyncContent(tasks) { return tasks ? { tasks } : {}; } }; TasksSynchroniser = __decorate( [ __param(2, IUserDataSyncStoreService), __param(3, IUserDataSyncBackupStoreService), __param(4, IUserDataSyncLogService), __param(5, IConfigurationService), __param(6, IUserDataSyncEnablementService), __param(7, IFileService), __param(8, IEnvironmentService), __param(9, IStorageService), __param(10, ITelemetryService), __param(11, IUriIdentityService), ], TasksSynchroniser, ); export { TasksSynchroniser }; let TasksInitializer = class TasksInitializer extends AbstractInitializer { tasksResource = this.userDataProfilesService.defaultProfile.tasksResource; constructor( fileService, userDataProfilesService, environmentService, logService, storageService, uriIdentityService, ) { super( 'tasks' /* SyncResource.Tasks */, userDataProfilesService, environmentService, logService, fileService, storageService, uriIdentityService, ); } async doInitialize(remoteUserData) { const tasksContent = remoteUserData.syncData ? getTasksContentFromSyncContent(remoteUserData.syncData.content, this.logService) : null; if (!tasksContent) { this.logService.info('Skipping initializing tasks because remote tasks does not exist.'); return; } const isEmpty = await this.isEmpty(); if (!isEmpty) { this.logService.info('Skipping initializing tasks because local tasks exist.'); return; } await this.fileService.writeFile(this.tasksResource, VSBuffer.fromString(tasksContent)); await this.updateLastSyncUserData(remoteUserData); } async isEmpty() { return this.fileService.exists(this.tasksResource); } }; TasksInitializer = __decorate( [ __param(0, IFileService), __param(1, IUserDataProfilesService), __param(2, IEnvironmentService), __param(3, IUserDataSyncLogService), __param(4, IStorageService), __param(5, IUriIdentityService), ], TasksInitializer, ); export { TasksInitializer }; function merge(originalLocalContent, originalRemoteContent, baseContent) { /* no changes */ if (originalLocalContent === null && originalRemoteContent === null && baseContent === null) { return { content: null, hasLocalChanged: false, hasRemoteChanged: false, hasConflicts: false }; } /* no changes */ if (originalLocalContent === originalRemoteContent) { return { content: null, hasLocalChanged: false, hasRemoteChanged: false, hasConflicts: false }; } const localForwarded = baseContent !== originalLocalContent; const remoteForwarded = baseContent !== originalRemoteContent; /* no changes */ if (!localForwarded && !remoteForwarded) { return { content: null, hasLocalChanged: false, hasRemoteChanged: false, hasConflicts: false }; } /* local has changed and remote has not */ if (localForwarded && !remoteForwarded) { return { content: originalLocalContent, hasRemoteChanged: true, hasLocalChanged: false, hasConflicts: false }; } /* remote has changed and local has not */ if (remoteForwarded && !localForwarded) { return { content: originalRemoteContent, hasLocalChanged: true, hasRemoteChanged: false, hasConflicts: false }; } return { content: originalLocalContent, hasLocalChanged: true, hasRemoteChanged: true, hasConflicts: true }; }