@@ -3,30 +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' ;
76import { INativeEnvironmentService } from 'vs/platform/environment/common/environment' ;
7+ import { IRemoteExtensionHostStartParams } from 'vs/platform/remote/common/remoteAgentConnection' ;
88import { getNlsConfiguration } from 'vs/server/node/nls' ;
99import { Protocol } from 'vs/server/node/protocol' ;
1010import { IExtHostReadyMessage } from 'vs/workbench/services/extensions/common/extensionHostProtocol' ;
1111
1212export abstract class Connection {
1313 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+ */
1418 public readonly onClose = this . _onClose . event ;
1519 private disposed = false ;
1620 private _offline : number | undefined ;
1721
18- 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+ }
1936
2037 public get offline ( ) : number | undefined {
2138 return this . _offline ;
2239 }
2340
24- public reconnect ( socket : ISocket , buffer : VSBuffer ) : void {
41+ public reconnect ( protocol : Protocol ) : void {
42+ this . logger . debug ( 'Reconnecting...' ) ;
2543 this . _offline = undefined ;
26- this . doReconnect ( socket , buffer ) ;
44+ this . doReconnect ( protocol ) ;
2745 }
2846
29- public dispose ( ) : void {
47+ public dispose ( reason ?: string ) : void {
48+ this . logger . debug ( 'Disposing...' , field ( 'reason' , reason ) ) ;
3049 if ( ! this . disposed ) {
3150 this . disposed = true ;
3251 this . doDispose ( ) ;
@@ -35,6 +54,7 @@ export abstract class Connection {
3554 }
3655
3756 protected setOffline ( ) : void {
57+ this . logger . debug ( 'Disconnected' ) ;
3858 if ( ! this . _offline ) {
3959 this . _offline = Date . now ( ) ;
4060 }
@@ -43,27 +63,34 @@ export abstract class Connection {
4363 /**
4464 * Set up the connection on a new socket.
4565 */
46- protected abstract doReconnect ( socket : ISocket , buffer : VSBuffer ) : void ;
66+ protected abstract doReconnect ( protcol : Protocol ) : void ;
67+
68+ /**
69+ * Dispose/destroy everything permanently.
70+ */
4771 protected abstract doDispose ( ) : void ;
4872}
4973
5074/**
5175 * Used for all the IPC channels.
5276 */
5377export class ManagementConnection extends Connection {
54- public constructor ( protected protocol : Protocol , token : string ) {
55- super ( protocol , token ) ;
78+ public constructor ( protocol : Protocol ) {
79+ super ( protocol , 'management' ) ;
5680 protocol . onDidDispose ( ( ) => this . dispose ( ) ) ; // Explicit close.
5781 protocol . onSocketClose ( ( ) => this . setOffline ( ) ) ; // Might reconnect.
82+ protocol . sendMessage ( { type : 'ok' } ) ;
5883 }
5984
6085 protected doDispose ( ) : void {
6186 this . protocol . destroy ( ) ;
6287 }
6388
64- protected doReconnect ( socket : ISocket , buffer : VSBuffer ) : void {
65- this . protocol . beginAcceptReconnection ( socket , buffer ) ;
89+ protected doReconnect ( protocol : Protocol ) : void {
90+ protocol . sendMessage ( { type : 'ok' } ) ;
91+ this . protocol . beginAcceptReconnection ( protocol . getSocket ( ) , protocol . readEntireBuffer ( ) ) ;
6692 this . protocol . endAcceptReconnection ( ) ;
93+ protocol . dispose ( ) ;
6794 }
6895}
6996
@@ -82,17 +109,21 @@ type ExtHostMessage = DisconnectedMessage | ConsoleMessage | IExtHostReadyMessag
82109
83110export class ExtensionHostConnection extends Connection {
84111 private process ?: cp . ChildProcess ;
85- private readonly logger : Logger ;
86112
87113 public constructor (
88- locale : string , protocol : Protocol , buffer : VSBuffer , token : string ,
114+ protocol : Protocol ,
115+ private readonly params : IRemoteExtensionHostStartParams ,
89116 private readonly environment : INativeEnvironmentService ,
90117 ) {
91- super ( protocol , token ) ;
92- this . logger = logger . named ( 'exthost' , field ( 'token' , token ) ) ;
93- this . protocol . dispose ( ) ;
94- this . spawn ( locale , buffer ) . then ( ( p ) => this . process = p ) ;
95- 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 ) ;
96127 }
97128
98129 protected doDispose ( ) : void {
@@ -102,34 +133,38 @@ export class ExtensionHostConnection extends Connection {
102133 }
103134 }
104135
105- protected doReconnect ( socket : ISocket , buffer : VSBuffer ) : void {
106- this . protocol . setSocket ( socket ) ;
107- this . protocol . dispose ( ) ;
108- 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 ) ;
109145 }
110146
111- private sendInitMessage ( buffer : VSBuffer ) : void {
147+ private sendInitMessage ( buffer : VSBuffer , inflateBytes : Uint8Array | undefined ) : void {
112148 if ( ! this . process ) {
113- throw new Error ( " Tried to initialize VS Code before spawning" ) ;
149+ throw new Error ( ' Tried to initialize VS Code before spawning' ) ;
114150 }
115151
116- this . protocol . getUnderlyingSocket ( ) . pause ( ) ;
117-
118152 this . logger . debug ( 'Sending socket' ) ;
119153
154+ // TODO: Do something with the debug port.
120155 this . process . send ( {
121156 type : 'VSCODE_EXTHOST_IPC_SOCKET' ,
122157 initialDataChunk : Buffer . from ( buffer . buffer ) . toString ( 'base64' ) ,
123158 skipWebSocketFrames : this . protocol . options . skipWebSocketFrames ,
124159 permessageDeflate : this . protocol . options . permessageDeflate ,
125- inflateBytes : this . protocol . inflateBytes ,
160+ inflateBytes : inflateBytes ? Buffer . from ( inflateBytes ) . toString ( 'base64' ) : undefined ,
126161 } , this . protocol . getUnderlyingSocket ( ) ) ;
127162 }
128163
129- private async spawn ( locale : string , buffer : VSBuffer ) : Promise < cp . ChildProcess > {
130- this . logger . trace ( 'Getting NLS configuration...' ) ;
131- const config = await getNlsConfiguration ( locale , this . environment . userDataPath ) ;
132- 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...' ) ;
133168 const proc = cp . fork (
134169 FileAccess . asFileUri ( 'bootstrap-fork' , require ) . fsPath ,
135170 // While not technically necessary, makes it easier to tell which process
@@ -158,7 +193,7 @@ export class ExtensionHostConnection extends Connection {
158193 this . dispose ( ) ;
159194 } ) ;
160195 proc . on ( 'exit' , ( code ) => {
161- this . logger . trace ( 'Exited' , field ( 'code' , code ) ) ;
196+ this . logger . debug ( 'Exited' , field ( 'code' , code ) ) ;
162197 this . dispose ( ) ;
163198 } ) ;
164199 if ( proc . stdout && proc . stderr ) {
@@ -177,20 +212,20 @@ export class ExtensionHostConnection extends Connection {
177212 }
178213 break ;
179214 case 'VSCODE_EXTHOST_DISCONNECTED' :
180- this . logger . trace ( 'Going offline ') ;
215+ this . logger . debug ( 'Got disconnected message ') ;
181216 this . setOffline ( ) ;
182217 break ;
183218 case 'VSCODE_EXTHOST_IPC_READY' :
184- this . logger . trace ( 'Got ready message ') ;
185- this . sendInitMessage ( buffer ) ;
219+ this . logger . debug ( 'Handshake completed ') ;
220+ this . sendInitMessage ( buffer , inflateBytes ) ;
186221 break ;
187222 default :
188223 this . logger . error ( 'Unexpected message' , field ( 'event' , event ) ) ;
189224 break ;
190225 }
191226 } ) ;
192227
193- this . logger . trace ( 'Waiting for handshake...' ) ;
228+ this . logger . debug ( 'Waiting for handshake...' ) ;
194229 return proc ;
195230 }
196231}
0 commit comments