Move user data sync to shared process

This commit is contained in:
Sandeep Somavarapu
2019-09-17 23:37:53 +02:00
parent b920133a68
commit 927f8d87a8
18 changed files with 264 additions and 100 deletions

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IUserDataSyncService, SyncStatus, USER_DATA_PREVIEW_SCHEME } from 'vs/platform/userDataSync/common/userDataSync';
import { IUserDataSyncService, SyncStatus, SyncSource } from 'vs/platform/userDataSync/common/userDataSync';
import { localize } from 'vs/nls';
import { Disposable, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
@@ -16,7 +16,6 @@ import { MenuRegistry, MenuId, IMenuItem } from 'vs/platform/actions/common/acti
import { RawContextKey, IContextKeyService, IContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { IActivityService, IBadge, NumberBadge, ProgressBadge } from 'vs/workbench/services/activity/common/activity';
import { GLOBAL_ACTIVITY_ID } from 'vs/workbench/common/activity';
import { timeout } from 'vs/base/common/async';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { URI } from 'vs/base/common/uri';
import { registerAndGetAmdImageURL } from 'vs/base/common/amd';
@@ -25,8 +24,8 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { Event } from 'vs/base/common/event';
import { IHistoryService } from 'vs/workbench/services/history/common/history';
import { IFileService } from 'vs/platform/files/common/files';
import { InMemoryFileSystemProvider } from 'vs/workbench/services/userData/common/inMemoryUserDataProvider';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { isEqual } from 'vs/base/common/resources';
const CONTEXT_SYNC_STATE = new RawContextKey<string>('syncStatus', SyncStatus.Uninitialized);
@@ -46,39 +45,6 @@ Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration)
}
});
class UserDataSyncContribution extends Disposable implements IWorkbenchContribution {
constructor(
@IFileService fileService: IFileService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IUserDataSyncService private readonly userDataSyncService: IUserDataSyncService,
) {
super();
this._register(fileService.registerProvider(USER_DATA_PREVIEW_SCHEME, new InMemoryFileSystemProvider()));
this.sync(true);
this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('userConfiguration.enableSync') && this.configurationService.getValue<boolean>('userConfiguration.enableSync'))
(() => this.sync(true)));
// Sync immediately if there is a local change.
this._register(Event.debounce(this.userDataSyncService.onDidChangeLocal, () => undefined, 500)(() => this.sync(false)));
}
private async sync(loop: boolean): Promise<void> {
if (this.configurationService.getValue<boolean>('userConfiguration.enableSync')) {
try {
await this.userDataSyncService.sync();
} catch (e) {
// Ignore errors
}
if (loop) {
await timeout(1000 * 5); // Loop sync for every 5s.
this.sync(loop);
}
}
}
}
const SYNC_PUSH_LIGHT_ICON_URI = URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/userData/browser/media/sync-push-light.svg`));
const SYNC_PUSH_DARK_ICON_URI = URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/userData/browser/media/sync-push-dark.svg`));
class SyncActionsContribution extends Disposable implements IWorkbenchContribution {
@@ -96,6 +62,7 @@ class SyncActionsContribution extends Disposable implements IWorkbenchContributi
@IEditorService private readonly editorService: IEditorService,
@ITextFileService private readonly textFileService: ITextFileService,
@IHistoryService private readonly historyService: IHistoryService,
@IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService,
) {
super();
this.syncEnablementContext = CONTEXT_SYNC_STATE.bindTo(contextKeyService);
@@ -142,17 +109,14 @@ class SyncActionsContribution extends Disposable implements IWorkbenchContributi
private async continueSync(): Promise<void> {
// Get the preview editor
const editorInput = this.editorService.editors.filter(input => {
const resource = input.getResource();
return resource && resource.scheme === USER_DATA_PREVIEW_SCHEME;
})[0];
const editorInput = this.editorService.editors.filter(input => isEqual(input.getResource(), this.workbenchEnvironmentService.settingsSyncPreviewResource))[0];
// Save the preview
if (editorInput && editorInput.isDirty()) {
await this.textFileService.save(editorInput.getResource()!);
}
try {
// Continue Sync
await this.userDataSyncService.continueSync();
await this.userDataSyncService.sync(true);
} catch (error) {
this.notificationService.error(error);
return;
@@ -164,10 +128,9 @@ class SyncActionsContribution extends Disposable implements IWorkbenchContributi
}
private async handleConflicts(): Promise<void> {
const resource = this.userDataSyncService.conflicts;
if (resource) {
if (this.userDataSyncService.conflictsSource === SyncSource.Settings ) {
const resourceInput = {
resource,
resource: this.workbenchEnvironmentService.settingsSyncPreviewResource,
options: {
preserveFocus: false,
pinned: false,
@@ -237,11 +200,10 @@ class SyncActionsContribution extends Disposable implements IWorkbenchContributi
},
group: 'navigation',
order: 1,
when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.isEqualTo(SyncStatus.HasConflicts), ResourceContextKey.Scheme.isEqualTo(USER_DATA_PREVIEW_SCHEME)),
when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.isEqualTo(SyncStatus.HasConflicts), ResourceContextKey.Resource.isEqualTo(this.workbenchEnvironmentService.settingsSyncPreviewResource.toString())),
});
}
}
const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
workbenchRegistry.registerWorkbenchContribution(SyncActionsContribution, LifecyclePhase.Starting);
workbenchRegistry.registerWorkbenchContribution(UserDataSyncContribution, LifecyclePhase.Eventually);

