Skip to content

Commit 8292829

Browse files
committed
Explorations
1 parent 1876bd1 commit 8292829

5 files changed

Lines changed: 225 additions & 84 deletions

File tree

src/vs/code/electron-main/app.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ import { LogLevelSetterChannel } from 'vs/platform/log/node/logIpc';
5656
import * as errors from 'vs/base/common/errors';
5757
import { ElectronURLListener } from 'vs/platform/url/electron-main/electronUrlListener';
5858
import { serve as serveDriver } from 'vs/platform/driver/electron-main/driver';
59-
import { connectRemoteAgentManagement, ManagementPersistentConnection, IConnectionOptions } from 'vs/platform/remote/node/remoteAgentConnection';
59+
import { connectRemoteAgentManagement, ManagementPersistentConnection, IConnectionOptions } from 'vs/platform/remote/common/remoteAgentConnection';
6060
import { IMenubarService } from 'vs/platform/menubar/common/menubar';
6161
import { MenubarService } from 'vs/platform/menubar/electron-main/menubarService';
6262
import { MenubarChannel } from 'vs/platform/menubar/node/menubarIpc';
@@ -80,6 +80,7 @@ import { HistoryMainService } from 'vs/platform/history/electron-main/historyMai
8080
import { URLService } from 'vs/platform/url/common/urlService';
8181
import { WorkspacesMainService } from 'vs/platform/workspaces/electron-main/workspacesMainService';
8282
import { RemoteAgentConnectionContext } from 'vs/platform/remote/common/remoteAgentEnvironment';
83+
import { nodeWebSocketFactory } from 'vs/platform/remote/node/nodeWebSocketFactory';
8384

