提交 e29d2530 编写于 作者: A Alex Ross

Add notification for automatic port forwarding

Fixes microsoft/vscode-remote-release#3662
上级 157255fa
......@@ -19,7 +19,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
import { FilterViewPaneContainer } from 'vs/workbench/browser/parts/views/viewsViewlet';
import { VIEWLET_ID } from 'vs/workbench/contrib/remote/common/remote.contribution';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IViewDescriptor, IViewsRegistry, Extensions, ViewContainerLocation, IViewContainersRegistry, IViewDescriptorService, IAddedViewDescriptorRef } from 'vs/workbench/common/views';
import { IViewDescriptor, IViewsRegistry, Extensions, ViewContainerLocation, IViewContainersRegistry, IViewDescriptorService, IAddedViewDescriptorRef, IViewsService } from 'vs/workbench/common/views';
import { Registry } from 'vs/platform/registry/common/platform';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { IOpenerService } from 'vs/platform/opener/common/opener';
......@@ -37,14 +37,14 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { ReconnectionWaitEvent, PersistentConnectionEventType } from 'vs/platform/remote/common/remoteAgentConnection';
import Severity from 'vs/base/common/severity';
import { ReloadWindowAction } from 'vs/workbench/browser/actions/windowActions';
import { IDisposable } from 'vs/base/common/lifecycle';
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { SwitchRemoteViewItem, SwitchRemoteAction } from 'vs/workbench/contrib/remote/browser/explorerViewItems';
import { Action, IActionViewItem, IAction } from 'vs/base/common/actions';
import { isStringArray } from 'vs/base/common/types';
import { IRemoteExplorerService } from 'vs/workbench/services/remote/common/remoteExplorerService';
import { IRemoteExplorerService, MakeAddress } from 'vs/workbench/services/remote/common/remoteExplorerService';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { TunnelPanelDescriptor, TunnelViewModel, forwardedPortsViewEnabled } from 'vs/workbench/contrib/remote/browser/tunnelView';
import { TunnelPanelDescriptor, TunnelViewModel, forwardedPortsViewEnabled, OpenPortInBrowserAction } from 'vs/workbench/contrib/remote/browser/tunnelView';
import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
import { ITreeRenderer, ITreeNode, IAsyncDataSource } from 'vs/base/browser/ui/tree/tree';
......@@ -56,6 +56,8 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { RemoteStatusIndicator } from 'vs/workbench/contrib/remote/browser/remoteIndicator';
import { inQuickPickContextKeyValue } from 'vs/workbench/browser/quickaccess';
import { Codicon, registerIcon } from 'vs/base/common/codicons';
import { INotificationService, IPromptChoice } from 'vs/platform/notification/common/notification';
import { UrlFinder } from 'vs/workbench/contrib/remote/browser/urlFinder';
import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
export interface HelpInformation {
......@@ -485,8 +487,7 @@ export class RemoteViewPaneContainer extends FilterViewPaneContainer implements
@IRemoteExplorerService private readonly remoteExplorerService: IRemoteExplorerService,
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
@ITerminalService private readonly terminalService: ITerminalService
@IViewDescriptorService viewDescriptorService: IViewDescriptorService
) {
super(VIEWLET_ID, remoteExplorerService.onDidChangeTargetType, configurationService, layoutService, telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService, viewDescriptorService);
this.addConstantViewDescriptors([this.helpPanelDescriptor]);
......@@ -561,7 +562,7 @@ export class RemoteViewPaneContainer extends FilterViewPaneContainer implements
// This context key is set to false in the constructor, but is expected to be changed by resolver extensions to enable the forwarded ports view.
const viewEnabled: boolean = !!forwardedPortsViewEnabled.getValue(this.contextKeyService);
if (this.environmentService.configuration.remoteAuthority && !this.tunnelPanelDescriptor && viewEnabled) {
this.tunnelPanelDescriptor = new TunnelPanelDescriptor(new TunnelViewModel(this.remoteExplorerService, this.terminalService), this.environmentService);
this.tunnelPanelDescriptor = new TunnelPanelDescriptor(new TunnelViewModel(this.remoteExplorerService), this.environmentService);
const viewsRegistry = Registry.as<IViewsRegistry>(Extensions.ViewsRegistry);
viewsRegistry.registerViews([this.tunnelPanelDescriptor!], this.viewContainer);
}
......@@ -840,6 +841,37 @@ class RemoteAgentConnectionStatusListener implements IWorkbenchContribution {
}
}
class AutomaticPortForwarding extends Disposable implements IWorkbenchContribution {
constructor(
@ITerminalService readonly terminalService: ITerminalService,
@INotificationService readonly notificationService: INotificationService,
@IOpenerService readonly openerService: IOpenerService,
@IViewsService readonly viewsService: IViewsService,
@IRemoteExplorerService readonly remoteExplorerService: IRemoteExplorerService
) {
super();
const urlFinder = this._register(new UrlFinder(terminalService));
this._register(urlFinder.onDidMatchLocalUrl(async (localUrl) => {
const forwarded = await this.remoteExplorerService.forward(localUrl);
if (forwarded) {
const address = MakeAddress(forwarded.tunnelRemoteHost, forwarded.tunnelRemotePort);
const message = nls.localize('remote.tunnelsView.automaticForward', "{0} has been forwarded to {1} locally.",
address, forwarded.localAddress);
const browserChoice: IPromptChoice = {
label: OpenPortInBrowserAction.LABEL,
run: () => OpenPortInBrowserAction.run(this.remoteExplorerService.tunnelModel, openerService, address)
};
const showChoice: IPromptChoice = {
label: nls.localize('remote.tunnelsView.showView', "Show Tunnels View"),
run: () => viewsService.openViewContainer(VIEWLET_ID)
};
notificationService.prompt(Severity.Info, message, [browserChoice, showChoice]);
}
}));
}
}
const workbenchContributionsRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
workbenchContributionsRegistry.registerWorkbenchContribution(RemoteAgentConnectionStatusListener, LifecyclePhase.Eventually);
workbenchContributionsRegistry.registerWorkbenchContribution(RemoteStatusIndicator, LifecyclePhase.Starting);
workbenchContributionsRegistry.registerWorkbenchContribution(AutomaticPortForwarding, LifecyclePhase.Eventually);
......@@ -42,8 +42,6 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { UrlFinder } from 'vs/workbench/contrib/remote/browser/urlFinder';
export const forwardedPortsViewEnabled = new RawContextKey<boolean>('forwardedPortsViewEnabled', false);
......@@ -74,8 +72,7 @@ export class TunnelViewModel extends Disposable implements ITunnelViewModel {
private _candidates: Map<string, { host: string, port: number, detail: string }> = new Map();
constructor(
@IRemoteExplorerService private readonly remoteExplorerService: IRemoteExplorerService,
@ITerminalService readonly terminalService: ITerminalService) {
@IRemoteExplorerService private readonly remoteExplorerService: IRemoteExplorerService) {
super();
this.model = remoteExplorerService.tunnelModel;
this._register(this.model.onForwardPort(() => this._onForwardedPortsChanged.fire()));
......@@ -89,11 +86,6 @@ export class TunnelViewModel extends Disposable implements ITunnelViewModel {
remotePort: 0,
description: ''
};
const urlFinder = this._register(new UrlFinder(terminalService));
this._register(urlFinder.onDidMatchLocalUrl(localUrl => {
this.model.forward(localUrl);
}));
}
async groups(): Promise<ITunnelGroup[]> {
......@@ -866,7 +858,7 @@ namespace ClosePortAction {
}
}
namespace OpenPortInBrowserAction {
export namespace OpenPortInBrowserAction {
export const ID = 'remote.tunnel.open';
export const LABEL = nls.localize('remote.tunnel.open', "Open in Browser");
......@@ -876,15 +868,19 @@ namespace OpenPortInBrowserAction {
const model = accessor.get(IRemoteExplorerService).tunnelModel;
const openerService = accessor.get(IOpenerService);
const key = MakeAddress(arg.remoteHost, arg.remotePort);
const tunnel = model.forwarded.get(key) || model.detected.get(key);
let address: string | undefined;
if (tunnel && tunnel.localAddress && (address = model.address(tunnel.remoteHost, tunnel.remotePort))) {
return openerService.open(URI.parse('http://' + address));
}
return Promise.resolve();
return run(model, openerService, key);
}
};
}
export function run(model: TunnelModel, openerService: IOpenerService, key: string) {
const tunnel = model.forwarded.get(key) || model.detected.get(key);
let address: string | undefined;
if (tunnel && tunnel.localAddress && (address = model.address(tunnel.remoteHost, tunnel.remotePort))) {
return openerService.open(URI.parse('http://' + address));
}
return Promise.resolve();
}
}
namespace CopyAddressAction {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册