Fix #117098
This commit is contained in:
parent
c74bc68f0f
commit
78707e2d79
|
@ -3,7 +3,7 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event, Disposable } from 'vscode';
|
||||
import { EventEmitter, Event, Disposable } from 'vscode';
|
||||
|
||||
export function filterEvent<T>(event: Event<T>, filter: (e: T) => boolean): Event<T> {
|
||||
return (listener, thisArgs = null, disposables?) => event(e => filter(e) && listener.call(thisArgs, e), null, disposables);
|
||||
|
@ -47,29 +47,34 @@ const passthrough = (value: any, resolve: (value?: any) => void) => resolve(valu
|
|||
* @param adapter controls resolution of the returned promise
|
||||
* @returns a promise that resolves or rejects as specified by the adapter
|
||||
*/
|
||||
export async function promiseFromEvent<T, U>(
|
||||
export function promiseFromEvent<T, U>(
|
||||
event: Event<T>,
|
||||
adapter: PromiseAdapter<T, U> = passthrough): Promise<U> {
|
||||
adapter: PromiseAdapter<T, U> = passthrough): { promise: Promise<U>, cancel: EventEmitter<void> } {
|
||||
let subscription: Disposable;
|
||||
return new Promise<U>((resolve, reject) =>
|
||||
subscription = event((value: T) => {
|
||||
try {
|
||||
Promise.resolve(adapter(value, resolve, reject))
|
||||
.catch(reject);
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
let cancel = new EventEmitter<void>();
|
||||
return {
|
||||
promise: new Promise<U>((resolve, reject) => {
|
||||
cancel.event(_ => reject());
|
||||
subscription = event((value: T) => {
|
||||
try {
|
||||
Promise.resolve(adapter(value, resolve, reject))
|
||||
.catch(reject);
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}).then(
|
||||
(result: U) => {
|
||||
subscription.dispose();
|
||||
return result;
|
||||
},
|
||||
error => {
|
||||
subscription.dispose();
|
||||
throw error;
|
||||
}
|
||||
})
|
||||
).then(
|
||||
(result: U) => {
|
||||
subscription.dispose();
|
||||
return result;
|
||||
},
|
||||
error => {
|
||||
subscription.dispose();
|
||||
throw error;
|
||||
}
|
||||
);
|
||||
),
|
||||
cancel
|
||||
};
|
||||
}
|
||||
|
||||
export function arrayEquals<T>(one: ReadonlyArray<T> | undefined, other: ReadonlyArray<T> | undefined, itemEquals: (a: T, b: T) => boolean = (a, b) => a === b): boolean {
|
||||
|
|
|
@ -40,7 +40,7 @@ export class GitHubServer {
|
|||
private _statusBarItem: vscode.StatusBarItem | undefined;
|
||||
|
||||
private _pendingStates = new Map<string, string[]>();
|
||||
private _codeExchangePromises = new Map<string, Promise<string>>();
|
||||
private _codeExchangePromises = new Map<string, { promise: Promise<string>, cancel: vscode.EventEmitter<void> }>();
|
||||
|
||||
constructor(private readonly telemetryReporter: TelemetryReporter) { }
|
||||
|
||||
|
@ -86,17 +86,21 @@ export class GitHubServer {
|
|||
|
||||
// Register a single listener for the URI callback, in case the user starts the login process multiple times
|
||||
// before completing it.
|
||||
let existingPromise = this._codeExchangePromises.get(scopes);
|
||||
if (!existingPromise) {
|
||||
existingPromise = promiseFromEvent(uriHandler.event, this.exchangeCodeForToken(scopes));
|
||||
this._codeExchangePromises.set(scopes, existingPromise);
|
||||
let codeExchangePromise = this._codeExchangePromises.get(scopes);
|
||||
if (!codeExchangePromise) {
|
||||
codeExchangePromise = promiseFromEvent(uriHandler.event, this.exchangeCodeForToken(scopes));
|
||||
this._codeExchangePromises.set(scopes, codeExchangePromise);
|
||||
}
|
||||
|
||||
return Promise.race([
|
||||
existingPromise,
|
||||
promiseFromEvent<string | undefined, string>(onDidManuallyProvideToken.event, (token: string | undefined): string => { if (!token) { throw new Error('Cancelled'); } return token; })
|
||||
codeExchangePromise.promise,
|
||||
promiseFromEvent<string | undefined, string>(onDidManuallyProvideToken.event, (token: string | undefined): string => {
|
||||
if (!token) { throw new Error('Cancelled'); }
|
||||
return token;
|
||||
}).promise
|
||||
]).finally(() => {
|
||||
this._pendingStates.delete(scopes);
|
||||
codeExchangePromise?.cancel.fire();
|
||||
this._codeExchangePromises.delete(scopes);
|
||||
this.updateStatusBarItem(false);
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue