提交 71570aa4 编写于 作者: A Alex Ross

Add candidate port filtering to proposed API

上级 872096e1
......@@ -23,7 +23,6 @@ export interface TunnelDescription {
}
export interface TunnelInformation {
environmentTunnels?: TunnelDescription[];
hideCandidatePorts?: boolean;
}
export interface ResolverResult {
......
......@@ -108,7 +108,6 @@ declare module 'vscode' {
*/
environmentTunnels?: TunnelDescription[];
hideCandidatePorts?: boolean;
}
export type ResolverResult = ResolvedAuthority & ResolvedOptions & TunnelInformation;
......@@ -128,6 +127,11 @@ declare module 'vscode' {
* When implemented, the core will use this to forward ports.
*/
tunnelFactory?: (tunnelOptions: TunnelOptions) => Thenable<Tunnel> | undefined;
/**
* Provides filtering for candidate ports.
*/
showCandidatePort?: (host: string, port: number, detail: string) => Thenable<boolean>;
}
export namespace workspace {
......
......@@ -59,6 +59,22 @@ export class MainThreadTunnelService implements MainThreadTunnelServiceShape {
this.tunnelService.setTunnelProvider(tunnelProvider);
}
async $setCandidateFilter(): Promise<void> {
this.remoteExplorerService.setCandidateFilter(async (candidates: { host: string, port: number, detail: string }[]): Promise<{ host: string, port: number, detail: string }[]> => {
const filters: boolean[] = await this._proxy.$filterCandidates(candidates);
const filteredCandidates: { host: string, port: number, detail: string }[] = [];
if (filters.length !== candidates.length) {
return candidates;
}
for (let i = 0; i < candidates.length; i++) {
if (filters[i]) {
filteredCandidates.push(candidates[i]);
}
}
return filteredCandidates;
});
}
dispose(): void {
//
}
......
......@@ -787,6 +787,7 @@ export interface MainThreadTunnelServiceShape extends IDisposable {
$closeTunnel(remote: { host: string, port: number }): Promise<void>;
$registerCandidateFinder(): Promise<void>;
$setTunnelProvider(): Promise<void>;
$setCandidateFilter(): Promise<void>;
}
// -- extension host
......@@ -1421,6 +1422,7 @@ export interface MainThreadThemingShape extends IDisposable {
export interface ExtHostTunnelServiceShape {
$findCandidatePorts(): Promise<{ host: string, port: number, detail: string }[]>;
$filterCandidates(candidates: { host: string, port: number, detail: string }[]): Promise<boolean[]>;
$forwardPort(tunnelOptions: TunnelOptions): Promise<TunnelDto> | undefined;
$closeTunnel(remote: { host: string, port: number }): Promise<void>;
}
......
......@@ -645,7 +645,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
try {
const result = await resolver.resolve(remoteAuthority, { resolveAttempt });
this._disposables.add(await this._extHostTunnelService.setForwardPortProvider(resolver));
this._disposables.add(await this._extHostTunnelService.setTunnelExtensionFunctions(resolver));
// Split merged API result into separate authority/options
const authority: ResolvedAuthority = {
......@@ -662,7 +662,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
value: {
authority,
options,
tunnelInformation: { environmentTunnels: result.environmentTunnels, hideCandidatePorts: result.hideCandidatePorts }
tunnelInformation: { environmentTunnels: result.environmentTunnels }
}
};
} catch (err) {
......
......@@ -31,7 +31,7 @@ export interface Tunnel extends vscode.Disposable {
export interface IExtHostTunnelService extends ExtHostTunnelServiceShape {
readonly _serviceBrand: undefined;
openTunnel(forward: TunnelOptions): Promise<vscode.Tunnel | undefined>;
setForwardPortProvider(provider: vscode.RemoteAuthorityResolver | undefined): Promise<IDisposable>;
setTunnelExtensionFunctions(provider: vscode.RemoteAuthorityResolver | undefined): Promise<IDisposable>;
}
export const IExtHostTunnelService = createDecorator<IExtHostTunnelService>('IExtHostTunnelService');
......@@ -44,7 +44,10 @@ export class ExtHostTunnelService implements IExtHostTunnelService {
async $findCandidatePorts(): Promise<{ host: string, port: number; detail: string; }[]> {
return [];
}
async setForwardPortProvider(provider: vscode.RemoteAuthorityResolver | undefined): Promise<IDisposable> { return { dispose: () => { } }; }
async $filterCandidates(candidates: { host: string, port: number, detail: string }[]): Promise<boolean[]> {
return candidates.map(() => true);
}
async setTunnelExtensionFunctions(provider: vscode.RemoteAuthorityResolver | undefined): Promise<IDisposable> { return { dispose: () => { } }; }
$forwardPort(tunnelOptions: TunnelOptions): Promise<TunnelDto> | undefined { return undefined; }
async $closeTunnel(remote: { host: string, port: number }): Promise<void> { }
......
......@@ -37,6 +37,7 @@ export class ExtHostTunnelService extends Disposable implements IExtHostTunnelSe
readonly _serviceBrand: undefined;
private readonly _proxy: MainThreadTunnelServiceShape;
private _forwardPortProvider: ((tunnelOptions: TunnelOptions) => Thenable<vscode.Tunnel> | undefined) | undefined;
private _showCandidatePort: (host: string, port: number, detail: string) => Thenable<boolean> = () => { return Promise.resolve(true); };
private _extensionTunnels: Map<string, Map<number, vscode.Tunnel>> = new Map();
constructor(
......@@ -65,10 +66,22 @@ export class ExtHostTunnelService extends Disposable implements IExtHostTunnelSe
return this._proxy.$registerCandidateFinder();
}
async setForwardPortProvider(provider: vscode.RemoteAuthorityResolver | undefined): Promise<IDisposable> {
if (provider && provider.tunnelFactory) {
this._forwardPortProvider = provider.tunnelFactory;
await this._proxy.$setTunnelProvider();
$filterCandidates(candidates: { host: string, port: number, detail: string }[]): Promise<boolean[]> {
return Promise.all(candidates.map(candidate => {
return this._showCandidatePort(candidate.host, candidate.port, candidate.detail);
}));
}
async setTunnelExtensionFunctions(provider: vscode.RemoteAuthorityResolver | undefined): Promise<IDisposable> {
if (provider) {
if (provider.showCandidatePort) {
this._showCandidatePort = provider.showCandidatePort;
await this._proxy.$setCandidateFilter();
}
if (provider.tunnelFactory) {
this._forwardPortProvider = provider.tunnelFactory;
await this._proxy.$setTunnelProvider();
}
} else {
this._forwardPortProvider = undefined;
}
......@@ -128,9 +141,7 @@ export class ExtHostTunnelService extends Disposable implements IExtHostTunnelSe
const childStat = fs.statSync(childUri.fsPath);
if (childStat.isDirectory() && !isNaN(pid)) {
const cwd = fs.readlinkSync(resources.joinPath(childUri, 'cwd').fsPath);
const rawCmd = fs.readFileSync(resources.joinPath(childUri, 'cmdline').fsPath, 'utf8');
const nullIndex = rawCmd.indexOf('\0');
const cmd = rawCmd.substr(0, nullIndex > 0 ? nullIndex : rawCmd.length).trim();
const cmd = fs.readFileSync(resources.joinPath(childUri, 'cmdline').fsPath, 'utf8');
processes.push({ pid, cwd, cmd });
}
} catch (e) {
......
......@@ -59,7 +59,6 @@ export function MakeAddress(host: string, port: number): string {
export class TunnelModel extends Disposable {
readonly forwarded: Map<string, Tunnel>;
readonly detected: Map<string, Tunnel>;
private _candidatesEnabled: boolean = true;
private _onForwardPort: Emitter<Tunnel> = new Emitter();
public onForwardPort: Event<Tunnel> = this._onForwardPort.event;
private _onClosePort: Emitter<{ host: string, port: number }> = new Emitter();
......@@ -70,6 +69,7 @@ export class TunnelModel extends Disposable {
private _candidateFinder: (() => Promise<{ host: string, port: number, detail: string }[]>) | undefined;
private _onCandidatesChanged: Emitter<void> = new Emitter();
public onCandidatesChanged: Event<void> = this._onCandidatesChanged.event;
private _candidateFilter: ((candidates: { host: string, port: number, detail: string }[]) => Promise<{ host: string, port: number, detail: string }[]>) | undefined;
constructor(
@ITunnelService private readonly tunnelService: ITunnelService,
......@@ -187,29 +187,31 @@ export class TunnelModel extends Disposable {
});
}
set candidateEnabled(enabled: boolean) {
this._candidatesEnabled = enabled;
}
registerCandidateFinder(finder: () => Promise<{ host: string, port: number, detail: string }[]>): void {
this._candidateFinder = finder;
}
setCandidateFilter(filter: (candidates: { host: string, port: number, detail: string }[]) => Promise<{ host: string, port: number, detail: string }[]>): void {
this._candidateFilter = filter;
}
get candidates(): Promise<{ host: string, port: number, detail: string }[]> {
return this.updateCandidates().then(() => this._candidates);
}
private async updateCandidates(): Promise<void> {
if (!this._candidatesEnabled) {
this._candidates = [];
return;
}
if (this._candidateFinder) {
this._candidates = (await this._candidateFinder()).map(value => {
let candidates = await this._candidateFinder();
if (this._candidateFilter && (candidates.length > 0)) {
candidates = await this._candidateFilter(candidates);
}
this._candidates = candidates.map(value => {
const nullIndex = value.detail.indexOf('\0');
const detail = value.detail.substr(0, nullIndex > 0 ? nullIndex : value.detail.length).trim();
return {
host: ToLocalHost(value.host),
port: value.port,
detail: value.detail
detail
};
});
}
......@@ -233,6 +235,7 @@ export interface IRemoteExplorerService {
close(remote: { host: string, port: number }): Promise<void>;
setTunnelInformation(tunnelInformation: TunnelInformation | undefined): void;
registerCandidateFinder(finder: () => Promise<{ host: string, port: number, detail: string }[]>): void;
setCandidateFilter(filter: (candidates: { host: string, port: number, detail: string }[]) => Promise<{ host: string, port: number, detail: string }[]>): void;
refresh(): Promise<void>;
}
......@@ -285,8 +288,6 @@ class RemoteExplorerService implements IRemoteExplorerService {
if (tunnelInformation && tunnelInformation.environmentTunnels) {
this.tunnelModel.addEnvironmentTunnels(tunnelInformation.environmentTunnels);
}
this.tunnelModel.candidateEnabled = tunnelInformation ? (tunnelInformation.hideCandidatePorts !== true) : true;
}
setEditable(tunnelItem: ITunnelItem | undefined, data: IEditableData | null): void {
......@@ -309,6 +310,10 @@ class RemoteExplorerService implements IRemoteExplorerService {
this.tunnelModel.registerCandidateFinder(finder);
}
setCandidateFilter(filter: (candidates: { host: string, port: number, detail: string }[]) => Promise<{ host: string, port: number, detail: string }[]>): void {
this.tunnelModel.setCandidateFilter(filter);
}
refresh(): Promise<void> {
return this.tunnelModel.refresh();
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册