userDataAutoSyncService.ts ×37

Frontier kind: Code frontier

unlabeled · c_8970500e3202

16 tests · 28044 LOC · 134 files · introduces 0 tests · 168 LOC · 3 files

Introduces — evidence that enters the hierarchy at this concept

Code
47 ranges168 lines · 3 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
4789 ranges28044 lines · 134 files · Browse complete extent
All tests (intent)
16 testsBrowse complete intent

Neighbourhood graph

The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.

Introduced files, introduced tests, and structurally relevant concept specialization

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the native relationship evidence on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the native relationship evidence on this page while the interactive map is unavailable.

Native relationship evidence

Every exact file and test below is linked only from the concept that introduces it.

Introduced tests

Every collected test enters the hierarchy at exactly one concept.

No tests are introduced at this concept. Its intent tests are introduced by other concepts.

Introduced code

Every collected source range enters the hierarchy at exactly one concept.

3 files ranked by introduced lines: 168 introduced LOC across 47 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/platform/userDataSync/common/userDataAutoSyncService.ts 143 introduced LOC · 37 ranges

Open complete file

47 }
48 private set syncUrl(syncUrl: URI | undefined) {
49 > if (syncUrl) { userDataAutoSyncService.ts
50 > this.storageService.store(storeUrlKey, syncUrl.toString(), StorageScope.APPLICATION, StorageTarget.MACHINE);
51 > } else {
52 this.storageService.remove(storeUrlKey, StorageScope.APPLICATION);
53 }
55
56 private previousProductQuality: string | undefined;
57 private get productQuality(): string | undefined {
58 > return this.storageService.get(productQualityKey, StorageScope.APPLICATION); userDataAutoSyncService.ts
59 > }
60 private set productQuality(productQuality: string | undefined) {
61 > if (productQuality) { userDataAutoSyncService.ts
62 this.storageService.store(productQualityKey, productQuality, StorageScope.APPLICATION, StorageTarget.MACHINE);
64 > this.storageService.remove(productQualityKey, StorageScope.APPLICATION);
65 > }
66 > }
67
68 constructor(
69 > @IProductService productService: IProductService, userDataAutoSyncService.ts
70 > @IUserDataSyncStoreManagementService private readonly userDataSyncStoreManagementService: IUserDataSyncStoreManagementService,
71 > @IUserDataSyncStoreService private readonly userDataSyncStoreService: IUserDataSyncStoreService,
72 > @IUserDataSyncEnablementService private readonly userDataSyncEnablementService: IUserDataSyncEnablementService,
73 > @IUserDataSyncService private readonly userDataSyncService: IUserDataSyncService,
74 > @IUserDataSyncLogService private readonly logService: IUserDataSyncLogService,
75 > @IUserDataSyncAccountService private readonly userDataSyncAccountService: IUserDataSyncAccountService,
76 > @ITelemetryService private readonly telemetryService: ITelemetryService,
77 > @IUserDataSyncMachinesService private readonly userDataSyncMachinesService: IUserDataSyncMachinesService,
78 > @IStorageService private readonly storageService: IStorageService,
79 > @IMeteredConnectionService private readonly meteredConnectionService: IMeteredConnectionService,
80 > ) {
81 > super();
82 > this.syncTriggerDelayer = this._register(new ThrottledDelayer<void>(this.getSyncTriggerDelayTime()));
83 >
84 > this.lastSyncUrl = this.syncUrl;
85 > this.syncUrl = userDataSyncStoreManagementService.userDataSyncStore?.url;
86 >
87 > this.previousProductQuality = this.productQuality;
88 > this.productQuality = productService.quality;
89 >
90 > if (this.syncUrl) {
91 >
92 > this.logService.info('[AutoSync] Using settings sync service', this.syncUrl.toString());
93 > this._register(userDataSyncStoreManagementService.onDidChangeUserDataSyncStore(() => {
94 if (!isEqual(this.syncUrl, userDataSyncStoreManagementService.userDataSyncStore?.url)) {
95 this.lastSyncUrl = this.syncUrl;
99 }
100 }
102 >
103 > if (this.userDataSyncEnablementService.isEnabled()) {
104 > this.logService.info('[AutoSync] Enabled.');
105 > } else {
106 this.logService.info('[AutoSync] Disabled.');
107 }
108 > this.updateAutoSync(); userDataAutoSyncService.ts
109 >
110 > if (this.hasToDisableMachineEventually()) {
111 this.disableMachineEventually();
112 }
114 > this._register(userDataSyncAccountService.onDidChangeAccount(() => this.updateAutoSync()));
115 > this._register(userDataSyncStoreService.onDidChangeDonotMakeRequestsUntil(() => this.updateAutoSync()));
116 > this._register(userDataSyncService.onDidChangeLocal(source => this.triggerSync([source])));
117 > this._register(Event.filter(this.userDataSyncEnablementService.onDidChangeResourceEnablement, ([, enabled]) => enabled)(() => this.triggerSync(['resourceEnablement'])));
118 > this._register(this.userDataSyncStoreManagementService.onDidChangeUserDataSyncStore(() => this.triggerSync(['userDataSyncStoreChanged'])));
119 > this._register(meteredConnectionService.onDidChangeIsConnectionMetered(() => this.updateAutoSync()));
120 > }
121 > }
122
123 private updateAutoSync(): void {
124 > const { enabled, message } = this.isAutoSyncEnabled(); userDataAutoSyncService.ts
125 > if (enabled) {
126 > if (this.autoSync.value === undefined) {
127 > this.autoSync.value = new AutoSync(this.lastSyncUrl, 1000 * 60 * 5 /* 5 miutes */, this.userDataSyncStoreManagementService, this.userDataSyncStoreService, this.userDataSyncService, this.userDataSyncMachinesService, this.logService, this.telemetryService, this.storageService);
128 > this.autoSync.value.register(this.autoSync.value.onDidStartSync(() => this.lastSyncTriggerTime = new Date().getTime()));
129 > this.autoSync.value.register(this.autoSync.value.onDidFinishSync(e => this.onDidFinishSync(e)));
130 > if (this.startAutoSync()) {
131 this.autoSync.value.start();
132 }
134 > } else {
135 this.syncTriggerDelayer.cancel();
136 if (this.autoSync.value !== undefined) {
152
153 private isAutoSyncEnabled(): { enabled: boolean; message?: string } {
154 > if (!this.userDataSyncEnablementService.isEnabled()) { userDataAutoSyncService.ts
155 return { enabled: false, message: '[AutoSync] Disabled.' };
156 }
157 > if (!this.userDataSyncAccountService.account) { userDataAutoSyncService.ts
158 return { enabled: false, message: '[AutoSync] Suspended until auth token is available.' };
159 }
160 > if (this.userDataSyncStoreService.donotMakeRequestsUntil) { userDataAutoSyncService.ts
161 return { enabled: false, message: `[AutoSync] Suspended until ${toLocalISOString(this.userDataSyncStoreService.donotMakeRequestsUntil)} because server is not accepting requests until then.` };
162 }
163 > if (this.suspendUntilRestart) { userDataAutoSyncService.ts
164 return { enabled: false, message: '[AutoSync] Suspended until restart.' };
165 }
166 > if (this.meteredConnectionService.isConnectionMetered) { userDataAutoSyncService.ts
167 return { enabled: false, message: '[AutoSync] Suspended because connection is metered.' };
168 }
169 > return { enabled: true }; userDataAutoSyncService.ts
170 > }
171
172 async turnOn(): Promise<void> {
327
328 private hasToDisableMachineEventually(): boolean {
329 > return this.storageService.getBoolean(disableMachineEventuallyKey, StorageScope.APPLICATION, false); userDataAutoSyncService.ts
330 > }
331
332 private stopDisableMachineEventually(): void {
336 private sources: string[] = [];
337 async triggerSync(sources: string[], options?: SyncOptions): Promise<void> {
338 > if (this.autoSync.value === undefined) { userDataAutoSyncService.ts
339 return this.syncTriggerDelayer.cancel();
340 }
342 > if (options?.skipIfSyncedRecently && this.lastSyncTriggerTime && new Date().getTime() - this.lastSyncTriggerTime < 10_000) {
343 this.logService.debug('[AutoSync] Skipping because sync was triggered recently.', sources);
344 return;
345 }
347 > this.sources.push(...sources);
348 > return this.syncTriggerDelayer.trigger(async () => {
349 > this.logService.trace('[AutoSync] Activity sources', ...this.sources);
350 > this.sources = [];
351 > if (this.autoSync.value) {
352 > await this.autoSync.value.sync('Activity', !!options?.disableCache);
353 > }
354 > }, this.successiveFailures
355 ? Math.min(this.getSyncTriggerDelayTime() * this.successiveFailures, 60_000) /* Delay linearly until max 1 minute */
356 > : options?.immediately ? 0 : this.getSyncTriggerDelayTime()); userDataAutoSyncService.ts
357 >
358 > }
359
360 protected getSyncTriggerDelayTime(): number {
385
386 constructor(
387 > private readonly lastSyncUrl: URI | undefined, userDataAutoSyncService.ts
388 > private readonly interval: number /* in milliseconds */,
389 > private readonly userDataSyncStoreManagementService: IUserDataSyncStoreManagementService,
390 > private readonly userDataSyncStoreService: IUserDataSyncStoreService,
391 > private readonly userDataSyncService: IUserDataSyncService,
392 > private readonly userDataSyncMachinesService: IUserDataSyncMachinesService,
393 > private readonly logService: IUserDataSyncLogService,
394 > private readonly telemetryService: ITelemetryService,
395 > private readonly storageService: IStorageService,
396 > ) {
397 > super();
398 > }
399
400 start(): void {
420
421 sync(reason: string, disableCache: boolean): Promise<void> {
422 > const syncPromise = createCancelablePromise(async token => { userDataAutoSyncService.ts
423 > if (this.syncPromise) {
424 try {
425 // Wait until existing sync is finished
433 }
434 }
435 > return this.doSync(reason, disableCache, token); userDataAutoSyncService.ts
436 > });
437 > this.syncPromise = syncPromise;
438 > this.syncPromise.finally(() => this.syncPromise = undefined);
439 > return this.syncPromise;
440 > }
441
442 private hasSyncServiceChanged(): boolean {
455
456 private async doSync(reason: string, disableCache: boolean, token: CancellationToken): Promise<void> {
457 > this.logService.info(`[AutoSync] Triggered by ${reason}`); userDataAutoSyncService.ts
458 >
459 > this._onDidStartSync.fire();
460 >
461 > let error: Error | undefined;
462 > try {
463 > await this.createAndRunSyncTask(disableCache, token);
464 > } catch (e) {
465 this.logService.error(e);
466 error = e;
478 }
479 }
481 > this._onDidFinishSync.fire(error);
482 > }
483
484 private async createAndRunSyncTask(disableCache: boolean, token: CancellationToken): Promise<void> {
485 > this.syncTask = await this.userDataSyncService.createSyncTask(this.manifest, disableCache); userDataAutoSyncService.ts
486 > if (token.isCancellationRequested) {
487 return;
488 }
489 > this.manifest = this.syncTask.manifest; userDataAutoSyncService.ts
490 >
491 > // Server has no data but this machine was synced before
492 > if (this.manifest === null && await this.userDataSyncService.hasPreviouslySynced()) {
493 if (this.hasSyncServiceChanged()) {
494 if (await this.hasDefaultServiceChanged()) {
502 }
503 }
505 > const sessionId = this.storageService.get(sessionIdKey, StorageScope.APPLICATION);
506 > // Server session is different from client session
507 > if (sessionId && this.manifest && sessionId !== this.manifest.session) {
508 if (this.hasSyncServiceChanged()) {
509 if (await this.hasDefaultServiceChanged()) {
516 }
517 }
519 > const machines = await this.userDataSyncMachinesService.getMachines(this.manifest || undefined);
520 > // Return if cancellation is requested
521 > if (token.isCancellationRequested) {
522 return;
523 }
525 > const currentMachine = machines.find(machine => machine.isCurrent);
526 > // Check if sync was turned off from other machine
527 > if (currentMachine?.disabled) {
528 // Throw TurnedOff error
529 throw new UserDataAutoSyncError(localize('turned off machine', "Cannot sync because syncing is turned off on this machine from another machine."), UserDataSyncErrorCode.TurnedOff);
530 }
532 > const startTime = new Date().getTime();
533 > await this.syncTask.run();
534 this.telemetryService.publicLog2<{
535 duration: number;
550
551 // Update local session id
552 > if (this.manifest && this.manifest.session !== sessionId) { userDataAutoSyncService.ts
553 this.storageService.store(sessionIdKey, this.manifest.session, StorageScope.APPLICATION, StorageTarget.MACHINE);
554 }
563 await this.userDataSyncMachinesService.addCurrentMachine(this.manifest || undefined);
564 }
566
567 register<T extends IDisposable>(t: T): T {
568 > return super._register(t); userDataAutoSyncService.ts
569 > }
570
571 }
src/vs/platform/userDataSync/common/userDataSyncMachines.ts 19 introduced LOC · 7 ranges

Open complete file

101
102 async getMachines(manifest?: IUserDataManifest): Promise<IUserDataSyncMachine[]> {
103 > const currentMachineId = await this.currentMachineIdPromise; userDataSyncMachines.ts
104 > const machineData = await this.readMachinesData(manifest);
105 > return machineData.machines.map<IUserDataSyncMachine>(machine => ({ ...machine, ...{ isCurrent: machine.id === currentMachineId } }));
106 > }
107
108 async addCurrentMachine(manifest?: IUserDataManifest): Promise<void> {
170
171 private async readMachinesData(manifest?: IUserDataManifest): Promise<IMachinesData> {
172 > this.userData = await this.readUserData(manifest); userDataSyncMachines.ts
173 > const machinesData = this.parse(this.userData);
174 > if (machinesData.version !== UserDataSyncMachinesService.VERSION) {
175 throw new Error(localize('error incompatible', "Cannot read machines data as the current version is incompatible. Please update {0} and try again.", this.productService.nameLong));
176 }
177 > return machinesData; userDataSyncMachines.ts
178 > }
179
180 private async writeMachinesData(machinesData: IMachinesData): Promise<void> {
186
187 private async readUserData(manifest?: IUserDataManifest): Promise<IUserData> {
188 > if (this.userData) { userDataSyncMachines.ts
189
190 const latestRef = manifest && manifest.latest ? manifest.latest[UserDataSyncMachinesService.RESOURCE] : undefined;
200 }
201 }
203 > return this.userDataSyncStoreService.readResource(UserDataSyncMachinesService.RESOURCE, this.userData);
204 > }
205
206 private parse(userData: IUserData): IMachinesData {
207 > if (userData.content !== null) { userDataSyncMachines.ts
208 try {
209 return JSON.parse(userData.content);
212 }
213 }
214 > return { userDataSyncMachines.ts
215 > version: UserDataSyncMachinesService.VERSION,
216 > machines: []
217 > };
218 > }
219 }
src/vs/platform/userDataSync/common/userDataSyncEnablementService.ts 6 introduced LOC · 3 ranges

Open complete file