8485
export class CodeApplication extends Disposable {
8586

@@ -687,6 +688,7 @@ export class CodeApplication extends Disposable {
687688
const options: IConnectionOptions = {
688689
isBuilt: isBuilt,
689690
commit: product.commit,
691+
webSocketFactory: nodeWebSocketFactory,
690692
addressProvider: {
691693
getAddress: () => {
692694
return Promise.resolve({ host, port });
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { Client, PersistentProtocol, ISocket } from 'vs/base/parts/ipc/common/ipc.net';
7+
import { generateUuid } from 'vs/base/common/uuid';
8+
import { RemoteAgentConnectionContext } from 'vs/platform/remote/common/remoteAgentEnvironment';
9+
import { Disposable } from 'vs/base/common/lifecycle';
10+
11+
export const enum ConnectionType {
12+
Management = 1,
13+
ExtensionHost = 2,
14+
Tunnel = 3,
15+
}
16+
17+
interface ISimpleConnectionOptions {
18+
isBuilt: boolean;
19+
commit: string | undefined;
20+
host: string;
21+
port: number;
22+
reconnectionToken: string;
23+
reconnectionProtocol: PersistentProtocol | null;
24+
webSocketFactory: IWebSocketFactory;
25+
}
26+
27+
export interface IConnectCallback {
28+
(err: any | undefined, socket: ISocket | undefined): void;
29+
}
30+
31+
export interface IWebSocketFactory {
32+
connect(host: string, port: number, query: string, callback: IConnectCallback): void;
33+
}
34+
35+
async function connectToRemoteExtensionHostAgent(options: ISimpleConnectionOptions, connectionType: ConnectionType, args: any | undefined): Promise<PersistentProtocol> {
36+
throw new Error(`Not implemented`);
37+
}
38+
39+
interface IManagementConnectionResult {
40+
protocol: PersistentProtocol;
41+
}
42+
43+
async function doConnectRemoteAgentManagement(options: ISimpleConnectionOptions): Promise<IManagementConnectionResult> {
44+
const protocol = await connectToRemoteExtensionHostAgent(options, ConnectionType.Management, undefined);
45+
return new Promise<IManagementConnectionResult>((c, e) => {
46+
const registration = protocol.onControlMessage(raw => {
47+
registration.dispose();
48+
const msg = JSON.parse(raw.toString());
49+
const error = getErrorFromMessage(msg);
50+
if (error) {
51+
return e(error);
52+
}
53+
if (options.reconnectionProtocol) {
54+
options.reconnectionProtocol.endAcceptReconnection();
55+
}
56+
c({ protocol });
57+
});
58+
});
59+
}
60+
61+
export interface IRemoteExtensionHostStartParams {
62+
language: string;
63+
debugId?: string;
64+
break?: boolean;
65+
port?: number | null;
66+
updatePort?: boolean;
67+
}
68+
69+
interface IExtensionHostConnectionResult {
70+
protocol: PersistentProtocol;
71+
debugPort?: number;
72+
}
73+
74+
async function doConnectRemoteAgentExtensionHost(options: ISimpleConnectionOptions, startArguments: IRemoteExtensionHostStartParams): Promise<IExtensionHostConnectionResult> {
75+
const protocol = await connectToRemoteExtensionHostAgent(options, ConnectionType.ExtensionHost, startArguments);
76+
return new Promise<IExtensionHostConnectionResult>((c, e) => {
77+
const registration = protocol.onControlMessage(raw => {
78+
registration.dispose();
79+
const msg = JSON.parse(raw.toString());
80+
const error = getErrorFromMessage(msg);
81+
if (error) {
82+
return e(error);
83+
}
84+
const debugPort = msg && msg.debugPort;
85+
if (options.reconnectionProtocol) {
86+
options.reconnectionProtocol.endAcceptReconnection();
87+
}
88+
c({ protocol, debugPort });
89+
});
90+
});
91+
}
92+
93+
export interface ITunnelConnectionStartParams {
94+
port: number;
95+
}
96+
97+
async function doConnectRemoteAgentTunnel(options: ISimpleConnectionOptions, startParams: ITunnelConnectionStartParams): Promise<PersistentProtocol> {
98+
const protocol = await connectToRemoteExtensionHostAgent(options, ConnectionType.Tunnel, startParams);
99+
return protocol;
100+
}
101+
102+
export interface IConnectionOptions {
103+
isBuilt: boolean;
104+
commit: string | undefined;
105+
webSocketFactory: IWebSocketFactory;
106+
addressProvider: IAddressProvider;
107+
}
108+
109+
async function resolveConnectionOptions(options: IConnectionOptions, reconnectionToken: string, reconnectionProtocol: PersistentProtocol | null): Promise<ISimpleConnectionOptions> {
110+
const { host, port } = await options.addressProvider.getAddress();
111+
return {
112+
isBuilt: options.isBuilt,
113+
commit: options.commit,
114+
host: host,
115+
port: port,
116+
reconnectionToken: reconnectionToken,
117+
reconnectionProtocol: reconnectionProtocol,
118+
webSocketFactory: options.webSocketFactory,
119+
};
120+
}
121+
122+
export interface IAddress {
123+
host: string;
124+
port: number;
125+
}
126+
127+
export interface IAddressProvider {
128+
getAddress(): Promise<IAddress>;
129+
}
130+
131+
export async function connectRemoteAgentManagement(options: IConnectionOptions, remoteAuthority: string, clientId: string): Promise<ManagementPersistentConnection> {
132+
const reconnectionToken = generateUuid();
133+
const simpleOptions = await resolveConnectionOptions(options, reconnectionToken, null);
134+
const { protocol } = await doConnectRemoteAgentManagement(simpleOptions);
135+
return new ManagementPersistentConnection(options, remoteAuthority, clientId, reconnectionToken, protocol);
136+
}
137+
138+
export async function connectRemoteAgentExtensionHost(options: IConnectionOptions, startArguments: IRemoteExtensionHostStartParams): Promise<ExtensionHostPersistentConnection> {
139+
const reconnectionToken = generateUuid();
140+
const simpleOptions = await resolveConnectionOptions(options, reconnectionToken, null);
141+
const { protocol, debugPort } = await doConnectRemoteAgentExtensionHost(simpleOptions, startArguments);
142+
return new ExtensionHostPersistentConnection(options, startArguments, reconnectionToken, protocol, debugPort);
143+
}
144+
145+
export async function connectRemoteAgentTunnel(options: IConnectionOptions, tunnelRemotePort: number): Promise<PersistentProtocol> {
146+
const simpleOptions = await resolveConnectionOptions(options, generateUuid(), null);
147+
const protocol = await doConnectRemoteAgentTunnel(simpleOptions, { port: tunnelRemotePort });
148+
return protocol;
149+
}
150+
151+
abstract class PersistentConnection extends Disposable {
152+
153+
protected readonly _options: IConnectionOptions;
154+
public readonly reconnectionToken: string;
155+
public readonly protocol: PersistentProtocol;
156+
157+
constructor(options: IConnectionOptions, reconnectionToken: string, protocol: PersistentProtocol) {
158+
super();
159+
this._options = options;
160+
this.reconnectionToken = reconnectionToken;
161+
this.protocol = protocol;
162+
}
163+
164+
protected abstract _reconnect(options: ISimpleConnectionOptions): Promise<void>;
165+
}
166+
167+
export class ManagementPersistentConnection extends PersistentConnection {
168+
169+
public readonly client: Client<RemoteAgentConnectionContext>;
170+
171+
constructor(options: IConnectionOptions, remoteAuthority: string, clientId: string, reconnectionToken: string, protocol: PersistentProtocol) {
172+
super(options, reconnectionToken, protocol);
173+
this.client = this._register(new Client<RemoteAgentConnectionContext>(protocol, {
174+
remoteAuthority: remoteAuthority,
175+
clientId: clientId
176+
}));
177+
}
178+
179+
protected async _reconnect(options: ISimpleConnectionOptions): Promise<void> {
180+
await doConnectRemoteAgentManagement(options);
181+
}
182+
}
183+
184+
export class ExtensionHostPersistentConnection extends PersistentConnection {
185+
186+
private readonly _startArguments: IRemoteExtensionHostStartParams;
187+
public readonly debugPort: number | undefined;
188+
189+
constructor(options: IConnectionOptions, startArguments: IRemoteExtensionHostStartParams, reconnectionToken: string, protocol: PersistentProtocol, debugPort: number | undefined) {
190+
super(options, reconnectionToken, protocol);
191+
this._startArguments = startArguments;
192+
this.debugPort = debugPort;
193+
}
194+
195+
protected async _reconnect(options: ISimpleConnectionOptions): Promise<void> {
196+
await doConnectRemoteAgentExtensionHost(options, this._startArguments);
197+
}
198+
}
199+
200+
function getErrorFromMessage(msg: any): Error | null {
201+
if (msg && msg.type === 'error') {
202+
const error = new Error(`Connection error: ${msg.reason}`);
203+
(<any>error).code = 'VSCODE_CONNECTION_ERROR';
204+
return error;
205+
}
206+
return null;
207+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { IWebSocketFactory, IConnectCallback } from 'vs/platform/remote/common/remoteAgentConnection';
7+
8+
export const nodeWebSocketFactory = new class implements IWebSocketFactory {
9+
connect(host: string, port: number, query: string, callback: IConnectCallback): void {
10+
throw new Error(`Not implemented`);
11+
}
12+
};

src/vs/platform/remote/node/remoteAgentConnection.ts

Lines changed: 0 additions & 82 deletions
This file was deleted.

src/vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { Disposable } from 'vs/base/common/lifecycle';
77
import { IChannel, IServerChannel, getDelayedChannel } from 'vs/base/parts/ipc/common/ipc';
88
import { Client } from 'vs/base/parts/ipc/common/ipc.net';
99
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
10-
import { connectRemoteAgentManagement, IConnectionOptions } from 'vs/platform/remote/node/remoteAgentConnection';
10+
import { connectRemoteAgentManagement, IConnectionOptions } from 'vs/platform/remote/common/remoteAgentConnection';
1111
import { IWindowConfiguration } from 'vs/platform/windows/common/windows';
1212
import { IRemoteAgentConnection, IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
1313
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
@@ -19,6 +19,7 @@ import { RemoteExtensionEnvironmentChannelClient } from 'vs/workbench/services/r
1919
import { INotificationService } from 'vs/platform/notification/common/notification';
2020
import { localize } from 'vs/nls';
2121
import product from 'vs/platform/product/node/product';
22+
import { nodeWebSocketFactory } from 'vs/platform/remote/node/nodeWebSocketFactory';
2223

2324
export class RemoteAgentService extends Disposable implements IRemoteAgentService {
2425

@@ -90,6 +91,7 @@ class RemoteAgentConnection extends Disposable implements IRemoteAgentConnection
9091
const options: IConnectionOptions = {
9192
isBuilt: this._environmentService.isBuilt,
9293
commit: product.commit,
94+
webSocketFactory: nodeWebSocketFactory,
9395
addressProvider: {
9496
getAddress: async () => {
9597
const { host, port } = await this._remoteAuthorityResolverService.resolveAuthority(this.remoteAuthority);

0 commit comments

Comments
 (0)