@codingame/monaco-vscode-1b4486de-4fe4-59c4-9e6d-34f265ff6625-common 12.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,847 @@
1
+
2
+ import { __decorate, __param } from 'vscode/external/tslib/tslib.es6';
3
+ import { localize, localize2 } from 'vscode/vscode/vs/nls';
4
+ import { Disposable, MutableDisposable } from 'vscode/vscode/vs/base/common/lifecycle';
5
+ import { Extensions, ViewContainerLocation } from 'vscode/vscode/vs/workbench/common/views';
6
+ import { TUNNEL_VIEW_ID, TUNNEL_VIEW_CONTAINER_ID, PORT_AUTO_SOURCE_SETTING, PORT_AUTO_FALLBACK_SETTING, PORT_AUTO_SOURCE_SETTING_PROCESS, PORT_AUTO_SOURCE_SETTING_HYBRID, PORT_AUTO_SOURCE_SETTING_OUTPUT, PORT_AUTO_FORWARD_SETTING, PortsEnablement } from 'vscode/vscode/vs/workbench/services/remote/common/remoteExplorerService';
7
+ import { IRemoteExplorerService } from 'vscode/vscode/vs/workbench/services/remote/common/remoteExplorerService.service';
8
+ import { forwardedPortsFeaturesEnabled, forwardedPortsViewEnabled, TunnelSource, OnPortForward, makeAddress, mapHasAddressLocalhostOrAllInterfaces, TunnelCloseReason, AutoTunnelSource } from 'vscode/vscode/vs/workbench/services/remote/common/tunnelModel';
9
+ import { ForwardPortAction, TunnelPanelDescriptor, TunnelViewModel, OpenPortInPreviewAction, OpenPortInBrowserAction, TunnelPanel, openPreviewEnabledContext } from './tunnelView.js';
10
+ import { IContextKeyService } from 'vscode/vscode/vs/platform/contextkey/common/contextkey.service';
11
+ import { IWorkbenchEnvironmentService } from 'vscode/vscode/vs/workbench/services/environment/common/environmentService.service';
12
+ import { Registry } from 'vscode/vscode/vs/platform/registry/common/platform';
13
+ import { StatusbarAlignment } from 'vscode/vscode/vs/workbench/services/statusbar/browser/statusbar';
14
+ import { IStatusbarService } from 'vscode/vscode/vs/workbench/services/statusbar/browser/statusbar.service';
15
+ import { UrlFinder } from './urlFinder.js';
16
+ import Severity from 'vscode/vscode/vs/base/common/severity';
17
+ import { ConfigurationTarget } from 'vscode/vscode/vs/platform/configuration/common/configuration';
18
+ import { INotificationService } from 'vscode/vscode/vs/platform/notification/common/notification.service';
19
+ import { IOpenerService } from 'vscode/vscode/vs/platform/opener/common/opener.service';
20
+ import { ITerminalService } from 'vscode/vscode/vs/workbench/contrib/terminal/browser/terminal.service';
21
+ import { IDebugService } from 'vscode/vscode/vs/workbench/contrib/debug/common/debug.service';
22
+ import { IRemoteAgentService } from 'vscode/vscode/vs/workbench/services/remote/common/remoteAgentService.service';
23
+ import { OperatingSystem, isWeb } from 'vscode/vscode/vs/base/common/platform';
24
+ import { TunnelPrivacyId } from 'vscode/vscode/vs/platform/tunnel/common/tunnel';
25
+ import { ITunnelService } from 'vscode/vscode/vs/platform/tunnel/common/tunnel.service';
26
+ import { SyncDescriptor } from 'vscode/vscode/vs/platform/instantiation/common/descriptors';
27
+ import { ViewPaneContainer } from '@codingame/monaco-vscode-9e888134-1a6f-58d9-b0e6-0fc047448366-common/vscode/vs/workbench/browser/parts/views/viewPaneContainer';
28
+ import { NumberBadge } from '@codingame/monaco-vscode-a7c9ae3c-16d2-5d17-86b2-981be7094566-common/vscode/vs/workbench/services/activity/common/activity';
29
+ import { IActivityService } from 'vscode/vscode/vs/workbench/services/activity/common/activity.service';
30
+ import { portsViewIcon } from './remoteIcons.js';
31
+ import { Event } from 'vscode/vscode/vs/base/common/event';
32
+ import { IExternalUriOpenerService } from 'vscode/vscode/vs/workbench/contrib/externalUriOpener/common/externalUriOpenerService.service';
33
+ import { IHostService } from 'vscode/vscode/vs/workbench/services/host/browser/host.service';
34
+ import { Extensions as Extensions$1 } from 'vscode/vscode/vs/platform/configuration/common/configurationRegistry';
35
+ import { ILogService } from 'vscode/vscode/vs/platform/log/common/log.service';
36
+ import { IWorkbenchConfigurationService } from '@codingame/monaco-vscode-422642f2-7e3a-5c1c-9e1e-1d3ef1817346-common/vscode/vs/workbench/services/configuration/common/configuration.service';
37
+ import { Action } from 'vscode/vscode/vs/base/common/actions';
38
+ import { IPreferencesService } from 'vscode/vscode/vs/workbench/services/preferences/common/preferences.service';
39
+ import { StorageScope } from 'vscode/vscode/vs/platform/storage/common/storage';
40
+ import { IStorageService } from 'vscode/vscode/vs/platform/storage/common/storage.service';
41
+
42
+ const VIEWLET_ID = 'workbench.view.remote';
43
+ let ForwardedPortsView = class ForwardedPortsView extends Disposable {
44
+ constructor(contextKeyService, environmentService, remoteExplorerService, tunnelService, activityService, statusbarService) {
45
+ super();
46
+ this.contextKeyService = contextKeyService;
47
+ this.environmentService = environmentService;
48
+ this.remoteExplorerService = remoteExplorerService;
49
+ this.tunnelService = tunnelService;
50
+ this.activityService = activityService;
51
+ this.statusbarService = statusbarService;
52
+ this.contextKeyListener = this._register(( new MutableDisposable()));
53
+ this.activityBadge = this._register(( new MutableDisposable()));
54
+ this._register(( Registry.as(Extensions.ViewsRegistry)).registerViewWelcomeContent(TUNNEL_VIEW_ID, {
55
+ content: this.environmentService.remoteAuthority ? ( localize(
56
+ 8249,
57
+ "No forwarded ports. Forward a port to access your running services locally.\n[Forward a Port]({0})",
58
+ `command:${ForwardPortAction.INLINE_ID}`
59
+ ))
60
+ : ( localize(
61
+ 8250,
62
+ "No forwarded ports. Forward a port to access your locally running services over the internet.\n[Forward a Port]({0})",
63
+ `command:${ForwardPortAction.INLINE_ID}`
64
+ )),
65
+ }));
66
+ this.enableBadgeAndStatusBar();
67
+ this.enableForwardedPortsFeatures();
68
+ }
69
+ async getViewContainer() {
70
+ return ( Registry.as(Extensions.ViewContainersRegistry)).registerViewContainer({
71
+ id: TUNNEL_VIEW_CONTAINER_ID,
72
+ title: ( localize2(8251, "Ports")),
73
+ icon: portsViewIcon,
74
+ ctorDescriptor: ( new SyncDescriptor(
75
+ ViewPaneContainer,
76
+ [TUNNEL_VIEW_CONTAINER_ID, { mergeViewWithContainerWhenSingleView: true }]
77
+ )),
78
+ storageId: TUNNEL_VIEW_CONTAINER_ID,
79
+ hideIfEmpty: true,
80
+ order: 5
81
+ }, ViewContainerLocation.Panel);
82
+ }
83
+ async enableForwardedPortsFeatures() {
84
+ this.contextKeyListener.clear();
85
+ const featuresEnabled = !!forwardedPortsFeaturesEnabled.getValue(this.contextKeyService);
86
+ const viewEnabled = !!forwardedPortsViewEnabled.getValue(this.contextKeyService);
87
+ if (featuresEnabled || viewEnabled) {
88
+ if (!viewEnabled) {
89
+ this.contextKeyService.createKey(forwardedPortsViewEnabled.key, true);
90
+ }
91
+ const viewContainer = await this.getViewContainer();
92
+ const tunnelPanelDescriptor = ( new TunnelPanelDescriptor(( new TunnelViewModel(this.remoteExplorerService, this.tunnelService)), this.environmentService));
93
+ const viewsRegistry = ( Registry.as(Extensions.ViewsRegistry));
94
+ if (viewContainer) {
95
+ this.remoteExplorerService.enablePortsFeatures(!featuresEnabled);
96
+ viewsRegistry.registerViews([tunnelPanelDescriptor], viewContainer);
97
+ }
98
+ }
99
+ else {
100
+ this.contextKeyListener.value = this.contextKeyService.onDidChangeContext(e => {
101
+ if (e.affectsSome(( new Set([...( forwardedPortsFeaturesEnabled.keys()), ...( forwardedPortsViewEnabled.keys())])))) {
102
+ this.enableForwardedPortsFeatures();
103
+ }
104
+ });
105
+ }
106
+ }
107
+ enableBadgeAndStatusBar() {
108
+ const disposable = ( Registry.as(Extensions.ViewsRegistry)).onViewsRegistered(e => {
109
+ if (e.find(view => view.views.find(viewDescriptor => viewDescriptor.id === TUNNEL_VIEW_ID))) {
110
+ this._register(Event.debounce(this.remoteExplorerService.tunnelModel.onForwardPort, (_last, e) => e, 50)(() => {
111
+ this.updateActivityBadge();
112
+ this.updateStatusBar();
113
+ }));
114
+ this._register(Event.debounce(this.remoteExplorerService.tunnelModel.onClosePort, (_last, e) => e, 50)(() => {
115
+ this.updateActivityBadge();
116
+ this.updateStatusBar();
117
+ }));
118
+ this.updateActivityBadge();
119
+ this.updateStatusBar();
120
+ disposable.dispose();
121
+ }
122
+ });
123
+ }
124
+ async updateActivityBadge() {
125
+ if (this.remoteExplorerService.tunnelModel.forwarded.size > 0) {
126
+ this.activityBadge.value = this.activityService.showViewActivity(TUNNEL_VIEW_ID, {
127
+ badge: ( new NumberBadge(
128
+ this.remoteExplorerService.tunnelModel.forwarded.size,
129
+ n => n === 1 ? ( localize(8252, "1 forwarded port")) : ( localize(8253, "{0} forwarded ports", n))
130
+ ))
131
+ });
132
+ }
133
+ else {
134
+ this.activityBadge.clear();
135
+ }
136
+ }
137
+ updateStatusBar() {
138
+ if (!this.entryAccessor) {
139
+ this._register(this.entryAccessor = this.statusbarService.addEntry(this.entry, 'status.forwardedPorts', StatusbarAlignment.LEFT, 40));
140
+ }
141
+ else {
142
+ this.entryAccessor.update(this.entry);
143
+ }
144
+ }
145
+ get entry() {
146
+ let tooltip;
147
+ const count = this.remoteExplorerService.tunnelModel.forwarded.size + this.remoteExplorerService.tunnelModel.detected.size;
148
+ const text = `${count}`;
149
+ if (count === 0) {
150
+ tooltip = ( localize(8254, "No Ports Forwarded"));
151
+ }
152
+ else {
153
+ const allTunnels = Array.from(( this.remoteExplorerService.tunnelModel.forwarded.values()));
154
+ allTunnels.push(...Array.from(( this.remoteExplorerService.tunnelModel.detected.values())));
155
+ tooltip = ( localize(
156
+ 8255,
157
+ "Forwarded Ports: {0}",
158
+ ( allTunnels.map(forwarded => forwarded.remotePort)).join(', ')
159
+ ));
160
+ }
161
+ return {
162
+ name: ( localize(8256, "Forwarded Ports")),
163
+ text: `$(radio-tower) ${text}`,
164
+ ariaLabel: tooltip,
165
+ tooltip,
166
+ command: `${TUNNEL_VIEW_ID}.focus`
167
+ };
168
+ }
169
+ };
170
+ ForwardedPortsView = ( __decorate([
171
+ ( __param(0, IContextKeyService)),
172
+ ( __param(1, IWorkbenchEnvironmentService)),
173
+ ( __param(2, IRemoteExplorerService)),
174
+ ( __param(3, ITunnelService)),
175
+ ( __param(4, IActivityService)),
176
+ ( __param(5, IStatusbarService))
177
+ ], ForwardedPortsView));
178
+ let PortRestore = class PortRestore {
179
+ constructor(remoteExplorerService, logService) {
180
+ this.remoteExplorerService = remoteExplorerService;
181
+ this.logService = logService;
182
+ if (!this.remoteExplorerService.tunnelModel.environmentTunnelsSet) {
183
+ Event.once(this.remoteExplorerService.tunnelModel.onEnvironmentTunnelsSet)(async () => {
184
+ await this.restore();
185
+ });
186
+ }
187
+ else {
188
+ this.restore();
189
+ }
190
+ }
191
+ async restore() {
192
+ this.logService.trace('ForwardedPorts: Doing first restore.');
193
+ return this.remoteExplorerService.restore();
194
+ }
195
+ };
196
+ PortRestore = ( __decorate([
197
+ ( __param(0, IRemoteExplorerService)),
198
+ ( __param(1, ILogService))
199
+ ], PortRestore));
200
+ let AutomaticPortForwarding = class AutomaticPortForwarding extends Disposable {
201
+ constructor(terminalService, notificationService, openerService, externalOpenerService, remoteExplorerService, environmentService, contextKeyService, configurationService, debugService, remoteAgentService, tunnelService, hostService, logService, storageService, preferencesService) {
202
+ super();
203
+ this.terminalService = terminalService;
204
+ this.notificationService = notificationService;
205
+ this.openerService = openerService;
206
+ this.externalOpenerService = externalOpenerService;
207
+ this.remoteExplorerService = remoteExplorerService;
208
+ this.contextKeyService = contextKeyService;
209
+ this.configurationService = configurationService;
210
+ this.debugService = debugService;
211
+ this.tunnelService = tunnelService;
212
+ this.hostService = hostService;
213
+ this.logService = logService;
214
+ this.storageService = storageService;
215
+ this.preferencesService = preferencesService;
216
+ if (!environmentService.remoteAuthority) {
217
+ return;
218
+ }
219
+ configurationService.whenRemoteConfigurationLoaded().then(() => remoteAgentService.getEnvironment()).then(environment => {
220
+ this.setup(environment);
221
+ this._register(configurationService.onDidChangeConfiguration(e => {
222
+ if (e.affectsConfiguration(PORT_AUTO_SOURCE_SETTING)) {
223
+ this.setup(environment);
224
+ }
225
+ else if (e.affectsConfiguration(PORT_AUTO_FALLBACK_SETTING) && !this.portListener) {
226
+ this.listenForPorts();
227
+ }
228
+ }));
229
+ });
230
+ if (!this.storageService.getBoolean('processPortForwardingFallback', StorageScope.WORKSPACE, true)) {
231
+ this.configurationService.updateValue(PORT_AUTO_FALLBACK_SETTING, 0, ConfigurationTarget.WORKSPACE);
232
+ }
233
+ }
234
+ getPortAutoFallbackNumber() {
235
+ const fallbackAt = this.configurationService.inspect(PORT_AUTO_FALLBACK_SETTING);
236
+ if ((fallbackAt.value !== undefined) && (fallbackAt.value === 0 || (fallbackAt.value !== fallbackAt.defaultValue))) {
237
+ return fallbackAt.value;
238
+ }
239
+ const inspectSource = this.configurationService.inspect(PORT_AUTO_SOURCE_SETTING);
240
+ if (inspectSource.applicationValue === PORT_AUTO_SOURCE_SETTING_PROCESS ||
241
+ inspectSource.userValue === PORT_AUTO_SOURCE_SETTING_PROCESS ||
242
+ inspectSource.userLocalValue === PORT_AUTO_SOURCE_SETTING_PROCESS ||
243
+ inspectSource.userRemoteValue === PORT_AUTO_SOURCE_SETTING_PROCESS ||
244
+ inspectSource.workspaceFolderValue === PORT_AUTO_SOURCE_SETTING_PROCESS ||
245
+ inspectSource.workspaceValue === PORT_AUTO_SOURCE_SETTING_PROCESS) {
246
+ return 0;
247
+ }
248
+ return fallbackAt.value ?? 20;
249
+ }
250
+ listenForPorts() {
251
+ let fallbackAt = this.getPortAutoFallbackNumber();
252
+ if (fallbackAt === 0) {
253
+ this.portListener?.dispose();
254
+ return;
255
+ }
256
+ if (this.procForwarder && !this.portListener && (this.configurationService.getValue(PORT_AUTO_SOURCE_SETTING) === PORT_AUTO_SOURCE_SETTING_PROCESS)) {
257
+ this.portListener = this._register(this.remoteExplorerService.tunnelModel.onForwardPort(async () => {
258
+ fallbackAt = this.getPortAutoFallbackNumber();
259
+ if (fallbackAt === 0) {
260
+ this.portListener?.dispose();
261
+ return;
262
+ }
263
+ if (Array.from(( this.remoteExplorerService.tunnelModel.forwarded.values())).filter(tunnel => tunnel.source.source === TunnelSource.Auto).length > fallbackAt) {
264
+ await this.configurationService.updateValue(PORT_AUTO_SOURCE_SETTING, PORT_AUTO_SOURCE_SETTING_HYBRID);
265
+ this.notificationService.notify({
266
+ message: ( localize(
267
+ 8257,
268
+ "Over 20 ports have been automatically forwarded. The `process` based automatic port forwarding has been switched to `hybrid` in settings. Some ports may no longer be detected."
269
+ )),
270
+ severity: Severity.Warning,
271
+ actions: {
272
+ primary: [
273
+ ( new Action('switchBack', ( localize(8258, "Undo")), undefined, true, async () => {
274
+ await this.configurationService.updateValue(PORT_AUTO_SOURCE_SETTING, PORT_AUTO_SOURCE_SETTING_PROCESS);
275
+ await this.configurationService.updateValue(PORT_AUTO_FALLBACK_SETTING, 0, ConfigurationTarget.WORKSPACE);
276
+ this.portListener?.dispose();
277
+ this.portListener = undefined;
278
+ })),
279
+ ( new Action('showPortSourceSetting', ( localize(8259, "Show Setting")), undefined, true, async () => {
280
+ await this.preferencesService.openSettings({
281
+ query: 'remote.autoForwardPortsSource'
282
+ });
283
+ }))
284
+ ]
285
+ }
286
+ });
287
+ }
288
+ }));
289
+ }
290
+ else {
291
+ this.portListener?.dispose();
292
+ this.portListener = undefined;
293
+ }
294
+ }
295
+ setup(environment) {
296
+ const alreadyForwarded = this.procForwarder?.forwarded;
297
+ const isSwitch = this.outputForwarder || this.procForwarder;
298
+ this.procForwarder?.dispose();
299
+ this.procForwarder = undefined;
300
+ this.outputForwarder?.dispose();
301
+ this.outputForwarder = undefined;
302
+ if (environment?.os !== OperatingSystem.Linux) {
303
+ if (this.configurationService.inspect(PORT_AUTO_SOURCE_SETTING).default?.value !== PORT_AUTO_SOURCE_SETTING_OUTPUT) {
304
+ ( Registry.as(Extensions$1.Configuration))
305
+ .registerDefaultConfigurations([{ overrides: { 'remote.autoForwardPortsSource': PORT_AUTO_SOURCE_SETTING_OUTPUT } }]);
306
+ }
307
+ this.outputForwarder = this._register(( new OutputAutomaticPortForwarding(
308
+ this.terminalService,
309
+ this.notificationService,
310
+ this.openerService,
311
+ this.externalOpenerService,
312
+ this.remoteExplorerService,
313
+ this.configurationService,
314
+ this.debugService,
315
+ this.tunnelService,
316
+ this.hostService,
317
+ this.logService,
318
+ this.contextKeyService,
319
+ () => false
320
+ )));
321
+ }
322
+ else {
323
+ const useProc = () => (this.configurationService.getValue(PORT_AUTO_SOURCE_SETTING) === PORT_AUTO_SOURCE_SETTING_PROCESS);
324
+ if (useProc()) {
325
+ this.procForwarder = this._register(( new ProcAutomaticPortForwarding(
326
+ false,
327
+ alreadyForwarded,
328
+ !isSwitch,
329
+ this.configurationService,
330
+ this.remoteExplorerService,
331
+ this.notificationService,
332
+ this.openerService,
333
+ this.externalOpenerService,
334
+ this.tunnelService,
335
+ this.hostService,
336
+ this.logService,
337
+ this.contextKeyService
338
+ )));
339
+ }
340
+ else if (this.configurationService.getValue(PORT_AUTO_SOURCE_SETTING) === PORT_AUTO_SOURCE_SETTING_HYBRID) {
341
+ this.procForwarder = this._register(( new ProcAutomaticPortForwarding(
342
+ true,
343
+ alreadyForwarded,
344
+ !isSwitch,
345
+ this.configurationService,
346
+ this.remoteExplorerService,
347
+ this.notificationService,
348
+ this.openerService,
349
+ this.externalOpenerService,
350
+ this.tunnelService,
351
+ this.hostService,
352
+ this.logService,
353
+ this.contextKeyService
354
+ )));
355
+ }
356
+ this.outputForwarder = this._register(( new OutputAutomaticPortForwarding(
357
+ this.terminalService,
358
+ this.notificationService,
359
+ this.openerService,
360
+ this.externalOpenerService,
361
+ this.remoteExplorerService,
362
+ this.configurationService,
363
+ this.debugService,
364
+ this.tunnelService,
365
+ this.hostService,
366
+ this.logService,
367
+ this.contextKeyService,
368
+ useProc
369
+ )));
370
+ }
371
+ this.listenForPorts();
372
+ }
373
+ };
374
+ AutomaticPortForwarding = ( __decorate([
375
+ ( __param(0, ITerminalService)),
376
+ ( __param(1, INotificationService)),
377
+ ( __param(2, IOpenerService)),
378
+ ( __param(3, IExternalUriOpenerService)),
379
+ ( __param(4, IRemoteExplorerService)),
380
+ ( __param(5, IWorkbenchEnvironmentService)),
381
+ ( __param(6, IContextKeyService)),
382
+ ( __param(7, IWorkbenchConfigurationService)),
383
+ ( __param(8, IDebugService)),
384
+ ( __param(9, IRemoteAgentService)),
385
+ ( __param(10, ITunnelService)),
386
+ ( __param(11, IHostService)),
387
+ ( __param(12, ILogService)),
388
+ ( __param(13, IStorageService)),
389
+ ( __param(14, IPreferencesService))
390
+ ], AutomaticPortForwarding));
391
+ class OnAutoForwardedAction extends Disposable {
392
+ static { this.NOTIFY_COOL_DOWN = 5000; }
393
+ constructor(notificationService, remoteExplorerService, openerService, externalOpenerService, tunnelService, hostService, logService, contextKeyService) {
394
+ super();
395
+ this.notificationService = notificationService;
396
+ this.remoteExplorerService = remoteExplorerService;
397
+ this.openerService = openerService;
398
+ this.externalOpenerService = externalOpenerService;
399
+ this.tunnelService = tunnelService;
400
+ this.hostService = hostService;
401
+ this.logService = logService;
402
+ this.contextKeyService = contextKeyService;
403
+ this.alreadyOpenedOnce = ( new Set());
404
+ this.lastNotifyTime = ( new Date());
405
+ this.lastNotifyTime.setFullYear(this.lastNotifyTime.getFullYear() - 1);
406
+ }
407
+ async doAction(tunnels) {
408
+ this.logService.trace(`ForwardedPorts: (OnAutoForwardedAction) Starting action for ${tunnels[0]?.tunnelRemotePort}`);
409
+ this.doActionTunnels = tunnels;
410
+ const tunnel = await this.portNumberHeuristicDelay();
411
+ this.logService.trace(`ForwardedPorts: (OnAutoForwardedAction) Heuristic chose ${tunnel?.tunnelRemotePort}`);
412
+ if (tunnel) {
413
+ const allAttributes = await this.remoteExplorerService.tunnelModel.getAttributes([{ port: tunnel.tunnelRemotePort, host: tunnel.tunnelRemoteHost }]);
414
+ const attributes = allAttributes?.get(tunnel.tunnelRemotePort)?.onAutoForward;
415
+ this.logService.trace(`ForwardedPorts: (OnAutoForwardedAction) onAutoForward action is ${attributes}`);
416
+ switch (attributes) {
417
+ case OnPortForward.OpenBrowserOnce: {
418
+ if (( this.alreadyOpenedOnce.has(tunnel.localAddress))) {
419
+ break;
420
+ }
421
+ this.alreadyOpenedOnce.add(tunnel.localAddress);
422
+ }
423
+ case OnPortForward.OpenBrowser: {
424
+ const address = makeAddress(tunnel.tunnelRemoteHost, tunnel.tunnelRemotePort);
425
+ await OpenPortInBrowserAction.run(this.remoteExplorerService.tunnelModel, this.openerService, address);
426
+ break;
427
+ }
428
+ case OnPortForward.OpenPreview: {
429
+ const address = makeAddress(tunnel.tunnelRemoteHost, tunnel.tunnelRemotePort);
430
+ await OpenPortInPreviewAction.run(this.remoteExplorerService.tunnelModel, this.openerService, this.externalOpenerService, address);
431
+ break;
432
+ }
433
+ case OnPortForward.Silent: break;
434
+ default: {
435
+ const elapsed = ( new Date()).getTime() - this.lastNotifyTime.getTime();
436
+ this.logService.trace(`ForwardedPorts: (OnAutoForwardedAction) time elapsed since last notification ${elapsed} ms`);
437
+ if (elapsed > OnAutoForwardedAction.NOTIFY_COOL_DOWN) {
438
+ await this.showNotification(tunnel);
439
+ }
440
+ }
441
+ }
442
+ }
443
+ }
444
+ hide(removedPorts) {
445
+ if (this.doActionTunnels) {
446
+ this.doActionTunnels = this.doActionTunnels.filter(value => !removedPorts.includes(value.tunnelRemotePort));
447
+ }
448
+ if (this.lastShownPort && removedPorts.indexOf(this.lastShownPort) >= 0) {
449
+ this.lastNotification?.close();
450
+ }
451
+ }
452
+ async portNumberHeuristicDelay() {
453
+ this.logService.trace(`ForwardedPorts: (OnAutoForwardedAction) Starting heuristic delay`);
454
+ if (!this.doActionTunnels || this.doActionTunnels.length === 0) {
455
+ return;
456
+ }
457
+ this.doActionTunnels = this.doActionTunnels.sort((a, b) => a.tunnelRemotePort - b.tunnelRemotePort);
458
+ const firstTunnel = this.doActionTunnels.shift();
459
+ if (firstTunnel.tunnelRemotePort % 1000 === 0) {
460
+ this.logService.trace(`ForwardedPorts: (OnAutoForwardedAction) Heuristic chose tunnel because % 1000: ${firstTunnel.tunnelRemotePort}`);
461
+ this.newerTunnel = firstTunnel;
462
+ return firstTunnel;
463
+ }
464
+ else if (firstTunnel.tunnelRemotePort < 10000 && firstTunnel.tunnelRemotePort !== 9229) {
465
+ this.logService.trace(`ForwardedPorts: (OnAutoForwardedAction) Heuristic chose tunnel because < 10000: ${firstTunnel.tunnelRemotePort}`);
466
+ this.newerTunnel = firstTunnel;
467
+ return firstTunnel;
468
+ }
469
+ this.logService.trace(`ForwardedPorts: (OnAutoForwardedAction) Waiting for "better" tunnel than ${firstTunnel.tunnelRemotePort}`);
470
+ this.newerTunnel = undefined;
471
+ return ( new Promise(resolve => {
472
+ setTimeout(() => {
473
+ if (this.newerTunnel) {
474
+ resolve(undefined);
475
+ }
476
+ else if (this.doActionTunnels?.includes(firstTunnel)) {
477
+ resolve(firstTunnel);
478
+ }
479
+ else {
480
+ resolve(undefined);
481
+ }
482
+ }, 3000);
483
+ }));
484
+ }
485
+ async basicMessage(tunnel) {
486
+ const properties = await this.remoteExplorerService.tunnelModel.getAttributes([{ host: tunnel.tunnelRemoteHost, port: tunnel.tunnelRemotePort }], false);
487
+ const label = properties?.get(tunnel.tunnelRemotePort)?.label;
488
+ return localize(
489
+ 8260,
490
+ "Your application{0} running on port {1} is available. ",
491
+ label ? ` (${label})` : '',
492
+ tunnel.tunnelRemotePort
493
+ );
494
+ }
495
+ linkMessage() {
496
+ return localize(8261, "[See all forwarded ports]({0})", `command:${TunnelPanel.ID}.focus`);
497
+ }
498
+ async showNotification(tunnel) {
499
+ if (!(await this.hostService.hadLastFocus())) {
500
+ return;
501
+ }
502
+ this.lastNotification?.close();
503
+ let message = await this.basicMessage(tunnel);
504
+ const choices = [this.openBrowserChoice(tunnel)];
505
+ if (!isWeb || openPreviewEnabledContext.getValue(this.contextKeyService)) {
506
+ choices.push(this.openPreviewChoice(tunnel));
507
+ }
508
+ if ((tunnel.tunnelLocalPort !== tunnel.tunnelRemotePort) && this.tunnelService.canElevate && this.tunnelService.isPortPrivileged(tunnel.tunnelRemotePort)) {
509
+ message += ( localize(
510
+ 8262,
511
+ "You'll need to run as superuser to use port {0} locally. ",
512
+ tunnel.tunnelRemotePort
513
+ ));
514
+ choices.unshift(this.elevateChoice(tunnel));
515
+ }
516
+ if (tunnel.privacy === TunnelPrivacyId.Private && isWeb && this.tunnelService.canChangePrivacy) {
517
+ choices.push(this.makePublicChoice(tunnel));
518
+ }
519
+ message += this.linkMessage();
520
+ this.lastNotification = this.notificationService.prompt(Severity.Info, message, choices, { neverShowAgain: { id: 'remote.tunnelsView.autoForwardNeverShow', isSecondary: true } });
521
+ this.lastShownPort = tunnel.tunnelRemotePort;
522
+ this.lastNotifyTime = ( new Date());
523
+ this.lastNotification.onDidClose(() => {
524
+ this.lastNotification = undefined;
525
+ this.lastShownPort = undefined;
526
+ });
527
+ }
528
+ makePublicChoice(tunnel) {
529
+ return {
530
+ label: ( localize(8263, "Make Public")),
531
+ run: async () => {
532
+ const oldTunnelDetails = mapHasAddressLocalhostOrAllInterfaces(this.remoteExplorerService.tunnelModel.forwarded, tunnel.tunnelRemoteHost, tunnel.tunnelRemotePort);
533
+ await this.remoteExplorerService.close({ host: tunnel.tunnelRemoteHost, port: tunnel.tunnelRemotePort }, TunnelCloseReason.Other);
534
+ return this.remoteExplorerService.forward({
535
+ remote: { host: tunnel.tunnelRemoteHost, port: tunnel.tunnelRemotePort },
536
+ local: tunnel.tunnelLocalPort,
537
+ name: oldTunnelDetails?.name,
538
+ elevateIfNeeded: true,
539
+ privacy: TunnelPrivacyId.Public,
540
+ source: oldTunnelDetails?.source
541
+ });
542
+ }
543
+ };
544
+ }
545
+ openBrowserChoice(tunnel) {
546
+ const address = makeAddress(tunnel.tunnelRemoteHost, tunnel.tunnelRemotePort);
547
+ return {
548
+ label: OpenPortInBrowserAction.LABEL,
549
+ run: () => OpenPortInBrowserAction.run(this.remoteExplorerService.tunnelModel, this.openerService, address)
550
+ };
551
+ }
552
+ openPreviewChoice(tunnel) {
553
+ const address = makeAddress(tunnel.tunnelRemoteHost, tunnel.tunnelRemotePort);
554
+ return {
555
+ label: OpenPortInPreviewAction.LABEL,
556
+ run: () => OpenPortInPreviewAction.run(this.remoteExplorerService.tunnelModel, this.openerService, this.externalOpenerService, address)
557
+ };
558
+ }
559
+ elevateChoice(tunnel) {
560
+ return {
561
+ label: ( localize(8264, "Use Port {0} as Sudo...", tunnel.tunnelRemotePort)),
562
+ run: async () => {
563
+ await this.remoteExplorerService.close({ host: tunnel.tunnelRemoteHost, port: tunnel.tunnelRemotePort }, TunnelCloseReason.Other);
564
+ const newTunnel = await this.remoteExplorerService.forward({
565
+ remote: { host: tunnel.tunnelRemoteHost, port: tunnel.tunnelRemotePort },
566
+ local: tunnel.tunnelRemotePort,
567
+ elevateIfNeeded: true,
568
+ source: AutoTunnelSource
569
+ });
570
+ if (!newTunnel || (typeof newTunnel === 'string')) {
571
+ return;
572
+ }
573
+ this.lastNotification?.close();
574
+ this.lastShownPort = newTunnel.tunnelRemotePort;
575
+ this.lastNotification = this.notificationService.prompt(Severity.Info, (await this.basicMessage(newTunnel)) + this.linkMessage(), [this.openBrowserChoice(newTunnel), this.openPreviewChoice(tunnel)], { neverShowAgain: { id: 'remote.tunnelsView.autoForwardNeverShow', isSecondary: true } });
576
+ this.lastNotification.onDidClose(() => {
577
+ this.lastNotification = undefined;
578
+ this.lastShownPort = undefined;
579
+ });
580
+ }
581
+ };
582
+ }
583
+ }
584
+ class OutputAutomaticPortForwarding extends Disposable {
585
+ constructor(terminalService, notificationService, openerService, externalOpenerService, remoteExplorerService, configurationService, debugService, tunnelService, hostService, logService, contextKeyService, privilegedOnly) {
586
+ super();
587
+ this.terminalService = terminalService;
588
+ this.notificationService = notificationService;
589
+ this.openerService = openerService;
590
+ this.externalOpenerService = externalOpenerService;
591
+ this.remoteExplorerService = remoteExplorerService;
592
+ this.configurationService = configurationService;
593
+ this.debugService = debugService;
594
+ this.tunnelService = tunnelService;
595
+ this.hostService = hostService;
596
+ this.logService = logService;
597
+ this.contextKeyService = contextKeyService;
598
+ this.privilegedOnly = privilegedOnly;
599
+ this.notifier = ( new OnAutoForwardedAction(
600
+ notificationService,
601
+ remoteExplorerService,
602
+ openerService,
603
+ externalOpenerService,
604
+ tunnelService,
605
+ hostService,
606
+ logService,
607
+ contextKeyService
608
+ ));
609
+ this._register(configurationService.onDidChangeConfiguration((e) => {
610
+ if (e.affectsConfiguration(PORT_AUTO_FORWARD_SETTING)) {
611
+ this.tryStartStopUrlFinder();
612
+ }
613
+ }));
614
+ this.portsFeatures = this._register(this.remoteExplorerService.onEnabledPortsFeatures(() => {
615
+ this.tryStartStopUrlFinder();
616
+ }));
617
+ this.tryStartStopUrlFinder();
618
+ if (configurationService.getValue(PORT_AUTO_SOURCE_SETTING) === PORT_AUTO_SOURCE_SETTING_HYBRID) {
619
+ this._register(this.tunnelService.onTunnelClosed(tunnel => this.notifier.hide([tunnel.port])));
620
+ }
621
+ }
622
+ tryStartStopUrlFinder() {
623
+ if (this.configurationService.getValue(PORT_AUTO_FORWARD_SETTING)) {
624
+ this.startUrlFinder();
625
+ }
626
+ else {
627
+ this.stopUrlFinder();
628
+ }
629
+ }
630
+ startUrlFinder() {
631
+ if (!this.urlFinder && (this.remoteExplorerService.portsFeaturesEnabled !== PortsEnablement.AdditionalFeatures)) {
632
+ return;
633
+ }
634
+ this.portsFeatures?.dispose();
635
+ this.urlFinder = this._register(( new UrlFinder(this.terminalService, this.debugService)));
636
+ this._register(this.urlFinder.onDidMatchLocalUrl(async (localUrl) => {
637
+ if (mapHasAddressLocalhostOrAllInterfaces(this.remoteExplorerService.tunnelModel.detected, localUrl.host, localUrl.port)) {
638
+ return;
639
+ }
640
+ const attributes = (await this.remoteExplorerService.tunnelModel.getAttributes([localUrl]))?.get(localUrl.port);
641
+ if (attributes?.onAutoForward === OnPortForward.Ignore) {
642
+ return;
643
+ }
644
+ if (this.privilegedOnly() && !this.tunnelService.isPortPrivileged(localUrl.port)) {
645
+ return;
646
+ }
647
+ const forwarded = await this.remoteExplorerService.forward({ remote: localUrl, source: AutoTunnelSource }, attributes ?? null);
648
+ if (forwarded && (typeof forwarded !== 'string')) {
649
+ this.notifier.doAction([forwarded]);
650
+ }
651
+ }));
652
+ }
653
+ stopUrlFinder() {
654
+ if (this.urlFinder) {
655
+ this.urlFinder.dispose();
656
+ this.urlFinder = undefined;
657
+ }
658
+ }
659
+ }
660
+ class ProcAutomaticPortForwarding extends Disposable {
661
+ constructor(unforwardOnly, alreadyAutoForwarded, needsInitialCandidates, configurationService, remoteExplorerService, notificationService, openerService, externalOpenerService, tunnelService, hostService, logService, contextKeyService) {
662
+ super();
663
+ this.unforwardOnly = unforwardOnly;
664
+ this.alreadyAutoForwarded = alreadyAutoForwarded;
665
+ this.needsInitialCandidates = needsInitialCandidates;
666
+ this.configurationService = configurationService;
667
+ this.remoteExplorerService = remoteExplorerService;
668
+ this.notificationService = notificationService;
669
+ this.openerService = openerService;
670
+ this.externalOpenerService = externalOpenerService;
671
+ this.tunnelService = tunnelService;
672
+ this.hostService = hostService;
673
+ this.logService = logService;
674
+ this.contextKeyService = contextKeyService;
675
+ this.autoForwarded = ( new Set());
676
+ this.notifiedOnly = ( new Set());
677
+ this.initialCandidates = ( new Set());
678
+ this.notifier = ( new OnAutoForwardedAction(
679
+ notificationService,
680
+ remoteExplorerService,
681
+ openerService,
682
+ externalOpenerService,
683
+ tunnelService,
684
+ hostService,
685
+ logService,
686
+ contextKeyService
687
+ ));
688
+ alreadyAutoForwarded?.forEach(port => this.autoForwarded.add(port));
689
+ this.initialize();
690
+ }
691
+ get forwarded() {
692
+ return this.autoForwarded;
693
+ }
694
+ async initialize() {
695
+ if (!this.remoteExplorerService.tunnelModel.environmentTunnelsSet) {
696
+ await ( new Promise(
697
+ resolve => this.remoteExplorerService.tunnelModel.onEnvironmentTunnelsSet(() => resolve())
698
+ ));
699
+ }
700
+ this._register(this.configurationService.onDidChangeConfiguration(async (e) => {
701
+ if (e.affectsConfiguration(PORT_AUTO_FORWARD_SETTING)) {
702
+ await this.startStopCandidateListener();
703
+ }
704
+ }));
705
+ this.portsFeatures = this._register(this.remoteExplorerService.onEnabledPortsFeatures(async () => {
706
+ await this.startStopCandidateListener();
707
+ }));
708
+ this.startStopCandidateListener();
709
+ }
710
+ async startStopCandidateListener() {
711
+ if (this.configurationService.getValue(PORT_AUTO_FORWARD_SETTING)) {
712
+ await this.startCandidateListener();
713
+ }
714
+ else {
715
+ this.stopCandidateListener();
716
+ }
717
+ }
718
+ stopCandidateListener() {
719
+ if (this.candidateListener) {
720
+ this.candidateListener.dispose();
721
+ this.candidateListener = undefined;
722
+ }
723
+ }
724
+ async startCandidateListener() {
725
+ if (this.candidateListener || (this.remoteExplorerService.portsFeaturesEnabled !== PortsEnablement.AdditionalFeatures)) {
726
+ return;
727
+ }
728
+ this.portsFeatures?.dispose();
729
+ await this.setInitialCandidates();
730
+ if (this.configurationService.getValue(PORT_AUTO_FORWARD_SETTING)) {
731
+ this.candidateListener = this._register(this.remoteExplorerService.tunnelModel.onCandidatesChanged(this.handleCandidateUpdate, this));
732
+ }
733
+ }
734
+ async setInitialCandidates() {
735
+ if (!this.needsInitialCandidates) {
736
+ this.logService.debug(`ForwardedPorts: (ProcForwarding) Not setting initial candidates`);
737
+ return;
738
+ }
739
+ let startingCandidates = this.remoteExplorerService.tunnelModel.candidatesOrUndefined;
740
+ if (!startingCandidates) {
741
+ await ( new Promise(
742
+ resolve => this.remoteExplorerService.tunnelModel.onCandidatesChanged(() => resolve())
743
+ ));
744
+ startingCandidates = this.remoteExplorerService.tunnelModel.candidates;
745
+ }
746
+ for (const value of startingCandidates) {
747
+ this.initialCandidates.add(makeAddress(value.host, value.port));
748
+ }
749
+ this.logService.debug(`ForwardedPorts: (ProcForwarding) Initial candidates set to ${( startingCandidates.map(candidate => candidate.port)).join(', ')}`);
750
+ }
751
+ async forwardCandidates() {
752
+ let attributes;
753
+ const allTunnels = [];
754
+ this.logService.trace(`ForwardedPorts: (ProcForwarding) Attempting to forward ${this.remoteExplorerService.tunnelModel.candidates.length} candidates`);
755
+ for (const value of this.remoteExplorerService.tunnelModel.candidates) {
756
+ if (!value.detail) {
757
+ this.logService.trace(`ForwardedPorts: (ProcForwarding) Port ${value.port} missing detail`);
758
+ continue;
759
+ }
760
+ if (!attributes) {
761
+ attributes = await this.remoteExplorerService.tunnelModel.getAttributes(this.remoteExplorerService.tunnelModel.candidates);
762
+ }
763
+ const portAttributes = attributes?.get(value.port);
764
+ const address = makeAddress(value.host, value.port);
765
+ if (( this.initialCandidates.has(address)) && (portAttributes?.onAutoForward === undefined)) {
766
+ continue;
767
+ }
768
+ if (( this.notifiedOnly.has(address)) || ( this.autoForwarded.has(address))) {
769
+ continue;
770
+ }
771
+ const alreadyForwarded = mapHasAddressLocalhostOrAllInterfaces(this.remoteExplorerService.tunnelModel.forwarded, value.host, value.port);
772
+ if (mapHasAddressLocalhostOrAllInterfaces(this.remoteExplorerService.tunnelModel.detected, value.host, value.port)) {
773
+ continue;
774
+ }
775
+ if (portAttributes?.onAutoForward === OnPortForward.Ignore) {
776
+ this.logService.trace(`ForwardedPorts: (ProcForwarding) Port ${value.port} is ignored`);
777
+ continue;
778
+ }
779
+ const forwarded = await this.remoteExplorerService.forward({ remote: value, source: AutoTunnelSource }, portAttributes ?? null);
780
+ if (!alreadyForwarded && forwarded) {
781
+ this.logService.trace(`ForwardedPorts: (ProcForwarding) Port ${value.port} has been forwarded`);
782
+ this.autoForwarded.add(address);
783
+ }
784
+ else if (forwarded) {
785
+ this.logService.trace(`ForwardedPorts: (ProcForwarding) Port ${value.port} has been notified`);
786
+ this.notifiedOnly.add(address);
787
+ }
788
+ if (forwarded && (typeof forwarded !== 'string')) {
789
+ allTunnels.push(forwarded);
790
+ }
791
+ }
792
+ this.logService.trace(`ForwardedPorts: (ProcForwarding) Forwarded ${allTunnels.length} candidates`);
793
+ if (allTunnels.length === 0) {
794
+ return undefined;
795
+ }
796
+ return allTunnels;
797
+ }
798
+ async handleCandidateUpdate(removed) {
799
+ const removedPorts = [];
800
+ let autoForwarded;
801
+ if (this.unforwardOnly) {
802
+ autoForwarded = ( new Map());
803
+ for (const entry of this.remoteExplorerService.tunnelModel.forwarded.entries()) {
804
+ if (entry[1].source.source === TunnelSource.Auto) {
805
+ autoForwarded.set(entry[0], entry[1]);
806
+ }
807
+ }
808
+ }
809
+ else {
810
+ autoForwarded = ( new Map(this.autoForwarded.entries()));
811
+ }
812
+ for (const removedPort of removed) {
813
+ const key = removedPort[0];
814
+ let value = removedPort[1];
815
+ const forwardedValue = mapHasAddressLocalhostOrAllInterfaces(autoForwarded, value.host, value.port);
816
+ if (forwardedValue) {
817
+ if (typeof forwardedValue === 'string') {
818
+ this.autoForwarded.delete(key);
819
+ }
820
+ else {
821
+ value = { host: forwardedValue.remoteHost, port: forwardedValue.remotePort };
822
+ }
823
+ await this.remoteExplorerService.close(value, TunnelCloseReason.AutoForwardEnd);
824
+ removedPorts.push(value.port);
825
+ }
826
+ else if (( this.notifiedOnly.has(key))) {
827
+ this.notifiedOnly.delete(key);
828
+ removedPorts.push(value.port);
829
+ }
830
+ else if (( this.initialCandidates.has(key))) {
831
+ this.initialCandidates.delete(key);
832
+ }
833
+ }
834
+ if (this.unforwardOnly) {
835
+ return;
836
+ }
837
+ if (removedPorts.length > 0) {
838
+ await this.notifier.hide(removedPorts);
839
+ }
840
+ const tunnels = await this.forwardCandidates();
841
+ if (tunnels) {
842
+ await this.notifier.doAction(tunnels);
843
+ }
844
+ }
845
+ }
846
+
847
+ export { AutomaticPortForwarding, ForwardedPortsView, PortRestore, VIEWLET_ID };