View File

@@ -0,0 +1,24 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { ISettingsMergeService } from 'vs/platform/userDataSync/common/userDataSync';
import { Registry } from 'vs/platform/registry/common/platform';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
import { SettingsMergeChannel } from 'vs/platform/userDataSync/common/settingsSyncIpc';
class UserDataSyncServicesContribution implements IWorkbenchContribution {
constructor(
@ISettingsMergeService settingsMergeService: ISettingsMergeService,
@ISharedProcessService sharedProcessService: ISharedProcessService,
) {
sharedProcessService.registerChannel('settingsMerge', new SettingsMergeChannel(settingsMergeService));
}
}
const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
workbenchRegistry.registerWorkbenchContribution(UserDataSyncServicesContribution, LifecyclePhase.Starting);

View File

@@ -84,6 +84,7 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment
this.configuration.machineId = generateUuid();
this.userRoamingDataHome = URI.file('/User').with({ scheme: Schemas.userData });
this.settingsResource = joinPath(this.userRoamingDataHome, 'settings.json');
this.settingsSyncPreviewResource = joinPath(this.userRoamingDataHome, '.settings.json');
this.keybindingsResource = joinPath(this.userRoamingDataHome, 'keybindings.json');
this.keyboardLayoutResource = joinPath(this.userRoamingDataHome, 'keyboardLayout.json');
this.localeResource = joinPath(this.userRoamingDataHome, 'locale.json');
@@ -141,6 +142,7 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment
appSettingsHome: URI;
userRoamingDataHome: URI;
settingsResource: URI;
settingsSyncPreviewResource: URI;
keybindingsResource: URI;
keyboardLayoutResource: URI;
localeResource: URI;

View File

@@ -0,0 +1,49 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { SyncStatus, SyncSource, IUserDataSyncService } from 'vs/platform/userDataSync/common/userDataSync';
import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
import { Disposable } from 'vs/base/common/lifecycle';
import { Emitter, Event } from 'vs/base/common/event';
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
export class UserDataSyncService extends Disposable implements IUserDataSyncService {
_serviceBrand: undefined;
private readonly channel: IChannel;
private _status: SyncStatus = SyncStatus.Uninitialized;
get status(): SyncStatus { return this._status; }
private _onDidChangeStatus: Emitter<SyncStatus> = this._register(new Emitter<SyncStatus>());
readonly onDidChangeStatus: Event<SyncStatus> = this._onDidChangeStatus.event;
get onDidChangeLocal(): Event<void> { return this.channel.listen('onDidChangeLocal'); }
private _conflictsSource: SyncSource | null = null;
get conflictsSource(): SyncSource | null { return this._conflictsSource; }
constructor(
@ISharedProcessService sharedProcessService: ISharedProcessService
) {
super();
this.channel = sharedProcessService.getChannel('userDataSync');
this._register(this.channel.listen<SyncStatus>('onDidChangeStatus')(status => this.updateStatus(status)));
}
sync(_continue?: boolean): Promise<boolean> {
return this.channel.call('sync', [_continue]);
}
private async updateStatus(status: SyncStatus): Promise<void> {
this._conflictsSource = await this.channel.call<SyncSource>('getConflictsSource');
this._status = status;
this._onDidChangeStatus.fire(status);
}
}
registerSingleton(IUserDataSyncService, UserDataSyncService);

