userDataSyncStoreService.ts 4.1 KB
Newer Older
S
Sandeep Somavarapu 已提交
1 2 3 4 5 6
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import { Disposable, } from 'vs/base/common/lifecycle';
S
Sandeep Somavarapu 已提交
7
import { IUserData, IUserDataSyncStoreService, UserDataSyncStoreErrorCode, UserDataSyncStoreError, IUserDataSyncLogService } from 'vs/platform/userDataSync/common/userDataSync';
8
import { IProductService } from 'vs/platform/product/common/productService';
S
Sandeep Somavarapu 已提交
9
import { IRequestService, asText, isSuccess } from 'vs/platform/request/common/request';
10 11 12
import { URI } from 'vs/base/common/uri';
import { joinPath } from 'vs/base/common/resources';
import { CancellationToken } from 'vs/base/common/cancellation';
S
Sandeep Somavarapu 已提交
13
import { IHeaders, IRequestOptions, IRequestContext } from 'vs/base/parts/request/common/request';
S
Sandeep Somavarapu 已提交
14
import { IAuthTokenService, AuthTokenStatus } from 'vs/platform/auth/common/auth';
S
Sandeep Somavarapu 已提交
15 16 17 18 19

export class UserDataSyncStoreService extends Disposable implements IUserDataSyncStoreService {

	_serviceBrand: any;

20
	get enabled(): boolean { return !!this.productService.settingsSyncStoreUrl; }
S
Sandeep Somavarapu 已提交
21 22

	constructor(
23
		@IProductService private readonly productService: IProductService,
24
		@IRequestService private readonly requestService: IRequestService,
S
Sandeep Somavarapu 已提交
25
		@IUserDataSyncLogService private readonly logService: IUserDataSyncLogService,
S
Sandeep Somavarapu 已提交
26
		@IAuthTokenService private readonly authTokenService: IAuthTokenService,
S
Sandeep Somavarapu 已提交
27 28 29 30
	) {
		super();
	}

31
	async read(key: string, oldValue: IUserData | null): Promise<IUserData> {
32 33
		if (!this.enabled) {
			return Promise.reject(new Error('No settings sync store url configured.'));
S
Sandeep Somavarapu 已提交
34
		}
35

36
		const url = joinPath(URI.parse(this.productService.settingsSyncStoreUrl!), 'resource', key, 'latest').toString();
S
Sandeep Somavarapu 已提交
37 38 39 40
		const headers: IHeaders = {};
		if (oldValue) {
			headers['If-None-Match'] = oldValue.ref;
		}
41

S
Sandeep Somavarapu 已提交
42
		const context = await this.request({ type: 'GET', url, headers }, CancellationToken.None);
43 44 45 46 47 48

		if (context.res.statusCode === 304) {
			// There is no new value. Hence return the old value.
			return oldValue!;
		}

S
Sandeep Somavarapu 已提交
49 50 51 52
		if (!isSuccess(context)) {
			throw new Error('Server returned ' + context.res.statusCode);
		}

53 54 55 56 57 58
		const ref = context.res.headers['etag'];
		if (!ref) {
			throw new Error('Server did not return the ref');
		}
		const content = await asText(context);
		return { ref, content };
S
Sandeep Somavarapu 已提交
59 60
	}

61
	async write(key: string, data: string, ref: string | null): Promise<string> {
62 63
		if (!this.enabled) {
			return Promise.reject(new Error('No settings sync store url configured.'));
S
Sandeep Somavarapu 已提交
64
		}
65

66
		const url = joinPath(URI.parse(this.productService.settingsSyncStoreUrl!), 'resource', key).toString();
67
		const headers: IHeaders = { 'Content-Type': 'text/plain' };
S
Sandeep Somavarapu 已提交
68 69 70
		if (ref) {
			headers['If-Match'] = ref;
		}
71

S
Sandeep Somavarapu 已提交
72
		const context = await this.request({ type: 'POST', url, data, headers }, CancellationToken.None);
73 74 75 76 77 78

		if (context.res.statusCode === 412) {
			// There is a new value. Throw Rejected Error
			throw new UserDataSyncStoreError('New data exists', UserDataSyncStoreErrorCode.Rejected);
		}

S
Sandeep Somavarapu 已提交
79 80 81 82
		if (!isSuccess(context)) {
			throw new Error('Server returned ' + context.res.statusCode);
		}

83
		const newRef = context.res.headers['etag'];
84 85 86 87
		if (!newRef) {
			throw new Error('Server did not return the ref');
		}
		return newRef;
S
Sandeep Somavarapu 已提交
88 89
	}

S
Sandeep Somavarapu 已提交
90
	private async request(options: IRequestOptions, token: CancellationToken): Promise<IRequestContext> {
S
Sandeep Somavarapu 已提交
91 92 93 94 95 96 97
		if (this.authTokenService.status !== AuthTokenStatus.Disabled) {
			const authToken = await this.authTokenService.getToken();
			if (!authToken) {
				return Promise.reject(new Error('No Auth Token Available.'));
			}
			options.headers = options.headers || {};
			options.headers['authorization'] = `Bearer ${authToken}`;
S
Sandeep Somavarapu 已提交
98 99
		}

S
Sandeep Somavarapu 已提交
100 101 102 103 104
		const context = await this.requestService.request(options, token);

		if (context.res.statusCode === 401) {
			// Not Authorized
			this.logService.info('Authroization Failed.');
S
Sandeep Somavarapu 已提交
105
			this.authTokenService.refreshToken();
S
Sandeep Somavarapu 已提交
106 107 108 109 110 111 112
			Promise.reject('Authroization Failed.');
		}

		return context;

	}

S
Sandeep Somavarapu 已提交
113
}