mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 04:49:35 +00:00
Add RemoteAuthorityResolver.getCanonicalURI
This commit is contained in:
parent
c650993dd3
commit
85f518b255
|
@ -216,6 +216,9 @@ export function activate(context: vscode.ExtensionContext) {
|
|||
}
|
||||
|
||||
const authorityResolverDisposable = vscode.workspace.registerRemoteAuthorityResolver('test', {
|
||||
async getCanonicalURI(uri: vscode.Uri): Promise<vscode.Uri> {
|
||||
return vscode.Uri.file(uri.path);
|
||||
},
|
||||
resolve(_authority: string): Thenable<vscode.ResolvedAuthority> {
|
||||
return vscode.window.withProgress({
|
||||
location: vscode.ProgressLocation.Notification,
|
||||
|
|
|
@ -40,6 +40,10 @@ export class RemoteAuthorityResolverService extends Disposable implements IRemot
|
|||
return this._cache.get(authority)!;
|
||||
}
|
||||
|
||||
async getCanonicalURI(uri: URI): Promise<URI> {
|
||||
return uri;
|
||||
}
|
||||
|
||||
getConnectionData(authority: string): IRemoteConnectionData | null {
|
||||
if (!this._cache.has(authority)) {
|
||||
return null;
|
||||
|
@ -76,4 +80,7 @@ export class RemoteAuthorityResolverService extends Disposable implements IRemot
|
|||
RemoteAuthorities.setConnectionToken(authority, connectionToken);
|
||||
this._onDidChangeConnectionData.fire();
|
||||
}
|
||||
|
||||
_setCanonicalURIProvider(provider: (uri: URI) => Promise<URI>): void {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
export const IRemoteAuthorityResolverService = createDecorator<IRemoteAuthorityResolverService>('remoteAuthorityResolverService');
|
||||
|
||||
|
@ -92,9 +93,18 @@ export interface IRemoteAuthorityResolverService {
|
|||
|
||||
resolveAuthority(authority: string): Promise<ResolverResult>;
|
||||
getConnectionData(authority: string): IRemoteConnectionData | null;
|
||||
/**
|
||||
* Get the canonical URI for a `vscode-remote://` URI.
|
||||
*
|
||||
* **NOTE**: This can throw e.g. in cases where there is no resolver installed for the specific remote authority.
|
||||
*
|
||||
* @param uri The `vscode-remote://` URI
|
||||
*/
|
||||
getCanonicalURI(uri: URI): Promise<URI>;
|
||||
|
||||
_clearResolvedAuthority(authority: string): void;
|
||||
_setResolvedAuthority(resolvedAuthority: ResolvedAuthority, resolvedOptions?: ResolvedOptions): void;
|
||||
_setResolvedAuthorityError(authority: string, err: any): void;
|
||||
_setAuthorityConnectionToken(authority: string, connectionToken: string): void;
|
||||
_setCanonicalURIProvider(provider: (uri: URI) => Promise<URI>): void;
|
||||
}
|
||||
|
|
|
@ -8,22 +8,27 @@ import * as errors from 'vs/base/common/errors';
|
|||
import { RemoteAuthorities } from 'vs/base/common/network';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
class PendingResolveAuthorityRequest {
|
||||
class PendingPromise<I, R> {
|
||||
public readonly promise: Promise<R>;
|
||||
public readonly input: I;
|
||||
public result: R | null;
|
||||
private _resolve!: (value: R) => void;
|
||||
private _reject!: (err: any) => void;
|
||||
|
||||
public value: ResolverResult | null;
|
||||
|
||||
constructor(
|
||||
private readonly _resolve: (value: ResolverResult) => void,
|
||||
private readonly _reject: (err: any) => void,
|
||||
public readonly promise: Promise<ResolverResult>,
|
||||
) {
|
||||
this.value = null;
|
||||
constructor(request: I) {
|
||||
this.input = request;
|
||||
this.promise = new Promise<R>((resolve, reject) => {
|
||||
this._resolve = resolve;
|
||||
this._reject = reject;
|
||||
});
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
resolve(value: ResolverResult): void {
|
||||
this.value = value;
|
||||
this._resolve(this.value);
|
||||
resolve(result: R): void {
|
||||
this.result = result;
|
||||
this._resolve(this.result);
|
||||
}
|
||||
|
||||
reject(err: any): void {
|
||||
|
@ -38,40 +43,50 @@ export class RemoteAuthorityResolverService extends Disposable implements IRemot
|
|||
private readonly _onDidChangeConnectionData = this._register(new Emitter<void>());
|
||||
public readonly onDidChangeConnectionData = this._onDidChangeConnectionData.event;
|
||||
|
||||
private readonly _resolveAuthorityRequests: Map<string, PendingResolveAuthorityRequest>;
|
||||
private readonly _resolveAuthorityRequests: Map<string, PendingPromise<string, ResolverResult>>;
|
||||
private readonly _connectionTokens: Map<string, string>;
|
||||
private readonly _canonicalURIRequests: Map<string, PendingPromise<URI, URI>>;
|
||||
private _canonicalURIProvider: ((uri: URI) => Promise<URI>) | null;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._resolveAuthorityRequests = new Map<string, PendingResolveAuthorityRequest>();
|
||||
this._resolveAuthorityRequests = new Map<string, PendingPromise<string, ResolverResult>>();
|
||||
this._connectionTokens = new Map<string, string>();
|
||||
this._canonicalURIRequests = new Map<string, PendingPromise<URI, URI>>();
|
||||
this._canonicalURIProvider = null;
|
||||
}
|
||||
|
||||
resolveAuthority(authority: string): Promise<ResolverResult> {
|
||||
if (!this._resolveAuthorityRequests.has(authority)) {
|
||||
let resolve: (value: ResolverResult) => void;
|
||||
let reject: (err: any) => void;
|
||||
const promise = new Promise<ResolverResult>((_resolve, _reject) => {
|
||||
resolve = _resolve;
|
||||
reject = _reject;
|
||||
});
|
||||
this._resolveAuthorityRequests.set(authority, new PendingResolveAuthorityRequest(resolve!, reject!, promise));
|
||||
this._resolveAuthorityRequests.set(authority, new PendingPromise<string, ResolverResult>(authority));
|
||||
}
|
||||
return this._resolveAuthorityRequests.get(authority)!.promise;
|
||||
}
|
||||
|
||||
async getCanonicalURI(uri: URI): Promise<URI> {
|
||||
const key = uri.toString();
|
||||
if (!this._canonicalURIRequests.has(key)) {
|
||||
const request = new PendingPromise<URI, URI>(uri);
|
||||
if (this._canonicalURIProvider) {
|
||||
this._canonicalURIProvider(request.input).then((uri) => request.resolve(uri), (err) => request.reject(err));
|
||||
}
|
||||
this._canonicalURIRequests.set(key, request);
|
||||
}
|
||||
return this._canonicalURIRequests.get(key)!.promise;
|
||||
}
|
||||
|
||||
getConnectionData(authority: string): IRemoteConnectionData | null {
|
||||
if (!this._resolveAuthorityRequests.has(authority)) {
|
||||
return null;
|
||||
}
|
||||
const request = this._resolveAuthorityRequests.get(authority)!;
|
||||
if (!request.value) {
|
||||
if (!request.result) {
|
||||
return null;
|
||||
}
|
||||
const connectionToken = this._connectionTokens.get(authority);
|
||||
return {
|
||||
host: request.value.authority.host,
|
||||
port: request.value.authority.port,
|
||||
host: request.result.authority.host,
|
||||
port: request.result.authority.port,
|
||||
connectionToken: connectionToken
|
||||
};
|
||||
}
|
||||
|
@ -107,4 +122,11 @@ export class RemoteAuthorityResolverService extends Disposable implements IRemot
|
|||
RemoteAuthorities.setConnectionToken(authority, connectionToken);
|
||||
this._onDidChangeConnectionData.fire();
|
||||
}
|
||||
|
||||
_setCanonicalURIProvider(provider: (uri: URI) => Promise<URI>): void {
|
||||
this._canonicalURIProvider = provider;
|
||||
this._canonicalURIRequests.forEach((value) => {
|
||||
this._canonicalURIProvider!(value.input).then((uri) => value.resolve(uri), (err) => value.reject(err));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
17
src/vs/vscode.proposed.d.ts
vendored
17
src/vs/vscode.proposed.d.ts
vendored
|
@ -144,7 +144,24 @@ declare module 'vscode' {
|
|||
}
|
||||
|
||||
export interface RemoteAuthorityResolver {
|
||||
/**
|
||||
* Resolve the authority part of the current opened `vscode-remote://` URI.
|
||||
*
|
||||
* This method will be invoked once during the startup of VS Code and again each time
|
||||
* VS Code detects a disconnection.
|
||||
*
|
||||
* @param authority The authority part of the current opened `vscode-remote://` URI.
|
||||
* @param context A context indicating if this is the first call or a subsequent call.
|
||||
*/
|
||||
resolve(authority: string, context: RemoteAuthorityResolverContext): ResolverResult | Thenable<ResolverResult>;
|
||||
|
||||
/**
|
||||
* Get the canonical URI (if applicable) for a `vscode-remote://` URI.
|
||||
*
|
||||
* @returns The canonical URI or undefined if the uri is already canonical.
|
||||
*/
|
||||
getCanonicalURI?(uri: Uri): ProviderResult<Uri>;
|
||||
|
||||
/**
|
||||
* Can be optionally implemented if the extension can forward ports better than the core.
|
||||
* When not implemented, the core will use its default forwarding logic.
|
||||
|
|
|
@ -1297,6 +1297,7 @@ export type IResolveAuthorityResult = IResolveAuthorityErrorResult | IResolveAut
|
|||
|
||||
export interface ExtHostExtensionServiceShape {
|
||||
$resolveAuthority(remoteAuthority: string, resolveAttempt: number): Promise<IResolveAuthorityResult>;
|
||||
$getCanonicalURI(remoteAuthority: string, uri: UriComponents): Promise<UriComponents>;
|
||||
$startExtensionHost(enabledExtensionIds: ExtensionIdentifier[]): Promise<void>;
|
||||
$extensionTestsExecute(): Promise<number>;
|
||||
$extensionTestsExit(code: number): Promise<void>;
|
||||
|
|
|
@ -7,10 +7,10 @@ import * as nls from 'vs/nls';
|
|||
import * as path from 'vs/base/common/path';
|
||||
import * as performance from 'vs/base/common/performance';
|
||||
import { originalFSPath, joinPath } from 'vs/base/common/resources';
|
||||
import { Barrier, timeout } from 'vs/base/common/async';
|
||||
import { asPromise, Barrier, timeout } from 'vs/base/common/async';
|
||||
import { dispose, toDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { TernarySearchTree } from 'vs/base/common/map';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { ExtHostExtensionServiceShape, IInitData, MainContext, MainThreadExtensionServiceShape, MainThreadTelemetryShape, MainThreadWorkspaceShape, IResolveAuthorityResult } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostConfiguration, IExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
|
||||
|
@ -631,7 +631,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
|
|||
|
||||
// -- called by main thread
|
||||
|
||||
public async $resolveAuthority(remoteAuthority: string, resolveAttempt: number): Promise<IResolveAuthorityResult> {
|
||||
private async _activateAndGetResolver(remoteAuthority: string): Promise<{ authorityPrefix: string; resolver: vscode.RemoteAuthorityResolver | undefined; }> {
|
||||
const authorityPlusIndex = remoteAuthority.indexOf('+');
|
||||
if (authorityPlusIndex === -1) {
|
||||
throw new Error(`Not an authority that can be resolved!`);
|
||||
|
@ -641,7 +641,12 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
|
|||
await this._almostReadyToRunExtensions.wait();
|
||||
await this._activateByEvent(`onResolveRemoteAuthority:${authorityPrefix}`, false);
|
||||
|
||||
const resolver = this._resolvers[authorityPrefix];
|
||||
return { authorityPrefix, resolver: this._resolvers[authorityPrefix] };
|
||||
}
|
||||
|
||||
public async $resolveAuthority(remoteAuthority: string, resolveAttempt: number): Promise<IResolveAuthorityResult> {
|
||||
|
||||
const { authorityPrefix, resolver } = await this._activateAndGetResolver(remoteAuthority);
|
||||
if (!resolver) {
|
||||
return {
|
||||
type: 'error',
|
||||
|
@ -695,6 +700,28 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
|
|||
}
|
||||
}
|
||||
|
||||
public async $getCanonicalURI(remoteAuthority: string, uriComponents: UriComponents): Promise<UriComponents> {
|
||||
|
||||
const { authorityPrefix, resolver } = await this._activateAndGetResolver(remoteAuthority);
|
||||
if (!resolver) {
|
||||
throw new Error(`Cannot get canonical URI because no remote extension is installed to resolve ${authorityPrefix}`);
|
||||
}
|
||||
|
||||
const uri = URI.revive(uriComponents);
|
||||
|
||||
if (typeof resolver.getCanonicalURI === 'undefined') {
|
||||
// resolver cannot compute canonical URI
|
||||
return uri;
|
||||
}
|
||||
|
||||
const result = await asPromise(() => resolver.getCanonicalURI!(uri));
|
||||
if (!result) {
|
||||
return uri;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public $startExtensionHost(enabledExtensionIds: ExtensionIdentifier[]): Promise<void> {
|
||||
this._registry.keepOnly(enabledExtensionIds);
|
||||
return this._startExtensionHost();
|
||||
|
|
|
@ -24,6 +24,7 @@ import { IExtensionHost, ExtensionHostKind, ActivationKind } from 'vs/workbench/
|
|||
import { ExtensionActivationReason } from 'vs/workbench/api/common/extHostExtensionActivator';
|
||||
import { CATEGORIES } from 'vs/workbench/common/actions';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
// Enable to see detailed message communication between window and extension host
|
||||
const LOG_EXTENSION_HOST_COMMUNICATION = false;
|
||||
|
@ -285,6 +286,15 @@ export class ExtensionHostManager extends Disposable {
|
|||
}
|
||||
}
|
||||
|
||||
public async getCanonicalURI(remoteAuthority: string, uri: URI): Promise<URI> {
|
||||
const proxy = await this._getProxy();
|
||||
if (!proxy) {
|
||||
throw new Error(`Cannot resolve canonical URI`);
|
||||
}
|
||||
const result = await proxy.$getCanonicalURI(remoteAuthority, uri);
|
||||
return URI.revive(result);
|
||||
}
|
||||
|
||||
public async start(enabledExtensionIds: ExtensionIdentifier[]): Promise<void> {
|
||||
const proxy = await this._getProxy();
|
||||
if (!proxy) {
|
||||
|
|
|
@ -343,6 +343,16 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
|||
let remoteExtensions: IExtensionDescription[] = [];
|
||||
|
||||
if (remoteAuthority) {
|
||||
|
||||
this._remoteAuthorityResolverService._setCanonicalURIProvider(async (uri) => {
|
||||
if (uri.authority !== remoteAuthority) {
|
||||
// The current remote authority resolver cannot give the canonical URI for this URI
|
||||
return uri;
|
||||
}
|
||||
const localProcessExtensionHost = this._getExtensionHostManager(ExtensionHostKind.LocalProcess)!;
|
||||
return localProcessExtensionHost.getCanonicalURI(remoteAuthority, uri);
|
||||
});
|
||||
|
||||
let resolverResult: ResolverResult;
|
||||
|
||||
try {
|
||||
|
@ -397,6 +407,10 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
|||
}
|
||||
|
||||
updateProxyConfigurationsScope(remoteEnv.useHostProxy ? ConfigurationScope.APPLICATION : ConfigurationScope.MACHINE);
|
||||
} else {
|
||||
|
||||
this._remoteAuthorityResolverService._setCanonicalURIProvider(async (uri) => uri);
|
||||
|
||||
}
|
||||
|
||||
await this._startLocalExtensionHost(localExtensions, remoteAuthority, remoteEnv, remoteExtensions);
|
||||
|
|
Loading…
Reference in a new issue