diff options
author | Sandeep Somavarapu <sasomava@microsoft.com> | 2022-09-13 17:02:29 +0300 |
---|---|---|
committer | Sandeep Somavarapu <sasomava@microsoft.com> | 2022-09-13 17:02:29 +0300 |
commit | d0d5cbd82f4944741a40ff2784dc86f296825a23 (patch) | |
tree | 9004282f7b08baf9c0a211b3f6d6b73f67c2f1dd /src | |
parent | f0fc8a0a63920ed34ccbd70ccb43e2048cad0780 (diff) |
feedback
- move profile storage serice into userdatasync layer
- let storage service tells if the given profile is used or not
Diffstat (limited to 'src')
17 files changed, 155 insertions, 143 deletions
diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index 9e8abb0a993..5638094882a 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -106,8 +106,8 @@ import { UserDataProfilesNativeService } from 'vs/platform/userDataProfile/elect import { SharedProcessRequestService } from 'vs/platform/request/electron-browser/sharedProcessRequestService'; import { OneDataSystemAppender } from 'vs/platform/telemetry/node/1dsAppender'; import { UserDataProfilesCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/userDataProfilesCleaner'; -import { IProfileStorageService } from 'vs/platform/storage/common/profileStorageService'; -import { ProfileStorageService } from 'vs/platform/storage/electron-sandbox/profileStorageService'; +import { UserDataSyncProfilesStorageService } from 'vs/platform/userDataSync/electron-sandbox/userDataSyncProfilesStorageService'; +import { IUserDataSyncProfilesStorageService } from 'vs/platform/userDataSync/common/userDataSyncProfilesStorageService'; class SharedProcessMain extends Disposable { @@ -327,9 +327,6 @@ class SharedProcessMain extends Disposable { // Diagnostics services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService, undefined, false /* proxied to other processes */)); - // Profile Storage - services.set(IProfileStorageService, new SyncDescriptor(ProfileStorageService, undefined, true)); - // Settings Sync services.set(IUserDataSyncAccountService, new SyncDescriptor(UserDataSyncAccountService, undefined, true)); services.set(IUserDataSyncLogService, new SyncDescriptor(UserDataSyncLogService, undefined, true)); @@ -343,6 +340,7 @@ class SharedProcessMain extends Disposable { services.set(IUserDataSyncBackupStoreService, new SyncDescriptor(UserDataSyncBackupStoreService, undefined, false /* Eagerly cleans up old backups */)); services.set(IUserDataSyncEnablementService, new SyncDescriptor(UserDataSyncEnablementService, undefined, true)); services.set(IUserDataSyncService, new SyncDescriptor(UserDataSyncService, undefined, false /* Initializes the Sync State */)); + services.set(IUserDataSyncProfilesStorageService, new SyncDescriptor(UserDataSyncProfilesStorageService, undefined, true)); const ptyHostService = new PtyHostService({ graceTime: LocalReconnectConstants.GraceTime, diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 1e328b38b3c..68053657b4c 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -69,7 +69,7 @@ import { getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts'; import { SharedProcess } from 'vs/platform/sharedProcess/electron-main/sharedProcess'; import { ISignService } from 'vs/platform/sign/common/sign'; import { IStateMainService } from 'vs/platform/state/electron-main/state'; -import { ProfileStorageChangesListenerChannel, StorageDatabaseChannel } from 'vs/platform/storage/electron-main/storageIpc'; +import { StorageDatabaseChannel } from 'vs/platform/storage/electron-main/storageIpc'; import { ApplicationStorageMainService, IApplicationStorageMainService, IStorageMainService, StorageMainService } from 'vs/platform/storage/electron-main/storageMainService'; import { resolveCommonProperties } from 'vs/platform/telemetry/common/commonProperties'; import { ITelemetryService, machineIdKey, TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; @@ -111,6 +111,7 @@ import { ExtensionsScannerService } from 'vs/platform/extensionManagement/node/e import { UserDataTransientProfilesHandler } from 'vs/platform/userDataProfile/electron-main/userDataTransientProfilesHandler'; import { RunOnceScheduler, runWhenIdle } from 'vs/base/common/async'; import { IUserDataProfile } from 'vs/platform/userDataProfile/common/userDataProfile'; +import { ProfileStorageChangesListenerChannel } from 'vs/platform/userDataSync/electron-main/userDataSyncProfilesStorageIpc'; /** * The main VS Code application. There will only ever be one instance, diff --git a/src/vs/editor/contrib/find/test/browser/findController.test.ts b/src/vs/editor/contrib/find/test/browser/findController.test.ts index 95a2995beb2..0fb8aecd112 100644 --- a/src/vs/editor/contrib/find/test/browser/findController.test.ts +++ b/src/vs/editor/contrib/find/test/browser/findController.test.ts @@ -82,7 +82,7 @@ suite('FindController', async () => { keys: () => [], log: () => { }, switch: () => { throw new Error(); }, - getProfileStorageProfile() { return undefined; } + isProfileStorageFor() { return false; } } as IStorageService); if (platform.isMacintosh) { @@ -514,7 +514,7 @@ suite('FindController query options persistence', async () => { keys: () => [], log: () => { }, switch: () => { throw new Error(); }, - getProfileStorageProfile() { return undefined; } + isProfileStorageFor() { return false; } } as IStorageService); test('matchCase', async () => { diff --git a/src/vs/editor/contrib/multicursor/test/browser/multicursor.test.ts b/src/vs/editor/contrib/multicursor/test/browser/multicursor.test.ts index 6d6081184f5..a4fcd1f449d 100644 --- a/src/vs/editor/contrib/multicursor/test/browser/multicursor.test.ts +++ b/src/vs/editor/contrib/multicursor/test/browser/multicursor.test.ts @@ -99,7 +99,7 @@ suite('Multicursor selection', () => { flush: () => Promise.resolve(undefined), isNew: () => true, keys: () => [], - getProfileStorageProfile() { return undefined; } + isProfileStorageFor() { return false; } } as IStorageService); test('issue #8817: Cursor position changes when you cancel multicursor', () => { diff --git a/src/vs/platform/storage/common/storage.ts b/src/vs/platform/storage/common/storage.ts index 91491675ed7..0cc886a9fdf 100644 --- a/src/vs/platform/storage/common/storage.ts +++ b/src/vs/platform/storage/common/storage.ts @@ -141,9 +141,9 @@ export interface IStorageService { log(): void; /** - * Returns the profile used for the profile storage + * Returns true if the given profile is used for profile storage */ - getProfileStorageProfile(): IUserDataProfile | undefined; + isProfileStorageFor(profile: IUserDataProfile): boolean; /** * Switch storage to another workspace or profile. Optionally preserve the @@ -617,7 +617,7 @@ export abstract class AbstractStorageService extends Disposable implements IStor protected abstract switchToProfile(toProfile: IUserDataProfile, preserveData: boolean): Promise<void>; protected abstract switchToWorkspace(toWorkspace: IAnyWorkspaceIdentifier | IUserDataProfile, preserveData: boolean): Promise<void>; - abstract getProfileStorageProfile(): IUserDataProfile | undefined; + abstract isProfileStorageFor(profile: IUserDataProfile): boolean; } export function isProfileUsingDefaultStorage(profile: IUserDataProfile): boolean { @@ -670,8 +670,8 @@ export class InMemoryStorageService extends AbstractStorageService { // no-op when in-memory } - getProfileStorageProfile(): IUserDataProfile | undefined { - return undefined; + isProfileStorageFor(profiile: IUserDataProfile): boolean { + return false; } } diff --git a/src/vs/platform/storage/electron-main/storageIpc.ts b/src/vs/platform/storage/electron-main/storageIpc.ts index e7e0b2874a0..2f0725e05fb 100644 --- a/src/vs/platform/storage/electron-main/storageIpc.ts +++ b/src/vs/platform/storage/electron-main/storageIpc.ts @@ -4,16 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import { Emitter, Event } from 'vs/base/common/event'; -import { Disposable, DisposableStore, IDisposable, MutableDisposable } from 'vs/base/common/lifecycle'; +import { Disposable } from 'vs/base/common/lifecycle'; import { revive } from 'vs/base/common/marshalling'; import { IServerChannel } from 'vs/base/parts/ipc/common/ipc'; import { ILogService } from 'vs/platform/log/common/log'; -import { IProfileStorageChanges, IProfileStorageValueChanges } from 'vs/platform/storage/common/profileStorageService'; -import { loadKeyTargets, StorageScope, TARGET_KEY } from 'vs/platform/storage/common/storage'; import { IBaseSerializableStorageRequest, ISerializableItemsChangeEvent, ISerializableUpdateRequest, Key, Value } from 'vs/platform/storage/common/storageIpc'; import { IStorageChangeEvent, IStorageMain } from 'vs/platform/storage/electron-main/storageMain'; import { IStorageMainService } from 'vs/platform/storage/electron-main/storageMainService'; -import { IUserDataProfile, IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; +import { IUserDataProfile } from 'vs/platform/userDataProfile/common/userDataProfile'; import { reviveIdentifier, IEmptyWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace'; export class StorageDatabaseChannel extends Disposable implements IServerChannel { @@ -158,95 +156,3 @@ export class StorageDatabaseChannel extends Disposable implements IServerChannel return storage; } } - -export class ProfileStorageChangesListenerChannel extends Disposable implements IServerChannel { - - private readonly _onDidChange: Emitter<IProfileStorageChanges>; - - constructor( - private readonly storageMainService: IStorageMainService, - private readonly userDataProfilesService: IUserDataProfilesService, - private readonly logService: ILogService - ) { - super(); - const disposable = this._register(new MutableDisposable<IDisposable>()); - this._onDidChange = this._register(new Emitter<IProfileStorageChanges>( - { - // Start listening to profile storage changes only when someone is listening - onFirstListenerAdd: () => disposable.value = this.registerStorageChangeListeners(), - // Stop listening to profile storage changes when no one is listening - onLastListenerRemove: () => disposable.value = undefined - } - )); - } - - private registerStorageChangeListeners(): IDisposable { - this.logService.debug('ProfileStorageChangesListenerChannel#registerStorageChangeListeners'); - const disposables = new DisposableStore(); - disposables.add(Event.debounce(this.storageMainService.applicationStorage.onDidChangeStorage, (keys: string[] | undefined, e) => { - if (keys) { - keys.push(e.key); - } else { - keys = [e.key]; - } - return keys; - }, 100)(keys => this.onDidChangeApplicationStorage(keys))); - disposables.add(Event.debounce(this.storageMainService.onDidChangeProfileStorageData, (changes: Map<string, { profile: IUserDataProfile; keys: string[]; storage: IStorageMain }> | undefined, e) => { - if (!changes) { - changes = new Map<string, { profile: IUserDataProfile; keys: string[]; storage: IStorageMain }>(); - } - let profileChanges = changes.get(e.profile.id); - if (!profileChanges) { - changes.set(e.profile.id, profileChanges = { profile: e.profile, keys: [], storage: e.storage }); - } - profileChanges.keys.push(e.key); - return changes; - }, 100)(keys => this.onDidChangeProfileStorage(keys))); - return disposables; - } - - private onDidChangeApplicationStorage(keys: string[]): void { - const targetChangedProfiles: IUserDataProfile[] = keys.includes(TARGET_KEY) ? [this.userDataProfilesService.defaultProfile] : []; - const profileStorageValueChanges: IProfileStorageValueChanges[] = []; - keys = keys.filter(key => key !== TARGET_KEY); - if (keys.length) { - const keyTargets = loadKeyTargets(this.storageMainService.applicationStorage.storage); - profileStorageValueChanges.push({ profile: this.userDataProfilesService.defaultProfile, changes: keys.map(key => ({ key, scope: StorageScope.PROFILE, target: keyTargets[key] })) }); - } - this.triggerEvents(targetChangedProfiles, profileStorageValueChanges); - } - - private onDidChangeProfileStorage(changes: Map<string, { profile: IUserDataProfile; keys: string[]; storage: IStorageMain }>): void { - const targetChangedProfiles: IUserDataProfile[] = []; - const profileStorageValueChanges = new Map<string, IProfileStorageValueChanges>(); - for (const [profileId, profileChanges] of changes.entries()) { - if (profileChanges.keys.includes(TARGET_KEY)) { - targetChangedProfiles.push(profileChanges.profile); - } - const keys = profileChanges.keys.filter(key => key !== TARGET_KEY); - if (keys.length) { - const keyTargets = loadKeyTargets(profileChanges.storage.storage); - profileStorageValueChanges.set(profileId, { profile: profileChanges.profile, changes: keys.map(key => ({ key, scope: StorageScope.PROFILE, target: keyTargets[key] })) }); - } - } - this.triggerEvents(targetChangedProfiles, [...profileStorageValueChanges.values()]); - } - - private triggerEvents(targetChanges: IUserDataProfile[], valueChanges: IProfileStorageValueChanges[]): void { - if (targetChanges.length || valueChanges.length) { - this._onDidChange.fire({ valueChanges, targetChanges }); - } - } - - listen(_: unknown, event: string, arg: IBaseSerializableStorageRequest): Event<any> { - switch (event) { - case 'onDidChange': return this._onDidChange.event; - } - throw new Error(`Event not found: ${event}`); - } - - async call(_: unknown, command: string): Promise<any> { - throw new Error(`Call not found: ${command}`); - } - -} diff --git a/src/vs/platform/storage/electron-main/storageMainService.ts b/src/vs/platform/storage/electron-main/storageMainService.ts index b0332ba9687..afdce9aa8a3 100644 --- a/src/vs/platform/storage/electron-main/storageMainService.ts +++ b/src/vs/platform/storage/electron-main/storageMainService.ts @@ -370,7 +370,7 @@ export class ApplicationStorageMainService extends AbstractStorageService implem throw new Error('Switching storage workspace is unsupported from main process'); } - getProfileStorageProfile(): never { + isProfileStorageFor(): never { throw new Error('Profile storage is unsupported from main process'); } } diff --git a/src/vs/platform/storage/electron-sandbox/storageService.ts b/src/vs/platform/storage/electron-sandbox/storageService.ts index aebdc9d8018..739030ae362 100644 --- a/src/vs/platform/storage/electron-sandbox/storageService.ts +++ b/src/vs/platform/storage/electron-sandbox/storageService.ts @@ -178,7 +178,7 @@ export class NativeStorageService extends AbstractStorageService { this.switchData(oldItems, this.workspaceStorage, StorageScope.WORKSPACE, preserveData); } - getProfileStorageProfile(): IUserDataProfile { - return this.profileStorageProfile; + isProfileStorageFor(profile: IUserDataProfile): boolean { + return this.profileStorageProfile.id === profile.id; } } diff --git a/src/vs/platform/userDataSync/common/globalStateSync.ts b/src/vs/platform/userDataSync/common/globalStateSync.ts index 8371dabb50d..1f7f2860565 100644 --- a/src/vs/platform/userDataSync/common/globalStateSync.ts +++ b/src/vs/platform/userDataSync/common/globalStateSync.ts @@ -28,7 +28,7 @@ import { merge } from 'vs/platform/userDataSync/common/globalStateMerge'; import { ALL_SYNC_RESOURCES, Change, createSyncHeaders, getEnablementKey, IGlobalState, IRemoteUserData, IStorageValue, ISyncData, ISyncResourceHandle, IUserData, IUserDataSyncBackupStoreService, IUserDataSynchroniser, IUserDataSyncLogService, IUserDataSyncEnablementService, IUserDataSyncStoreService, SyncResource, SYNC_SERVICE_URL_TYPE, UserDataSyncError, UserDataSyncErrorCode, UserDataSyncStoreType, USER_DATA_SYNC_SCHEME } from 'vs/platform/userDataSync/common/userDataSync'; import { UserDataSyncStoreClient } from 'vs/platform/userDataSync/common/userDataSyncStoreService'; import { IUserDataProfile, IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; -import { IProfileStorageService } from 'vs/platform/storage/common/profileStorageService'; +import { IUserDataSyncProfilesStorageService } from 'vs/platform/userDataSync/common/userDataSyncProfilesStorageService'; const argvStoragePrefx = 'globalState.argv.'; const argvProperties: string[] = ['locale']; @@ -77,7 +77,7 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs constructor( private readonly profile: IUserDataProfile, - @IProfileStorageService private readonly profileStorageService: IProfileStorageService, + @IUserDataSyncProfilesStorageService private readonly userDataSyncProfilesStorageService: IUserDataSyncProfilesStorageService, @IFileService fileService: IFileService, @IUserDataSyncStoreService userDataSyncStoreService: IUserDataSyncStoreService, @IUserDataSyncBackupStoreService userDataSyncBackupStoreService: IUserDataSyncBackupStoreService, @@ -95,7 +95,7 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs Event.any( /* Locale change */ Event.filter(fileService.onDidFilesChange, e => e.contains(this.environmentService.argvResource)), - Event.filter(this.profileStorageService.onDidChange, e => { + Event.filter(this.userDataSyncProfilesStorageService.onDidChange, e => { /* StorageTarget has changed in profile storage */ if (e.targetChanges.some(profile => this.profile.id === profile.id)) { return true; @@ -311,7 +311,7 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs storage[`${argvStoragePrefx}${argvProperty}`] = { version: 1, value: argvValue[argvProperty] }; } } - const storageData = await this.profileStorageService.readStorageData(this.profile); + const storageData = await this.userDataSyncProfilesStorageService.readStorageData(this.profile); for (const [key, value] of storageData) { if (value.value && value.target === StorageTarget.USER) { storage[key] = { version: 1, value: value.value }; @@ -335,7 +335,7 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs private async writeLocalGlobalState({ added, removed, updated }: { added: IStringDictionary<IStorageValue>; updated: IStringDictionary<IStorageValue>; removed: string[] }): Promise<void> { const argv: IStringDictionary<any> = {}; const updatedStorage = new Map<string, string | undefined>(); - const storageData = await this.profileStorageService.readStorageData(this.profile); + const storageData = await this.userDataSyncProfilesStorageService.readStorageData(this.profile); const handleUpdatedStorage = (keys: string[], storage?: IStringDictionary<IStorageValue>): void => { for (const key of keys) { if (key.startsWith(argvStoragePrefx)) { @@ -364,7 +364,7 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs } if (updatedStorage.size) { this.logService.trace(`${this.syncResourceLogLabel}: Updating global state...`); - await this.profileStorageService.updateStorageData(this.profile, updatedStorage, StorageTarget.USER); + await this.userDataSyncProfilesStorageService.updateStorageData(this.profile, updatedStorage, StorageTarget.USER); this.logService.info(`${this.syncResourceLogLabel}: Updated global state`, [...updatedStorage.keys()]); } } @@ -383,7 +383,7 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs } private async getStorageKeys(lastSyncGlobalState: IGlobalState | null): Promise<StorageKeys> { - const storageData = await this.profileStorageService.readStorageData(this.profile); + const storageData = await this.userDataSyncProfilesStorageService.readStorageData(this.profile); const user: string[] = [], machine: string[] = []; for (const [key, value] of storageData) { if (value.target === StorageTarget.USER) { diff --git a/src/vs/platform/storage/common/profileStorageService.ts b/src/vs/platform/userDataSync/common/userDataSyncProfilesStorageService.ts index 645a94c9308..f79a4f4a894 100644 --- a/src/vs/platform/storage/common/profileStorageService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncProfilesStorageService.ts @@ -25,8 +25,8 @@ export interface IStorageValue { readonly target: StorageTarget; } -export const IProfileStorageService = createDecorator<IProfileStorageService>('IProfileStorageService'); -export interface IProfileStorageService { +export const IUserDataSyncProfilesStorageService = createDecorator<IUserDataSyncProfilesStorageService>('IUserDataSyncProfilesStorageService'); +export interface IUserDataSyncProfilesStorageService { readonly _serviceBrand: undefined; /** @@ -49,7 +49,7 @@ export interface IProfileStorageService { updateStorageData(profile: IUserDataProfile, data: Map<string, string | undefined | null>, target: StorageTarget): Promise<void>; } -export abstract class AbstractProfileStorageService extends Disposable implements IProfileStorageService { +export abstract class AbstractUserDataSyncProfilesStorageService extends Disposable implements IUserDataSyncProfilesStorageService { _serviceBrand: undefined; @@ -63,7 +63,7 @@ export abstract class AbstractProfileStorageService extends Disposable implement async readStorageData(profile: IUserDataProfile): Promise<Map<string, IStorageValue>> { // Use current storage service if the profile is same - if (this.storageService.getProfileStorageProfile()?.id === profile.id) { + if (this.storageService.isProfileStorageFor(profile)) { return this.getItems(this.storageService); } @@ -80,7 +80,7 @@ export abstract class AbstractProfileStorageService extends Disposable implement async updateStorageData(profile: IUserDataProfile, data: Map<string, string | undefined | null>, target: StorageTarget): Promise<void> { // Use current storage service if the profile is same - if (this.storageService.getProfileStorageProfile()?.id === profile.id) { + if (this.storageService.isProfileStorageFor(profile)) { return this.writeItems(this.storageService, data, target); } @@ -147,5 +147,5 @@ class StorageService extends AbstractStorageService { protected getLogDetails(): string | undefined { return undefined; } protected async switchToProfile(): Promise<void> { } protected async switchToWorkspace(): Promise<void> { } - getProfileStorageProfile() { return undefined; } + isProfileStorageFor() { return false; } } diff --git a/src/vs/platform/userDataSync/electron-main/userDataSyncProfilesStorageIpc.ts b/src/vs/platform/userDataSync/electron-main/userDataSyncProfilesStorageIpc.ts new file mode 100644 index 00000000000..931cc8d69b4 --- /dev/null +++ b/src/vs/platform/userDataSync/electron-main/userDataSyncProfilesStorageIpc.ts @@ -0,0 +1,107 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Emitter, Event } from 'vs/base/common/event'; +import { Disposable, DisposableStore, IDisposable, MutableDisposable } from 'vs/base/common/lifecycle'; +import { IServerChannel } from 'vs/base/parts/ipc/common/ipc'; +import { ILogService } from 'vs/platform/log/common/log'; +import { IProfileStorageChanges, IProfileStorageValueChanges } from 'vs/platform/userDataSync/common/userDataSyncProfilesStorageService'; +import { loadKeyTargets, StorageScope, TARGET_KEY } from 'vs/platform/storage/common/storage'; +import { IBaseSerializableStorageRequest } from 'vs/platform/storage/common/storageIpc'; +import { IStorageMain } from 'vs/platform/storage/electron-main/storageMain'; +import { IStorageMainService } from 'vs/platform/storage/electron-main/storageMainService'; +import { IUserDataProfile, IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; + +export class ProfileStorageChangesListenerChannel extends Disposable implements IServerChannel { + + private readonly _onDidChange: Emitter<IProfileStorageChanges>; + + constructor( + private readonly storageMainService: IStorageMainService, + private readonly userDataProfilesService: IUserDataProfilesService, + private readonly logService: ILogService + ) { + super(); + const disposable = this._register(new MutableDisposable<IDisposable>()); + this._onDidChange = this._register(new Emitter<IProfileStorageChanges>( + { + // Start listening to profile storage changes only when someone is listening + onFirstListenerAdd: () => disposable.value = this.registerStorageChangeListeners(), + // Stop listening to profile storage changes when no one is listening + onLastListenerRemove: () => disposable.value = undefined + } + )); + } + + private registerStorageChangeListeners(): IDisposable { + this.logService.debug('ProfileStorageChangesListenerChannel#registerStorageChangeListeners'); + const disposables = new DisposableStore(); + disposables.add(Event.debounce(this.storageMainService.applicationStorage.onDidChangeStorage, (keys: string[] | undefined, e) => { + if (keys) { + keys.push(e.key); + } else { + keys = [e.key]; + } + return keys; + }, 100)(keys => this.onDidChangeApplicationStorage(keys))); + disposables.add(Event.debounce(this.storageMainService.onDidChangeProfileStorageData, (changes: Map<string, { profile: IUserDataProfile; keys: string[]; storage: IStorageMain }> | undefined, e) => { + if (!changes) { + changes = new Map<string, { profile: IUserDataProfile; keys: string[]; storage: IStorageMain }>(); + } + let profileChanges = changes.get(e.profile.id); + if (!profileChanges) { + changes.set(e.profile.id, profileChanges = { profile: e.profile, keys: [], storage: e.storage }); + } + profileChanges.keys.push(e.key); + return changes; + }, 100)(keys => this.onDidChangeProfileStorage(keys))); + return disposables; + } + + private onDidChangeApplicationStorage(keys: string[]): void { + const targetChangedProfiles: IUserDataProfile[] = keys.includes(TARGET_KEY) ? [this.userDataProfilesService.defaultProfile] : []; + const profileStorageValueChanges: IProfileStorageValueChanges[] = []; + keys = keys.filter(key => key !== TARGET_KEY); + if (keys.length) { + const keyTargets = loadKeyTargets(this.storageMainService.applicationStorage.storage); + profileStorageValueChanges.push({ profile: this.userDataProfilesService.defaultProfile, changes: keys.map(key => ({ key, scope: StorageScope.PROFILE, target: keyTargets[key] })) }); + } + this.triggerEvents(targetChangedProfiles, profileStorageValueChanges); + } + + private onDidChangeProfileStorage(changes: Map<string, { profile: IUserDataProfile; keys: string[]; storage: IStorageMain }>): void { + const targetChangedProfiles: IUserDataProfile[] = []; + const profileStorageValueChanges = new Map<string, IProfileStorageValueChanges>(); + for (const [profileId, profileChanges] of changes.entries()) { + if (profileChanges.keys.includes(TARGET_KEY)) { + targetChangedProfiles.push(profileChanges.profile); + } + const keys = profileChanges.keys.filter(key => key !== TARGET_KEY); + if (keys.length) { + const keyTargets = loadKeyTargets(profileChanges.storage.storage); + profileStorageValueChanges.set(profileId, { profile: profileChanges.profile, changes: keys.map(key => ({ key, scope: StorageScope.PROFILE, target: keyTargets[key] })) }); + } + } + this.triggerEvents(targetChangedProfiles, [...profileStorageValueChanges.values()]); + } + + private triggerEvents(targetChanges: IUserDataProfile[], valueChanges: IProfileStorageValueChanges[]): void { + if (targetChanges.length || valueChanges.length) { + this._onDidChange.fire({ valueChanges, targetChanges }); + } + } + + listen(_: unknown, event: string, arg: IBaseSerializableStorageRequest): Event<any> { + switch (event) { + case 'onDidChange': return this._onDidChange.event; + } + throw new Error(`Event not found: ${event}`); + } + + async call(_: unknown, command: string): Promise<any> { + throw new Error(`Call not found: ${command}`); + } + +} diff --git a/src/vs/platform/storage/electron-sandbox/profileStorageService.ts b/src/vs/platform/userDataSync/electron-sandbox/userDataSyncProfilesStorageService.ts index 5bd6019c497..c668af40dfd 100644 --- a/src/vs/platform/storage/electron-sandbox/profileStorageService.ts +++ b/src/vs/platform/userDataSync/electron-sandbox/userDataSyncProfilesStorageService.ts @@ -8,12 +8,12 @@ import { MutableDisposable } from 'vs/base/common/lifecycle'; import { IStorageDatabase } from 'vs/base/parts/storage/common/storage'; import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/services'; import { ILogService } from 'vs/platform/log/common/log'; -import { AbstractProfileStorageService, IProfileStorageChanges, IProfileStorageService } from 'vs/platform/storage/common/profileStorageService'; +import { AbstractUserDataSyncProfilesStorageService, IProfileStorageChanges, IUserDataSyncProfilesStorageService } from 'vs/platform/userDataSync/common/userDataSyncProfilesStorageService'; import { isProfileUsingDefaultStorage, IStorageService } from 'vs/platform/storage/common/storage'; import { ApplicationStorageDatabaseClient, ProfileStorageDatabaseClient } from 'vs/platform/storage/common/storageIpc'; import { IUserDataProfile, IUserDataProfilesService, reviveProfile } from 'vs/platform/userDataProfile/common/userDataProfile'; -export class ProfileStorageService extends AbstractProfileStorageService implements IProfileStorageService { +export class UserDataSyncProfilesStorageService extends AbstractUserDataSyncProfilesStorageService implements IUserDataSyncProfilesStorageService { private readonly _onDidChange: Emitter<IProfileStorageChanges>; readonly onDidChange: Event<IProfileStorageChanges>; diff --git a/src/vs/platform/userDataSync/test/common/userDataSyncClient.ts b/src/vs/platform/userDataSync/test/common/userDataSyncClient.ts index 4bcf4b48db3..c81de3f5134 100644 --- a/src/vs/platform/userDataSync/test/common/userDataSyncClient.ts +++ b/src/vs/platform/userDataSync/test/common/userDataSyncClient.ts @@ -43,8 +43,8 @@ import { UserDataSyncService } from 'vs/platform/userDataSync/common/userDataSyn import { UserDataSyncStoreManagementService, UserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSyncStoreService'; import { IUserDataProfile, IUserDataProfilesService, UserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; import { NullPolicyService } from 'vs/platform/policy/common/policy'; -import { IProfileStorageService } from 'vs/platform/storage/common/profileStorageService'; -import { TestProfileStorageService } from 'vs/platform/storage/test/common/profileStorageService.test'; +import { IUserDataSyncProfilesStorageService } from 'vs/platform/userDataSync/common/userDataSyncProfilesStorageService'; +import { TestUserDataSyncProfilesStorageService } from 'vs/platform/userDataSync/test/common/userDataSyncProfilesStorageService.test'; export class UserDataSyncClient extends Disposable { @@ -92,7 +92,7 @@ export class UserDataSyncClient extends Disposable { const storageService = new TestStorageService(userDataProfilesService.defaultProfile); this.instantiationService.stub(IStorageService, this._register(storageService)); - this.instantiationService.stub(IProfileStorageService, this._register(new TestProfileStorageService(storageService))); + this.instantiationService.stub(IUserDataSyncProfilesStorageService, this._register(new TestUserDataSyncProfilesStorageService(storageService))); const configurationService = this._register(new ConfigurationService(userDataProfilesService.defaultProfile.settingsResource, fileService, new NullPolicyService(), logService)); await configurationService.initialize(); @@ -307,7 +307,7 @@ class TestStorageService extends InMemoryStorageService { constructor(private readonly profileStorageProfile: IUserDataProfile) { super(); } - override getProfileStorageProfile(): IUserDataProfile | undefined { - return this.profileStorageProfile; + override isProfileStorageFor(profile: IUserDataProfile): boolean { + return this.profileStorageProfile.id === profile.id; } } diff --git a/src/vs/platform/storage/test/common/profileStorageService.test.ts b/src/vs/platform/userDataSync/test/common/userDataSyncProfilesStorageService.test.ts index 3c51e76c107..fe4c35019ef 100644 --- a/src/vs/platform/storage/test/common/profileStorageService.test.ts +++ b/src/vs/platform/userDataSync/test/common/userDataSyncProfilesStorageService.test.ts @@ -8,7 +8,7 @@ import { Emitter, Event } from 'vs/base/common/event'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { InMemoryStorageDatabase, IStorageItemsChangeEvent, IUpdateRequest, Storage } from 'vs/base/parts/storage/common/storage'; -import { AbstractProfileStorageService, IProfileStorageService } from 'vs/platform/storage/common/profileStorageService'; +import { AbstractUserDataSyncProfilesStorageService, IUserDataSyncProfilesStorageService } from 'vs/platform/userDataSync/common/userDataSyncProfilesStorageService'; import { InMemoryStorageService, loadKeyTargets, StorageTarget, TARGET_KEY } from 'vs/platform/storage/common/storage'; import { IUserDataProfile, toUserDataProfile } from 'vs/platform/userDataProfile/common/userDataProfile'; @@ -25,7 +25,7 @@ class TestStorageDatabase extends InMemoryStorageDatabase { } } -export class TestProfileStorageService extends AbstractProfileStorageService implements IProfileStorageService { +export class TestUserDataSyncProfilesStorageService extends AbstractUserDataSyncProfilesStorageService implements IUserDataSyncProfilesStorageService { readonly onDidChange = Event.None; private databases = new Map<string, InMemoryStorageDatabase>(); @@ -45,11 +45,11 @@ suite('ProfileStorageService', () => { const disposables = new DisposableStore(); const profile = toUserDataProfile('test', URI.file('foo')); - let testObject: TestProfileStorageService; + let testObject: TestUserDataSyncProfilesStorageService; let storage: Storage; setup(async () => { - testObject = disposables.add(new TestProfileStorageService(new InMemoryStorageService())); + testObject = disposables.add(new TestUserDataSyncProfilesStorageService(new InMemoryStorageService())); storage = new Storage(await testObject.createStorageDatabase(profile)); await storage.init(); }); diff --git a/src/vs/workbench/services/storage/browser/storageService.ts b/src/vs/workbench/services/storage/browser/storageService.ts index ab80b407271..b92c3cfcc9b 100644 --- a/src/vs/workbench/services/storage/browser/storageService.ts +++ b/src/vs/workbench/services/storage/browser/storageService.ts @@ -239,8 +239,8 @@ export class BrowserStorageService extends AbstractStorageService { ]); } - getProfileStorageProfile(): IUserDataProfile { - return this.profileStorageProfile; + isProfileStorageFor(profile: IUserDataProfile): boolean { + return this.profileStorageProfile.id === profile.id; } } diff --git a/src/vs/workbench/services/storage/browser/profileStorageService.ts b/src/vs/workbench/services/userDataSync/browser/userDataSyncProfilesStorageService.ts index 4265e18d35f..7cec5ba8d7d 100644 --- a/src/vs/workbench/services/storage/browser/profileStorageService.ts +++ b/src/vs/workbench/services/userDataSync/browser/userDataSyncProfilesStorageService.ts @@ -7,13 +7,13 @@ import { Emitter, Event } from 'vs/base/common/event'; import { IStorageDatabase } from 'vs/base/parts/storage/common/storage'; import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ILogService } from 'vs/platform/log/common/log'; -import { AbstractProfileStorageService, IProfileStorageChanges, IProfileStorageService } from 'vs/platform/storage/common/profileStorageService'; +import { AbstractUserDataSyncProfilesStorageService, IProfileStorageChanges, IUserDataSyncProfilesStorageService } from 'vs/platform/userDataSync/common/userDataSyncProfilesStorageService'; import { isProfileUsingDefaultStorage, IStorageService, IStorageValueChangeEvent, StorageScope } from 'vs/platform/storage/common/storage'; import { IUserDataProfile } from 'vs/platform/userDataProfile/common/userDataProfile'; import { IndexedDBStorageDatabase } from 'vs/workbench/services/storage/browser/storageService'; import { IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; -export class ProfileStorageService extends AbstractProfileStorageService implements IProfileStorageService { +export class UserDataSyncProfilesStorageService extends AbstractUserDataSyncProfilesStorageService implements IUserDataSyncProfilesStorageService { private readonly _onDidChange = this._register(new Emitter<IProfileStorageChanges>()); readonly onDidChange: Event<IProfileStorageChanges> = this._onDidChange.event; @@ -45,4 +45,4 @@ export class ProfileStorageService extends AbstractProfileStorageService impleme } } -registerSingleton(IProfileStorageService, ProfileStorageService, InstantiationType.Delayed); +registerSingleton(IUserDataSyncProfilesStorageService, UserDataSyncProfilesStorageService, InstantiationType.Delayed); diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts index 5835fdd4094..d803e5293e8 100644 --- a/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.web.main.ts @@ -63,7 +63,7 @@ import 'vs/workbench/services/files/browser/elevatedFileService'; import 'vs/workbench/services/workingCopy/browser/workingCopyHistoryService'; import 'vs/workbench/services/userDataSync/browser/webUserDataSyncEnablementService'; import 'vs/workbench/services/configurationResolver/browser/configurationResolverService'; -import 'vs/workbench/services/storage/browser/profileStorageService'; +import 'vs/workbench/services/userDataSync/browser/userDataSyncProfilesStorageService'; import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; |