diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index 2e35f7c47a1..ac772deb3cf 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -52,7 +52,7 @@ import { IProductService } from 'vs/platform/product/common/productService'; import { IUserDataSyncService, IUserDataSyncStoreService, registerConfiguration, IUserDataSyncLogService, IUserDataSyncUtilService, ISettingsSyncService, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync'; import { UserDataSyncService } from 'vs/platform/userDataSync/common/userDataSyncService'; import { UserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSyncStoreService'; -import { UserDataSyncChannel, UserDataSyncUtilServiceClient, SettingsSyncChannel, UserDataAutoSyncChannel } from 'vs/platform/userDataSync/common/userDataSyncIpc'; +import { UserDataSyncChannel, UserDataSyncUtilServiceClient, SettingsSyncChannel, UserDataAutoSyncChannel, UserDataSyncStoreServiceChannel } from 'vs/platform/userDataSync/common/userDataSyncIpc'; import { IElectronService } from 'vs/platform/electron/node/electron'; import { LoggerService } from 'vs/platform/log/node/loggerService'; import { UserDataSyncLogService } from 'vs/platform/userDataSync/common/userDataSyncLog'; @@ -219,6 +219,10 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat const authTokenChannel = new AuthenticationTokenServiceChannel(authTokenService); server.registerChannel('authToken', authTokenChannel); + const userDataSyncStoreService = accessor.get(IUserDataSyncStoreService); + const userDataSyncStoreServiceChannel = new UserDataSyncStoreServiceChannel(userDataSyncStoreService); + server.registerChannel('userDataSyncStoreService', userDataSyncStoreServiceChannel); + const settingsSyncService = accessor.get(ISettingsSyncService); const settingsSyncChannel = new SettingsSyncChannel(settingsSyncService); server.registerChannel('settingsSync', settingsSyncChannel); diff --git a/src/vs/platform/userDataSync/common/userDataSync.ts b/src/vs/platform/userDataSync/common/userDataSync.ts index db964718718..315eeb93e3d 100644 --- a/src/vs/platform/userDataSync/common/userDataSync.ts +++ b/src/vs/platform/userDataSync/common/userDataSync.ts @@ -151,6 +151,9 @@ export interface IUserDataSyncStoreService { write(key: ResourceKey, content: string, ref: string | null, source?: SyncSource): Promise; manifest(): Promise; clear(): Promise; + getAllRefs(key: ResourceKey): Promise; + resolveContent(key: ResourceKey, ref: string): Promise; + delete(key: ResourceKey): Promise; } //#endregion diff --git a/src/vs/platform/userDataSync/common/userDataSyncIpc.ts b/src/vs/platform/userDataSync/common/userDataSyncIpc.ts index a2b8c25e64d..1c346ac1360 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncIpc.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncIpc.ts @@ -5,7 +5,7 @@ import { IServerChannel, IChannel } from 'vs/base/parts/ipc/common/ipc'; import { Event } from 'vs/base/common/event'; -import { IUserDataSyncService, IUserDataSyncUtilService, ISettingsSyncService, IUserDataAutoSyncService } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserDataSyncService, IUserDataSyncUtilService, ISettingsSyncService, IUserDataAutoSyncService, IUserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSync'; import { URI } from 'vs/base/common/uri'; import { IStringDictionary } from 'vs/base/common/collections'; import { FormattingOptions } from 'vs/base/common/jsonFormatter'; @@ -131,3 +131,20 @@ export class UserDataSyncUtilServiceClient implements IUserDataSyncUtilService { } +export class UserDataSyncStoreServiceChannel implements IServerChannel { + + constructor(private readonly service: IUserDataSyncStoreService) { } + + listen(_: unknown, event: string): Event { + throw new Error(`Event not found: ${event}`); + } + + call(context: any, command: string, args?: any): Promise { + switch (command) { + case 'getAllRefs': return this.service.getAllRefs(args[0]); + case 'resolveContent': return this.service.resolveContent(args[0], args[1]); + case 'delete': return this.service.delete(args[0]); + } + throw new Error('Invalid call'); + } +} diff --git a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts index 2280e1acc28..3057e9052a5 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts @@ -4,14 +4,15 @@ *--------------------------------------------------------------------------------------------*/ import { Disposable, } from 'vs/base/common/lifecycle'; -import { IUserData, IUserDataSyncStoreService, UserDataSyncErrorCode, IUserDataSyncStore, getUserDataSyncStore, SyncSource, UserDataSyncStoreError, IUserDataSyncLogService, IUserDataManifest } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserData, IUserDataSyncStoreService, UserDataSyncErrorCode, IUserDataSyncStore, getUserDataSyncStore, SyncSource, UserDataSyncStoreError, IUserDataSyncLogService, IUserDataManifest, ResourceKey } from 'vs/platform/userDataSync/common/userDataSync'; import { IRequestService, asText, isSuccess, asJson } from 'vs/platform/request/common/request'; -import { joinPath } from 'vs/base/common/resources'; +import { joinPath, relativePath } from 'vs/base/common/resources'; import { CancellationToken } from 'vs/base/common/cancellation'; import { IHeaders, IRequestOptions, IRequestContext } from 'vs/base/parts/request/common/request'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IAuthenticationTokenService } from 'vs/platform/authentication/common/authentication'; import { IProductService } from 'vs/platform/product/common/productService'; +import { URI } from 'vs/base/common/uri'; export class UserDataSyncStoreService extends Disposable implements IUserDataSyncStoreService { @@ -30,7 +31,58 @@ export class UserDataSyncStoreService extends Disposable implements IUserDataSyn this.userDataSyncStore = getUserDataSyncStore(productService, configurationService); } - async read(key: string, oldValue: IUserData | null, source?: SyncSource): Promise { + async getAllRefs(key: ResourceKey): Promise { + if (!this.userDataSyncStore) { + throw new Error('No settings sync store url configured.'); + } + + const uri = joinPath(this.userDataSyncStore.url, 'resource', key); + const headers: IHeaders = {}; + + const context = await this.request({ type: 'GET', url: uri.toString(), headers }, undefined, CancellationToken.None); + + if (!isSuccess(context)) { + throw new UserDataSyncStoreError('Server returned ' + context.res.statusCode, UserDataSyncErrorCode.Unknown, undefined); + } + + const resources: string[] = await asJson(context) || []; + return resources.map(resource => relativePath(uri, URI.parse(resource))!); + } + + async resolveContent(key: ResourceKey, ref: string): Promise { + if (!this.userDataSyncStore) { + throw new Error('No settings sync store url configured.'); + } + + const url = joinPath(this.userDataSyncStore.url, 'resource', key, ref).toString(); + const headers: IHeaders = {}; + + const context = await this.request({ type: 'GET', url, headers }, undefined, CancellationToken.None); + + if (!isSuccess(context)) { + throw new UserDataSyncStoreError('Server returned ' + context.res.statusCode, UserDataSyncErrorCode.Unknown, undefined); + } + + const content = await asText(context); + return content; + } + + async delete(key: ResourceKey): Promise { + if (!this.userDataSyncStore) { + throw new Error('No settings sync store url configured.'); + } + + const url = joinPath(this.userDataSyncStore.url, 'resource', key).toString(); + const headers: IHeaders = {}; + + const context = await this.request({ type: 'DELETE', url, headers }, undefined, CancellationToken.None); + + if (!isSuccess(context)) { + throw new UserDataSyncStoreError('Server returned ' + context.res.statusCode, UserDataSyncErrorCode.Unknown, undefined); + } + } + + async read(key: ResourceKey, oldValue: IUserData | null, source?: SyncSource): Promise { if (!this.userDataSyncStore) { throw new Error('No settings sync store url configured.'); } @@ -62,7 +114,7 @@ export class UserDataSyncStoreService extends Disposable implements IUserDataSyn return { ref, content }; } - async write(key: string, data: string, ref: string | null, source?: SyncSource): Promise { + async write(key: ResourceKey, data: string, ref: string | null, source?: SyncSource): Promise { if (!this.userDataSyncStore) { throw new Error('No settings sync store url configured.'); } diff --git a/src/vs/workbench/services/userDataSync/electron-browser/userDataSyncStoreService.ts b/src/vs/workbench/services/userDataSync/electron-browser/userDataSyncStoreService.ts new file mode 100644 index 00000000000..a79674273a5 --- /dev/null +++ b/src/vs/workbench/services/userDataSync/electron-browser/userDataSyncStoreService.ts @@ -0,0 +1,58 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { SyncSource, IUserDataSyncStoreService, IUserDataSyncStore, getUserDataSyncStore, ResourceKey, IUserData, IUserDataManifest } from 'vs/platform/userDataSync/common/userDataSync'; +import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; +import { IChannel } from 'vs/base/parts/ipc/common/ipc'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IProductService } from 'vs/platform/product/common/productService'; + +export class UserDataSyncStoreService implements IUserDataSyncStoreService { + + _serviceBrand: undefined; + private readonly channel: IChannel; + readonly userDataSyncStore: IUserDataSyncStore | undefined; + + constructor( + @ISharedProcessService sharedProcessService: ISharedProcessService, + @IProductService productService: IProductService, + @IConfigurationService configurationService: IConfigurationService + ) { + this.channel = sharedProcessService.getChannel('userDataSyncStoreService'); + this.userDataSyncStore = getUserDataSyncStore(productService, configurationService); + } + + read(key: ResourceKey, oldValue: IUserData | null, source?: SyncSource): Promise { + throw new Error('Not Supported'); + } + + write(key: ResourceKey, content: string, ref: string | null, source?: SyncSource): Promise { + throw new Error('Not Supported'); + } + + manifest(): Promise { + throw new Error('Not Supported'); + } + + clear(): Promise { + throw new Error('Not Supported'); + } + + getAllRefs(key: ResourceKey): Promise { + return this.channel.call('getAllRefs', [key]); + } + + resolveContent(key: ResourceKey, ref: string): Promise { + return this.channel.call('resolveContent', [key, ref]); + } + + delete(key: ResourceKey): Promise { + return this.channel.call('delete', [key]); + } + +} + +registerSingleton(IUserDataSyncStoreService, UserDataSyncStoreService); diff --git a/src/vs/workbench/workbench.desktop.main.ts b/src/vs/workbench/workbench.desktop.main.ts index 9e54cd80601..33ba47dadd6 100644 --- a/src/vs/workbench/workbench.desktop.main.ts +++ b/src/vs/workbench/workbench.desktop.main.ts @@ -52,6 +52,7 @@ import 'vs/workbench/services/workspaces/electron-browser/workspaceEditingServic import 'vs/workbench/services/userDataSync/electron-browser/userDataSyncService'; import 'vs/workbench/services/userDataSync/electron-browser/settingsSyncService'; import 'vs/workbench/services/userDataSync/electron-browser/userDataAutoSyncService'; +import 'vs/workbench/services/userDataSync/electron-browser/userDataSyncStoreService'; import 'vs/workbench/services/authentication/electron-browser/authenticationTokenService'; import 'vs/workbench/services/authentication/browser/authenticationService'; import 'vs/workbench/services/host/electron-browser/desktopHostService';