View File

@@ -79,7 +79,7 @@ import 'vs/workbench/services/label/common/labelService';
import 'vs/workbench/services/extensionManagement/common/extensionEnablementService';
import 'vs/workbench/services/notification/common/notificationService';
import 'vs/workbench/services/extensions/common/staticExtensions';
import 'vs/workbench/services/userData/common/settingsMergeService';
import 'vs/workbench/services/userDataSync/common/settingsMergeService';
import 'vs/workbench/services/workspace/browser/workspaceEditingService';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
@@ -106,9 +106,6 @@ import { IDownloadService } from 'vs/platform/download/common/download';
import { DownloadService } from 'vs/platform/download/common/downloadService';
import { OpenerService } from 'vs/editor/browser/services/openerService';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { IUserDataSyncStoreService, IUserDataSyncService } from 'vs/platform/userDataSync/common/userDataSync';
import { UserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSyncStoreService';
import { UserDataSyncService } from 'vs/platform/userDataSync/common/userDataSyncService';
registerSingleton(IExtensionGalleryService, ExtensionGalleryService, true);
registerSingleton(IContextViewService, ContextViewService, true);
@@ -122,8 +119,6 @@ registerSingleton(ITextResourceConfigurationService, TextResourceConfigurationSe
registerSingleton(IMenuService, MenuService, true);
registerSingleton(IDownloadService, DownloadService, true);
registerSingleton(IOpenerService, OpenerService, true);
registerSingleton(IUserDataSyncStoreService, UserDataSyncStoreService);
registerSingleton(IUserDataSyncService, UserDataSyncService);
//#endregion
@@ -259,7 +254,7 @@ import 'vs/workbench/contrib/experiments/browser/experiments.contribution';
// Send a Smile
import 'vs/workbench/contrib/feedback/browser/feedback.contribution';
// User Data
import 'vs/workbench/contrib/userData/browser/userData.contribution';
// User Data Sync
import 'vs/workbench/contrib/userDataSync/browser/userDataSync.contribution';
//#endregion

View File

@@ -49,6 +49,7 @@ import 'vs/workbench/services/backup/node/backupFileService';
import 'vs/workbench/services/credentials/node/credentialsService';
import 'vs/workbench/services/url/electron-browser/urlService';
import 'vs/workbench/services/workspace/electron-browser/workspacesService';
import 'vs/workbench/services/userDataSync/electron-browser/userDataSyncService';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
@@ -137,4 +138,7 @@ import 'vs/workbench/contrib/issue/electron-browser/issue.contribution';
// Tasks
import 'vs/workbench/contrib/tasks/electron-browser/taskService';
// User Data Sync
import 'vs/workbench/contrib/userDataSync/electron-browser/userDataSync.contribution';
//#endregion

View File

@@ -61,6 +61,9 @@ import { BackupFileService } from 'vs/workbench/services/backup/common/backupFil
import { ExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagementService';
import { ITunnelService } from 'vs/platform/remote/common/tunnel';
import { NoOpTunnelService } from 'vs/platform/remote/common/tunnelService';
import { IUserDataSyncStoreService, IUserDataSyncService } from 'vs/platform/userDataSync/common/userDataSync';
import { UserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSyncStoreService';
import { UserDataSyncService } from 'vs/platform/userDataSync/common/userDataSyncService';
registerSingleton(IRequestService, RequestService, true);
registerSingleton(IExtensionManagementService, ExtensionManagementService);
@@ -70,6 +73,8 @@ registerSingleton(IAccessibilityService, BrowserAccessibilityService, true);
registerSingleton(ILifecycleService, BrowserLifecycleService);
registerSingleton(IContextMenuService, ContextMenuService);
registerSingleton(ITunnelService, NoOpTunnelService, true);
registerSingleton(IUserDataSyncStoreService, UserDataSyncStoreService);
registerSingleton(IUserDataSyncService, UserDataSyncService);
//#endregion