@@ -3,31 +3,49 @@ import * as cp from 'child_process';
33import { VSBuffer } from 'vs/base/common/buffer' ;
44import { Emitter } from 'vs/base/common/event' ;
55import { FileAccess } from 'vs/base/common/network' ;
6- import { ISocket } from 'vs/base/parts/ipc/common/ipc.net' ;
7- import { WebSocketNodeSocket } from 'vs/base/parts/ipc/node/ipc.net' ;
86import { INativeEnvironmentService } from 'vs/platform/environment/common/environment' ;
7+ import { IRemoteExtensionHostStartParams } from 'vs/platform/remote/common/remoteAgentConnection' ;
98import { getNlsConfiguration } from 'vs/server/node/nls' ;
109import { Protocol } from 'vs/server/node/protocol' ;
1110import { IExtHostReadyMessage } from 'vs/workbench/services/extensions/common/extensionHostProtocol' ;
1211
1312export abstract class Connection {
1413 private readonly _onClose = new Emitter < void > ( ) ;
14+ /**
15+ * Fire when the connection is closed (not just disconnected). This should
16+ * only happen when the connection is offline and old or has an error.
17+ */
1518 public readonly onClose = this . _onClose . event ;
1619 private disposed = false ;
1720 private _offline : number | undefined ;
1821
19- public constructor ( protected protocol : Protocol , public readonly token : string ) { }
22+ protected readonly logger : Logger ;
23+
24+ public constructor (
25+ protected readonly protocol : Protocol ,
26+ public readonly name : string ,
27+ ) {
28+ this . logger = logger . named (
29+ this . name ,
30+ field ( 'token' , this . protocol . options . reconnectionToken ) ,
31+ ) ;
32+
33+ this . logger . debug ( 'Connecting...' ) ;
34+ this . onClose ( ( ) => this . logger . debug ( 'Closed' ) ) ;
35+ }
2036
2137 public get offline ( ) : number | undefined {
2238 return this . _offline ;
2339 }
2440
25- public reconnect ( socket : ISocket , buffer : VSBuffer ) : void {
41+ public reconnect ( protocol : Protocol ) : void {
42+ this . logger . debug ( 'Reconnecting...' ) ;
2643 this . _offline = undefined ;
27- this . doReconnect ( socket , buffer ) ;
44+ this . doReconnect ( protocol ) ;
2845 }
2946
30- public dispose ( ) : void {
47+ public dispose ( reason ?: string ) : void {
48+ this . logger . debug ( 'Disposing...' , field ( 'reason' , reason ) ) ;
3149 if ( ! this . disposed ) {
3250 this . disposed = true ;
3351 this . doDispose ( ) ;
@@ -36,6 +54,7 @@ export abstract class Connection {
3654 }
3755
3856 protected setOffline ( ) : void {
57+ this . logger . debug ( 'Disconnected' ) ;
3958 if ( ! this . _offline ) {
4059 this . _offline = Date . now ( ) ;
4160 }
@@ -44,29 +63,34 @@ export abstract class Connection {
4463 /**
4564 * Set up the connection on a new socket.
4665 */
47- protected abstract doReconnect ( socket : ISocket , buffer : VSBuffer ) : void ;
66+ protected abstract doReconnect ( protcol : Protocol ) : void ;
67+
68+ /**
69+ * Dispose/destroy everything permanently.
70+ */
4871 protected abstract doDispose ( ) : void ;
4972}
5073
5174/**
5275 * Used for all the IPC channels.
5376 */
5477export class ManagementConnection extends Connection {
55- public constructor ( protected protocol : Protocol , token : string ) {
56- super ( protocol , token ) ;
78+ public constructor ( protocol : Protocol ) {
79+ super ( protocol , 'management' ) ;
5780 protocol . onDidDispose ( ( ) => this . dispose ( ) ) ; // Explicit close.
5881 protocol . onSocketClose ( ( ) => this . setOffline ( ) ) ; // Might reconnect.
82+ protocol . sendMessage ( { type : 'ok' } ) ;
5983 }
6084
6185 protected doDispose ( ) : void {
62- this . protocol . sendDisconnect ( ) ;
63- this . protocol . dispose ( ) ;
64- this . protocol . getUnderlyingSocket ( ) . destroy ( ) ;
86+ this . protocol . destroy ( ) ;
6587 }
6688
67- protected doReconnect ( socket : ISocket , buffer : VSBuffer ) : void {
68- this . protocol . beginAcceptReconnection ( socket , buffer ) ;
89+ protected doReconnect ( protocol : Protocol ) : void {
90+ protocol . sendMessage ( { type : 'ok' } ) ;
91+ this . protocol . beginAcceptReconnection ( protocol . getSocket ( ) , protocol . readEntireBuffer ( ) ) ;
6992 this . protocol . endAcceptReconnection ( ) ;
93+ protocol . dispose ( ) ;
7094 }
7195}
7296
@@ -85,55 +109,62 @@ type ExtHostMessage = DisconnectedMessage | ConsoleMessage | IExtHostReadyMessag
85109
86110export class ExtensionHostConnection extends Connection {
87111 private process ?: cp . ChildProcess ;
88- private readonly logger : Logger ;
89112
90113 public constructor (
91- locale : string , protocol : Protocol , buffer : VSBuffer , token : string ,
114+ protocol : Protocol ,
115+ private readonly params : IRemoteExtensionHostStartParams ,
92116 private readonly environment : INativeEnvironmentService ,
93117 ) {
94- super ( protocol , token ) ;
95- this . logger = logger . named ( 'exthost' , field ( 'token' , token ) ) ;
96- this . protocol . dispose ( ) ;
97- this . spawn ( locale , buffer ) . then ( ( p ) => this . process = p ) ;
98- this . protocol . getUnderlyingSocket ( ) . pause ( ) ;
118+ super ( protocol , 'exthost' ) ;
119+
120+ protocol . sendMessage ( { debugPort : this . params . port } ) ;
121+ const buffer = protocol . readEntireBuffer ( ) ;
122+ const inflateBytes = protocol . inflateBytes ;
123+ protocol . dispose ( ) ;
124+ protocol . getUnderlyingSocket ( ) . pause ( ) ;
125+
126+ this . spawn ( buffer , inflateBytes ) . then ( ( p ) => this . process = p ) ;
99127 }
100128
101129 protected doDispose ( ) : void {
130+ this . protocol . destroy ( ) ;
102131 if ( this . process ) {
103132 this . process . kill ( ) ;
104133 }
105- this . protocol . getUnderlyingSocket ( ) . destroy ( ) ;
106134 }
107135
108- protected doReconnect ( socket : ISocket , buffer : VSBuffer ) : void {
109- // This is just to set the new socket.
110- this . protocol . beginAcceptReconnection ( socket , null ) ;
111- this . protocol . dispose ( ) ;
112- this . sendInitMessage ( buffer ) ;
136+ protected doReconnect ( protocol : Protocol ) : void {
137+ protocol . sendMessage ( { debugPort : this . params . port } ) ;
138+ const buffer = protocol . readEntireBuffer ( ) ;
139+ const inflateBytes = protocol . inflateBytes ;
140+ protocol . dispose ( ) ;
141+ protocol . getUnderlyingSocket ( ) . pause ( ) ;
142+ this . protocol . setSocket ( protocol . getSocket ( ) ) ;
143+
144+ this . sendInitMessage ( buffer , inflateBytes ) ;
113145 }
114146
115- private sendInitMessage ( buffer : VSBuffer ) : void {
116- const socket = this . protocol . getUnderlyingSocket ( ) ;
117- socket . pause ( ) ;
147+ private sendInitMessage ( buffer : VSBuffer , inflateBytes : Uint8Array | undefined ) : void {
148+ if ( ! this . process ) {
149+ throw new Error ( 'Tried to initialize VS Code before spawning' ) ;
150+ }
118151
119- const wrapperSocket = this . protocol . getSocket ( ) ;
152+ this . logger . debug ( 'Sending socket' ) ;
120153
121- this . logger . trace ( 'Sending socket' ) ;
122- this . process ! . send ( { // Process must be set at this point.
154+ // TODO: Do something with the debug port.
155+ this . process . send ( {
123156 type : 'VSCODE_EXTHOST_IPC_SOCKET' ,
124157 initialDataChunk : Buffer . from ( buffer . buffer ) . toString ( 'base64' ) ,
125- skipWebSocketFrames : ! ( wrapperSocket instanceof WebSocketNodeSocket ) ,
158+ skipWebSocketFrames : this . protocol . options . skipWebSocketFrames ,
126159 permessageDeflate : this . protocol . options . permessageDeflate ,
127- inflateBytes : wrapperSocket instanceof WebSocketNodeSocket
128- ? Buffer . from ( wrapperSocket . recordedInflateBytes . buffer ) . toString ( 'base64' )
129- : undefined ,
130- } , socket ) ;
160+ inflateBytes : inflateBytes ? Buffer . from ( inflateBytes ) . toString ( 'base64' ) : undefined ,
161+ } , this . protocol . getUnderlyingSocket ( ) ) ;
131162 }
132163
133- private async spawn ( locale : string , buffer : VSBuffer ) : Promise < cp . ChildProcess > {
134- this . logger . trace ( 'Getting NLS configuration...' ) ;
135- const config = await getNlsConfiguration ( locale , this . environment . userDataPath ) ;
136- this . logger . trace ( 'Spawning extension host...' ) ;
164+ private async spawn ( buffer : VSBuffer , inflateBytes : Uint8Array | undefined ) : Promise < cp . ChildProcess > {
165+ this . logger . debug ( 'Getting NLS configuration...' ) ;
166+ const config = await getNlsConfiguration ( this . params . language , this . environment . userDataPath ) ;
167+ this . logger . debug ( 'Spawning extension host...' ) ;
137168 const proc = cp . fork (
138169 FileAccess . asFileUri ( 'bootstrap-fork' , require ) . fsPath ,
139170 // While not technically necessary, makes it easier to tell which process
@@ -162,7 +193,7 @@ export class ExtensionHostConnection extends Connection {
162193 this . dispose ( ) ;
163194 } ) ;
164195 proc . on ( 'exit' , ( code ) => {
165- this . logger . trace ( 'Exited' , field ( 'code' , code ) ) ;
196+ this . logger . debug ( 'Exited' , field ( 'code' , code ) ) ;
166197 this . dispose ( ) ;
167198 } ) ;
168199 if ( proc . stdout && proc . stderr ) {
@@ -181,20 +212,20 @@ export class ExtensionHostConnection extends Connection {
181212 }
182213 break ;
183214 case 'VSCODE_EXTHOST_DISCONNECTED' :
184- this . logger . trace ( 'Going offline ') ;
215+ this . logger . debug ( 'Got disconnected message ') ;
185216 this . setOffline ( ) ;
186217 break ;
187218 case 'VSCODE_EXTHOST_IPC_READY' :
188- this . logger . trace ( 'Got ready message ') ;
189- this . sendInitMessage ( buffer ) ;
219+ this . logger . debug ( 'Handshake completed ') ;
220+ this . sendInitMessage ( buffer , inflateBytes ) ;
190221 break ;
191222 default :
192223 this . logger . error ( 'Unexpected message' , field ( 'event' , event ) ) ;
193224 break ;
194225 }
195226 } ) ;
196227
197- this . logger . trace ( 'Waiting for handshake...' ) ;
228+ this . logger . debug ( 'Waiting for handshake...' ) ;
198229 return proc ;
199230 }
200231}
0 commit comments