@@ -54,30 +54,24 @@ export class HttpError extends Error {
5454 }
5555}
5656
57- export class Server {
58- // Used to notify the IPC server that there is a new client.
59- public readonly _onDidClientConnect = new Emitter < ClientConnectionEvent > ( ) ;
60- public readonly onDidClientConnect = this . _onDidClientConnect . event ;
61-
62- private readonly rootPath = path . resolve ( __dirname , "../../.." ) ;
63-
64- // This is separate instead of just extending this class since we can't
65- // use properties in the super call. This manages channels.
66- private readonly ipc = new IPCServer ( this . onDidClientConnect ) ;
67-
68- // The web server.
69- private readonly server : http . Server ;
70-
71- private readonly environmentService : EnvironmentService ;
72- private readonly logService : ILogService ;
73-
74- // Persistent connections. These can reconnect within a timeout.
75- private readonly connections = new Map < ConnectionType , Map < string , Connection > > ( ) ;
57+ export abstract class Server {
58+ // The underlying web server.
59+ protected readonly server : http . Server ;
7660
7761 public constructor ( ) {
7862 this . server = http . createServer ( async ( request , response ) : Promise < void > => {
7963 try {
80- const [ content , headers ] = await this . handleRequest ( request ) ;
64+ if ( request . method !== "GET" ) {
65+ throw new HttpError (
66+ `Unsupported method ${ request . method } ` ,
67+ HttpCode . BadRequest ,
68+ ) ;
69+ }
70+
71+ const parsedUrl = url . parse ( request . url || "" , true ) ;
72+ const requestPath = parsedUrl . pathname || "/" ;
73+
74+ const [ content , headers ] = await this . handleRequest ( request , parsedUrl , requestPath ) ;
8175 response . writeHead ( HttpCode . Ok , {
8276 "Cache-Control" : "max-age=86400" ,
8377 // TODO: ETag?
@@ -89,6 +83,48 @@ export class Server {
8983 response . end ( error . message ) ;
9084 }
9185 } ) ;
86+ }
87+
88+ protected abstract handleRequest (
89+ request : http . IncomingMessage ,
90+ parsedUrl : url . UrlWithParsedQuery ,
91+ requestPath : string ,
92+ ) : Promise < [ string | Buffer , http . OutgoingHttpHeaders ] > ;
93+
94+ public listen ( port : number ) : Promise < void > {
95+ return new Promise ( ( resolve , reject ) => {
96+ this . server . on ( "error" , reject ) ;
97+ this . server . listen ( port , resolve ) ;
98+ } ) ;
99+ }
100+
101+ public get address ( ) : string {
102+ const address = this . server . address ( ) ;
103+ const endpoint = typeof address !== "string"
104+ ? ( ( address . address === "::" ? "localhost" : address . address ) + ":" + address . port )
105+ : address ;
106+ return `http://${ endpoint } ` ;
107+ }
108+ }
109+
110+ export class MainServer extends Server {
111+ // Used to notify the IPC server that there is a new client.
112+ public readonly _onDidClientConnect = new Emitter < ClientConnectionEvent > ( ) ;
113+ public readonly onDidClientConnect = this . _onDidClientConnect . event ;
114+
115+ private readonly rootPath = path . resolve ( __dirname , "../../.." ) ;
116+
117+ // This is separate instead of just extending this class since we can't
118+ // use properties in the super call. This manages channels.
119+ private readonly ipc = new IPCServer ( this . onDidClientConnect ) ;
120+
121+ // Persistent connections. These can reconnect within a timeout.
122+ private readonly connections = new Map < ConnectionType , Map < string , Connection > > ( ) ;
123+
124+ private readonly services = new ServiceCollection ( ) ;
125+
126+ public constructor ( private readonly webviewServer : WebviewServer ) {
127+ super ( ) ;
92128
93129 this . server . on ( "upgrade" , async ( request , socket ) => {
94130 const protocol = this . createProtocol ( request , socket ) ;
@@ -98,56 +134,44 @@ export class Server {
98134 protocol . dispose ( error ) ;
99135 }
100136 } ) ;
137+ }
101138
102- this . server . on ( "error" , ( error ) => {
103- console . error ( error ) ;
104- process . exit ( 1 ) ;
105- } ) ;
139+ public async listen ( port : number ) : Promise < void > {
140+ const args = validatePaths ( parseMainProcessArgv ( process . argv ) ) ;
106141
107- let args : ParsedArgs ;
108- try {
109- args = parseMainProcessArgv ( process . argv ) ;
110- args = validatePaths ( args ) ;
111- } catch ( error ) {
112- console . error ( error . message ) ;
113- return process . exit ( 1 ) ;
114- }
115-
116- const services = new ServiceCollection ( ) ;
117- this . environmentService = new EnvironmentService ( args , process . execPath ) ;
118- services . set ( IEnvironmentService , this . environmentService ) ;
142+ const environmentService = new EnvironmentService ( args , process . execPath ) ;
143+ this . services . set ( IEnvironmentService , environmentService ) ;
119144
120- this . logService = new SpdLogService (
145+ const logService = new SpdLogService (
121146 RemoteExtensionLogFileName ,
122- this . environmentService . logsPath ,
123- getLogLevel ( this . environmentService ) ,
147+ environmentService . logsPath ,
148+ getLogLevel ( environmentService ) ,
124149 ) ;
125- this . ipc . registerChannel ( "loglevel" , new LogLevelSetterChannel ( this . logService ) ) ;
150+ this . services . set ( ILogService , logService ) ;
126151
127- const instantiationService = new InstantiationService ( services ) ;
152+ this . ipc . registerChannel ( "loglevel" , new LogLevelSetterChannel ( logService ) ) ;
153+
154+ const instantiationService = new InstantiationService ( this . services ) ;
128155 instantiationService . invokeFunction ( ( ) => {
129156 instantiationService . createInstance ( LogsDataCleaner ) ;
130157 this . ipc . registerChannel (
131158 REMOTE_FILE_SYSTEM_CHANNEL_NAME ,
132- new FileProviderChannel ( this . logService ) ,
159+ new FileProviderChannel ( logService ) ,
133160 ) ;
134161 this . ipc . registerChannel (
135162 "remoteextensionsenvironment" ,
136- new ExtensionEnvironmentChannel ( this . environmentService , this . logService ) ,
163+ new ExtensionEnvironmentChannel ( environmentService , logService ) ,
137164 ) ;
138165 } ) ;
139- }
140166
141- private async handleRequest ( request : http . IncomingMessage ) : Promise < [ string | Buffer , http . OutgoingHttpHeaders ] > {
142- if ( request . method !== "GET" ) {
143- throw new HttpError (
144- `Unsupported method ${ request . method } ` ,
145- HttpCode . BadRequest ,
146- ) ;
147- }
167+ await super . listen ( port ) ;
168+ }
148169
149- const parsedUrl = url . parse ( request . url || "" , true ) ;
150- const requestPath = parsedUrl . pathname || "/" ;
170+ protected async handleRequest (
171+ request : http . IncomingMessage ,
172+ parsedUrl : url . UrlWithParsedQuery ,
173+ requestPath : string ,
174+ ) : Promise < [ string | Buffer , http . OutgoingHttpHeaders ] > {
151175 if ( requestPath === "/" ) {
152176 const htmlPath = path . join (
153177 this . rootPath ,
@@ -159,21 +183,29 @@ export class Server {
159183 const remoteAuthority = request . headers . host as string ;
160184 const transformer = getUriTransformer ( remoteAuthority ) ;
161185
162- const webviewEndpoint = "" ;
186+ const webviewEndpoint = this . webviewServer . address ;
163187
164188 const cwd = process . env . VSCODE_CWD || process . cwd ( ) ;
165189 const workspacePath = parsedUrl . query . workspace as string | undefined ;
166190 const folderPath = ! workspacePath ? parsedUrl . query . folder as string | undefined || cwd : undefined ;
167191
168192 const options : Options = {
169193 WORKBENCH_WEB_CONGIGURATION : {
170- workspaceUri : workspacePath ? transformer . transformOutgoing ( URI . file ( sanitizeFilePath ( workspacePath , cwd ) ) ) : undefined ,
171- folderUri : folderPath ? transformer . transformOutgoing ( URI . file ( sanitizeFilePath ( folderPath , cwd ) ) ) : undefined ,
194+ workspaceUri : workspacePath
195+ ? transformer . transformOutgoing ( URI . file ( sanitizeFilePath ( workspacePath , cwd ) ) )
196+ : undefined ,
197+ folderUri : folderPath
198+ ? transformer . transformOutgoing ( URI . file ( sanitizeFilePath ( folderPath , cwd ) ) )
199+ : undefined ,
172200 remoteAuthority,
173201 webviewEndpoint,
174202 } ,
175- REMOTE_USER_DATA_URI : transformer . transformOutgoing ( this . environmentService . webUserDataHome ) ,
176- PRODUCT_CONFIGURATION : require . __$__nodeRequire ( path . resolve ( getPathFromAmdModule ( require , "" ) , "../product.json" ) ) ,
203+ REMOTE_USER_DATA_URI : transformer . transformOutgoing (
204+ ( this . services . get ( IEnvironmentService ) as EnvironmentService ) . webUserDataHome ,
205+ ) ,
206+ PRODUCT_CONFIGURATION : require . __$__nodeRequire (
207+ path . resolve ( getPathFromAmdModule ( require , "" ) , "../product.json" ) ,
208+ ) ,
177209 CONNECTION_AUTH_TOKEN : "" ,
178210 } ;
179211
@@ -239,17 +271,6 @@ export class Server {
239271 ) ;
240272 }
241273
242- public listen ( port : number = 8443 ) : void {
243- this . server . listen ( port , ( ) => {
244- const address = this . server . address ( ) ;
245- const location = typeof address === "string"
246- ? address
247- : `port ${ address . port } ` ;
248- console . log ( `Listening on ${ location } ` ) ;
249- console . log ( `Serving ${ this . rootPath } ` ) ;
250- } ) ;
251- }
252-
253274 private async connect ( message : ConnectionTypeRequest , protocol : Protocol ) : Promise < void > {
254275 switch ( message . desiredConnectionType ) {
255276 case ConnectionType . ExtensionHost :
@@ -290,7 +311,9 @@ export class Server {
290311 onDidClientDisconnect : connection . onClose ,
291312 } ) ;
292313 } else {
293- connection = new ExtensionHostConnection ( protocol , this . logService ) ;
314+ connection = new ExtensionHostConnection (
315+ protocol , this . services . get ( ILogService ) as ILogService ,
316+ ) ;
294317 }
295318 connections . set ( protocol . options . reconnectionToken , connection ) ;
296319 connection . onClose ( ( ) => {
@@ -309,3 +332,9 @@ export class Server {
309332 return undefined ;
310333 }
311334}
335+
336+ export class WebviewServer extends Server {
337+ protected async handleRequest ( ) : Promise < [ string | Buffer , http . OutgoingHttpHeaders ] > {
338+ throw new Error ( "not implemented" ) ;
339+ }
340+ }
0 commit comments