Use SequencerByKey to sequence operations of the same set of scopes (#192638)

The idea here is... if a token is currently being refreshed, well then getting a token of those scopes should wait for that to finish.

Core has a really nice `SequencerByKey` for exactly this kind of thing, and so I've stolen that and started to organize the code with a `common` folder.

Oh, I also noticed we were sorting twice and fixed that to only sort once.

ref https://github.com/microsoft/vscode/issues/186693
This commit is contained in:
Tyler James Leonhardt
2023-09-08 22:09:20 -07:00
committed by GitHub
parent 106ac0b4c0
commit 41e940f76f
4 changed files with 86 additions and 75 deletions

View File

@@ -0,0 +1,49 @@
/*---------------------------------------------------------------------------------------------
* 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 'vscode';
export class SequencerByKey<TKey> {
private promiseMap = new Map<TKey, Promise<unknown>>();
queue<T>(key: TKey, promiseTask: () => Promise<T>): Promise<T> {
const runningPromise = this.promiseMap.get(key) ?? Promise.resolve();
const newPromise = runningPromise
.catch(() => { })
.then(promiseTask)
.finally(() => {
if (this.promiseMap.get(key) === newPromise) {
this.promiseMap.delete(key);
}
});
this.promiseMap.set(key, newPromise);
return newPromise;
}
}
export class IntervalTimer extends Disposable {
private _token: any;
constructor() {
super(() => this.cancel());
this._token = -1;
}
cancel(): void {
if (this._token !== -1) {
clearInterval(this._token);
this._token = -1;
}
}
cancelAndSet(runner: () => void, interval: number): void {
this.cancel();
this._token = setInterval(() => {
runner();
}, interval);
}
}

View File

@@ -0,0 +1,37 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { env, UIKind, Uri } from 'vscode';
const LOCALHOST_ADDRESSES = ['localhost', '127.0.0.1', '0:0:0:0:0:0:0:1', '::1'];
function isLocalhost(uri: Uri): boolean {
if (!/^https?$/i.test(uri.scheme)) {
return false;
}
const host = uri.authority.split(':')[0];
return LOCALHOST_ADDRESSES.indexOf(host) >= 0;
}
export function isSupportedEnvironment(uri: Uri): boolean {
if (env.uiKind === UIKind.Desktop) {
return true;
}
// local development (localhost:* or 127.0.0.1:*)
if (isLocalhost(uri)) {
return true;
}
// At this point we should only ever see https
if (uri.scheme !== 'https') {
return false;
}
return (
// vscode.dev & insiders.vscode.dev
/(?:^|\.)vscode\.dev$/.test(uri.authority) ||
// github.dev & codespaces
/(?:^|\.)github\.dev$/.test(uri.authority) ||
// github.dev/codespaces local setup (github.localhost)
/(?:^|\.)github\.localhost$/.test(uri.authority)
);
}