Merge pull request #157509 from microsoft/sandy081/subtle-halibut

make userdata sync store client profile aware
This commit is contained in:
Sandeep Somavarapu
2022-08-08 16:14:27 +02:00
committed by GitHub
7 changed files with 67 additions and 44 deletions
@@ -667,14 +667,14 @@ export abstract class AbstractSynchroniser extends Disposable implements IUserDa
return { ref: refOrLastSyncData, content };
} else {
const lastSyncUserData: IUserData | null = refOrLastSyncData ? { ref: refOrLastSyncData.ref, content: refOrLastSyncData.syncData ? JSON.stringify(refOrLastSyncData.syncData) : null } : null;
return this.userDataSyncStoreService.read(this.resource, lastSyncUserData, this.syncHeaders);
return this.userDataSyncStoreService.read(this.resource, lastSyncUserData, undefined, this.syncHeaders);
}
}
protected async updateRemoteUserData(content: string, ref: string | null): Promise<IRemoteUserData> {
const machineId = await this.currentMachineIdPromise;
const syncData: ISyncData = { version: this.version, machineId, content };
ref = await this.userDataSyncStoreService.write(this.resource, JSON.stringify(syncData), ref, this.syncHeaders);
ref = await this.userDataSyncStoreService.write(this.resource, JSON.stringify(syncData), ref, undefined, this.syncHeaders);
return { ref, syncData };
}
@@ -480,7 +480,7 @@ export class UserDataSyncStoreTypeSynchronizer {
private async doSync(userDataSyncStoreType: UserDataSyncStoreType, syncHeaders: IHeaders): Promise<void> {
// Read the global state from remote
const globalStateUserData = await this.userDataSyncStoreClient.read(SyncResource.GlobalState, null, syncHeaders);
const globalStateUserData = await this.userDataSyncStoreClient.readResource(SyncResource.GlobalState, null, syncHeaders);
const remoteGlobalState = this.parseGlobalState(globalStateUserData) || { storage: {} };
// Update the sync store type
@@ -489,7 +489,7 @@ export class UserDataSyncStoreTypeSynchronizer {
// Write the global state to remote
const machineId = await getServiceMachineId(this.environmentService, this.fileService, this.storageService);
const syncDataToUpdate: ISyncData = { version: GLOBAL_STATE_DATA_VERSION, machineId, content: stringify(remoteGlobalState, false) };
await this.userDataSyncStoreClient.write(SyncResource.GlobalState, JSON.stringify(syncDataToUpdate), globalStateUserData.ref, syncHeaders);
await this.userDataSyncStoreClient.writeResource(SyncResource.GlobalState, JSON.stringify(syncDataToUpdate), globalStateUserData.ref, syncHeaders);
}
private parseGlobalState({ content }: IUserData): IGlobalState | null {
@@ -156,7 +156,7 @@ export interface IResourceRefHandle {
created: number;
}
export type ServerResource = SyncResource | 'machines' | 'editSessions';
export type ServerResource = SyncResource | 'machines' | 'editSessions' | 'profiles';
export type UserDataSyncStoreType = 'insiders' | 'stable';
export const IUserDataSyncStoreManagementService = createDecorator<IUserDataSyncStoreManagementService>('IUserDataSyncStoreManagementService');
@@ -168,7 +168,9 @@ export interface IUserDataSyncStoreManagementService {
getPreviousUserDataSyncStore(): Promise<IUserDataSyncStore | undefined>;
}
export interface IUserDataSyncStoreClient {
export const IUserDataSyncStoreService = createDecorator<IUserDataSyncStoreService>('IUserDataSyncStoreService');
export interface IUserDataSyncStoreService {
readonly _serviceBrand: undefined;
readonly onDidChangeDonotMakeRequestsUntil: Event<void>;
readonly donotMakeRequestsUntil: Date | undefined;
@@ -176,20 +178,13 @@ export interface IUserDataSyncStoreClient {
readonly onTokenSucceed: Event<void>;
setAuthToken(token: string, type: string): void;
// Sync requests
manifest(oldValue: IUserDataManifest | null, headers?: IHeaders): Promise<IUserDataManifest | null>;
read(resource: ServerResource, oldValue: IUserData | null, headers?: IHeaders): Promise<IUserData>;
write(resource: ServerResource, content: string, ref: string | null, headers?: IHeaders): Promise<string>;
read(resource: ServerResource, oldValue: IUserData | null, profile?: string, headers?: IHeaders): Promise<IUserData>;
write(resource: ServerResource, content: string, ref: string | null, profile?: string, headers?: IHeaders): Promise<string>;
delete(resource: ServerResource, ref: string | null, profile?: string): Promise<void>;
getAllRefs(resource: ServerResource, profile?: string): Promise<IResourceRefHandle[]>;
resolveContent(resource: ServerResource, ref: string, profile?: string, headers?: IHeaders): Promise<string | null>;
clear(): Promise<void>;
delete(resource: ServerResource, ref: string | null): Promise<void>;
getAllRefs(resource: ServerResource): Promise<IResourceRefHandle[]>;
resolveContent(resource: ServerResource, ref: string, headers?: IHeaders): Promise<string | null>;
}
export const IUserDataSyncStoreService = createDecorator<IUserDataSyncStoreService>('IUserDataSyncStoreService');
export interface IUserDataSyncStoreService extends IUserDataSyncStoreClient {
readonly _serviceBrand: undefined;
}
export const IUserDataSyncBackupStoreService = createDecorator<IUserDataSyncBackupStoreService>('IUserDataSyncBackupStoreService');
@@ -12,6 +12,7 @@ import { Mimes } from 'vs/base/common/mime';
import { isWeb } from 'vs/base/common/platform';
import { ConfigurationSyncStore } from 'vs/base/common/product';
import { joinPath, relativePath } from 'vs/base/common/resources';
import { join } from 'vs/base/common/path';
import { isObject, isString } from 'vs/base/common/types';
import { URI } from 'vs/base/common/uri';
import { generateUuid } from 'vs/base/common/uuid';
@@ -23,7 +24,7 @@ import { IProductService } from 'vs/platform/product/common/productService';
import { asJson, asTextOrError, IRequestService, isSuccess as isSuccessContext } from 'vs/platform/request/common/request';
import { getServiceMachineId } from 'vs/platform/externalServices/common/serviceMachineId';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { CONFIGURATION_SYNC_STORE_KEY, HEADER_EXECUTION_ID, HEADER_OPERATION_ID, IAuthenticationProvider, IResourceRefHandle, IUserData, IUserDataManifest, IUserDataSyncLogService, IUserDataSyncStore, IUserDataSyncStoreClient, IUserDataSyncStoreManagementService, IUserDataSyncStoreService, ServerResource, SYNC_SERVICE_URL_TYPE, UserDataSyncErrorCode, UserDataSyncStoreError, UserDataSyncStoreType } from 'vs/platform/userDataSync/common/userDataSync';
import { CONFIGURATION_SYNC_STORE_KEY, HEADER_EXECUTION_ID, HEADER_OPERATION_ID, IAuthenticationProvider, IResourceRefHandle, IUserData, IUserDataManifest, IUserDataSyncLogService, IUserDataSyncStore, IUserDataSyncStoreManagementService, IUserDataSyncStoreService, ServerResource, SYNC_SERVICE_URL_TYPE, UserDataSyncErrorCode, UserDataSyncStoreError, UserDataSyncStoreType } from 'vs/platform/userDataSync/common/userDataSync';
const SYNC_PREVIOUS_STORE = 'sync.previous.store';
const DONOT_MAKE_REQUESTS_UNTIL_KEY = 'sync.donot-make-requests-until';
@@ -140,7 +141,7 @@ export class UserDataSyncStoreManagementService extends AbstractUserDataSyncStor
}
}
export class UserDataSyncStoreClient extends Disposable implements IUserDataSyncStoreClient {
export class UserDataSyncStoreClient extends Disposable {
private userDataSyncStoreUrl: URI | undefined;
@@ -230,12 +231,12 @@ export class UserDataSyncStoreClient extends Disposable implements IUserDataSync
}
}
async getAllRefs(resource: ServerResource): Promise<IResourceRefHandle[]> {
async getAllResourceRefs(path: string): Promise<IResourceRefHandle[]> {
if (!this.userDataSyncStoreUrl) {
throw new Error('No settings sync store url configured.');
}
const uri = joinPath(this.userDataSyncStoreUrl, 'resource', resource);
const uri = joinPath(this.userDataSyncStoreUrl, 'resource', path);
const headers: IHeaders = {};
const context = await this.request(uri.toString(), { type: 'GET', headers }, [], CancellationToken.None);
@@ -244,12 +245,12 @@ export class UserDataSyncStoreClient extends Disposable implements IUserDataSync
return result.map(({ url, created }) => ({ ref: relativePath(uri, uri.with({ path: url }))!, created: created * 1000 /* Server returns in seconds */ }));
}
async resolveContent(resource: ServerResource, ref: string, headers: IHeaders = {}): Promise<string | null> {
async resolveResourceContent(path: string, ref: string, headers: IHeaders = {}): Promise<string | null> {
if (!this.userDataSyncStoreUrl) {
throw new Error('No settings sync store url configured.');
}
const url = joinPath(this.userDataSyncStoreUrl, 'resource', resource, ref).toString();
const url = joinPath(this.userDataSyncStoreUrl, 'resource', path, ref).toString();
headers = { ...headers };
headers['Cache-Control'] = 'no-cache';
@@ -258,23 +259,23 @@ export class UserDataSyncStoreClient extends Disposable implements IUserDataSync
return content;
}
async delete(resource: ServerResource, ref: string | null): Promise<void> {
async deleteResource(path: string, ref: string | null): Promise<void> {
if (!this.userDataSyncStoreUrl) {
throw new Error('No settings sync store url configured.');
}
const url = ref !== null ? joinPath(this.userDataSyncStoreUrl, 'resource', resource, ref).toString() : joinPath(this.userDataSyncStoreUrl, 'resource', resource).toString();
const url = ref !== null ? joinPath(this.userDataSyncStoreUrl, 'resource', path, ref).toString() : joinPath(this.userDataSyncStoreUrl, 'resource', path).toString();
const headers: IHeaders = {};
await this.request(url, { type: 'DELETE', headers }, [], CancellationToken.None);
}
async read(resource: ServerResource, oldValue: IUserData | null, headers: IHeaders = {}): Promise<IUserData> {
async readResource(path: string, oldValue: IUserData | null, headers: IHeaders = {}): Promise<IUserData> {
if (!this.userDataSyncStoreUrl) {
throw new Error('No settings sync store url configured.');
}
const url = joinPath(this.userDataSyncStoreUrl, 'resource', resource, 'latest').toString();
const url = joinPath(this.userDataSyncStoreUrl, 'resource', path, 'latest').toString();
headers = { ...headers };
// Disable caching as they are cached by synchronisers
headers['Cache-Control'] = 'no-cache';
@@ -306,12 +307,12 @@ export class UserDataSyncStoreClient extends Disposable implements IUserDataSync
return userData;
}
async write(resource: ServerResource, data: string, ref: string | null, headers: IHeaders = {}): Promise<string> {
async writeResource(path: string, data: string, ref: string | null, headers: IHeaders = {}): Promise<string> {
if (!this.userDataSyncStoreUrl) {
throw new Error('No settings sync store url configured.');
}
const url = joinPath(this.userDataSyncStoreUrl, 'resource', resource).toString();
const url = joinPath(this.userDataSyncStoreUrl, 'resource', path).toString();
headers = { ...headers };
headers['Content-Type'] = Mimes.text;
if (ref) {
@@ -549,6 +550,33 @@ export class UserDataSyncStoreService extends UserDataSyncStoreClient implements
super(userDataSyncStoreManagementService.userDataSyncStore?.url, productService, requestService, logService, environmentService, fileService, storageService);
this._register(userDataSyncStoreManagementService.onDidChangeUserDataSyncStore(() => this.updateUserDataSyncStoreUrl(userDataSyncStoreManagementService.userDataSyncStore?.url)));
}
getAllRefs(resource: ServerResource, profile?: string): Promise<IResourceRefHandle[]> {
return this.getAllResourceRefs(profile ? this.getProfileResource(resource, profile) : resource);
}
read(resource: ServerResource, oldValue: IUserData | null, profile?: string, headers?: IHeaders): Promise<IUserData> {
return this.readResource(profile ? this.getProfileResource(resource, profile) : resource, oldValue, headers);
}
write(resource: ServerResource, content: string, ref: string | null, profile?: string, headers?: IHeaders): Promise<string> {
return this.writeResource(profile ? this.getProfileResource(resource, profile) : resource, content, ref, headers);
}
delete(resource: ServerResource, ref: string | null, profile?: string): Promise<void> {
return this.deleteResource(profile ? this.getProfileResource(resource, profile) : resource, ref);
}
resolveContent(resource: ServerResource, ref: string, profile?: string, headers?: IHeaders): Promise<string | null> {
return this.resolveResourceContent(profile ? this.getProfileResource(resource, profile) : resource, ref, headers);
}
private getProfileResource(resource: ServerResource, profile: string): string {
if (resource === 'profiles') {
throw new Error(`Invalid Resource Argument: ${resource}`);
}
return join('profiles', profile, resource);
}
}
export class RequestsSession {
@@ -77,7 +77,7 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes
throw new Error('Please sign in to store your edit session.');
}
return this.storeClient!.write('editSessions', JSON.stringify(editSession), null, createSyncHeaders(generateUuid()));
return this.storeClient!.writeResource('editSessions', JSON.stringify(editSession), null, createSyncHeaders(generateUuid()));
}
/**
@@ -96,9 +96,9 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes
const headers = createSyncHeaders(generateUuid());
try {
if (ref !== undefined) {
content = await this.storeClient?.resolveContent('editSessions', ref, headers);
content = await this.storeClient?.resolveResourceContent('editSessions', ref, headers);
} else {
const result = await this.storeClient?.read('editSessions', null, headers);
const result = await this.storeClient?.readResource('editSessions', null, headers);
content = result?.content;
ref = result?.ref;
}
@@ -117,7 +117,7 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes
}
try {
await this.storeClient?.delete('editSessions', ref);
await this.storeClient?.deleteResource('editSessions', ref);
} catch (ex) {
this.logService.error(ex);
}
@@ -130,7 +130,7 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes
}
try {
return this.storeClient?.getAllRefs('editSessions') ?? [];
return this.storeClient?.getAllResourceRefs('editSessions') ?? [];
} catch (ex) {
this.logService.error(ex);
}
@@ -400,7 +400,7 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes
});
if (result.confirmed) {
if (result.checkboxChecked) {
that.storeClient?.delete('editSessions', null);
that.storeClient?.deleteResource('editSessions', null);
}
that.clearAuthenticationPreference();
}
@@ -83,7 +83,7 @@ export class RemoteExtensionsInitializerContribution implements IWorkbenchContri
const userDataSyncStoreClient = this.instantiationService.createInstance(UserDataSyncStoreClient, this.userDataSyncStoreManagementService.userDataSyncStore.url);
userDataSyncStoreClient.setAuthToken(session.accessToken, resolvedAuthority.options.authenticationSession.providerId);
const userData = await userDataSyncStoreClient.read(SyncResource.Extensions, null);
const userData = await userDataSyncStoreClient.readResource(SyncResource.Extensions, null);
const serviceCollection = new ServiceCollection();
serviceCollection.set(IExtensionManagementService, remoteExtensionManagementServer.extensionManagementService);
@@ -16,7 +16,7 @@ import { ILogService } from 'vs/platform/log/common/log';
import { UserDataSyncStoreClient } from 'vs/platform/userDataSync/common/userDataSyncStoreService';
import { IProductService } from 'vs/platform/product/common/productService';
import { IRequestService } from 'vs/platform/request/common/request';
import { IRemoteUserData, IUserData, IUserDataInitializer, IUserDataSyncLogService, IUserDataSyncStoreClient, IUserDataSyncStoreManagementService, SyncResource } from 'vs/platform/userDataSync/common/userDataSync';
import { IRemoteUserData, IUserData, IUserDataInitializer, IUserDataSyncLogService, IUserDataSyncStoreManagementService, SyncResource } from 'vs/platform/userDataSync/common/userDataSync';
import { AuthenticationSessionInfo, getCurrentAuthenticationSessionInfo } from 'vs/workbench/services/authentication/browser/authenticationService';
import { getSyncAreaLabel } from 'vs/workbench/services/userDataSync/common/userDataSync';
import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions } from 'vs/workbench/common/contributions';
@@ -77,10 +77,10 @@ export class UserDataInitializationService implements IUserDataInitializationSer
});
}
private _userDataSyncStoreClientPromise: Promise<IUserDataSyncStoreClient | undefined> | undefined;
private createUserDataSyncStoreClient(): Promise<IUserDataSyncStoreClient | undefined> {
private _userDataSyncStoreClientPromise: Promise<UserDataSyncStoreClient | undefined> | undefined;
private createUserDataSyncStoreClient(): Promise<UserDataSyncStoreClient | undefined> {
if (!this._userDataSyncStoreClientPromise) {
this._userDataSyncStoreClientPromise = (async (): Promise<IUserDataSyncStoreClient | undefined> => {
this._userDataSyncStoreClientPromise = (async (): Promise<UserDataSyncStoreClient | undefined> => {
try {
if (!isWeb) {
this.logService.trace(`Skipping initializing user data in desktop`);
@@ -151,7 +151,7 @@ export class UserDataInitializationService implements IUserDataInitializationSer
userDataSyncStoreClient.setAuthToken(authenticationSession.accessToken, authenticationSession.providerId);
// Cache global state data for global state initialization
this.globalStateUserData = await userDataSyncStoreClient.read(SyncResource.GlobalState, null);
this.globalStateUserData = await userDataSyncStoreClient.readResource(SyncResource.GlobalState, null);
if (this.globalStateUserData) {
const userDataSyncStoreType = new UserDataSyncStoreTypeSynchronizer(userDataSyncStoreClient, this.storageService, this.environmentService, this.fileService, this.logService).getSyncStoreType(this.globalStateUserData);
@@ -238,7 +238,7 @@ export class UserDataInitializationService implements IUserDataInitializationSer
if (!userDataSyncStoreClient) {
return null;
}
const userData = await userDataSyncStoreClient.read(SyncResource.Extensions, null);
const userData = await userDataSyncStoreClient.readResource(SyncResource.Extensions, null);
return instantiationService.createInstance(ExtensionsPreviewInitializer, userData);
})();
}
@@ -260,7 +260,7 @@ export class UserDataInitializationService implements IUserDataInitializationSer
this.initialized.push(syncResource);
this.logService.trace(`Initializing ${getSyncAreaLabel(syncResource)}`);
const initializer = this.createSyncResourceInitializer(syncResource);
const userData = await userDataSyncStoreClient.read(syncResource, syncResource === SyncResource.GlobalState ? this.globalStateUserData : null);
const userData = await userDataSyncStoreClient.readResource(syncResource, syncResource === SyncResource.GlobalState ? this.globalStateUserData : null);
await initializer.initialize(userData);
this.logService.info(`Initialized ${getSyncAreaLabel(syncResource)}`);
} catch (error) {