2019-07-03 04:55:54 +07:00
import * as os from "os" ;
2019-07-12 05:12:52 +07:00
2019-07-03 04:55:54 +07:00
import { validatePaths } from "vs/code/node/paths" ;
import { parseMainProcessArgv } from "vs/platform/environment/node/argvHelper" ;
import { ParsedArgs } from "vs/platform/environment/common/environment" ;
2019-07-03 06:29:48 +07:00
import { buildHelpMessage , buildVersionMessage , options } from "vs/platform/environment/node/argv" ;
2019-07-03 04:55:54 +07:00
import pkg from "vs/platform/product/node/package" ;
2019-07-17 02:57:02 +07:00
import product from "vs/platform/product/node/product" ;
2019-07-12 05:12:52 +07:00
2019-07-24 03:38:00 +07:00
import { AuthType , MainServer , WebviewServer } from "vs/server/src/server" ;
2019-07-12 05:12:52 +07:00
import "vs/server/src/tar" ;
2019-07-24 03:38:00 +07:00
import { buildAllowedMessage , generateCertificate , generatePassword , open , unpackExecutables } from "vs/server/src/util" ;
2019-07-03 04:55:54 +07:00
2019-07-03 06:29:48 +07:00
interface Args extends ParsedArgs {
2019-07-24 03:38:00 +07:00
auth? : AuthType ;
2019-07-24 03:17:25 +07:00
"base-path" ? : string ;
2019-07-11 06:33:18 +07:00
cert? : string ;
"cert-key" ? : string ;
"extra-builtin-extensions-dir" ? : string ;
"extra-extensions-dir" ? : string ;
host? : string ;
open? : string ;
2019-07-03 06:29:48 +07:00
port? : string ;
2019-07-11 06:33:18 +07:00
socket? : string ;
2019-07-03 06:29:48 +07:00
"webview-port" ? : string ;
2019-07-11 06:33:18 +07:00
"webview-socket" ? : string ;
2019-07-03 06:29:48 +07:00
}
2019-07-11 06:33:18 +07:00
// The last item is _ which is like -- so our options need to come before it.
const last = options . pop ( ) ! ;
// Remove options that won't work or don't make sense.
let i = options . length ;
while ( i -- ) {
switch ( options [ i ] . id ) {
case "add" :
case "diff" :
case "file-uri" :
case "folder-uri" :
case "goto" :
case "new-window" :
case "reuse-window" :
case "wait" :
case "disable-gpu" :
// TODO: pretty sure these don't work but not 100%.
case "max-memory" :
case "prof-startup" :
case "inspect-extensions" :
case "inspect-brk-extensions" :
options . splice ( i , 1 ) ;
break ;
}
}
2019-07-24 03:17:25 +07:00
options . push ( { id : "base-path" , type : "string" , cat : "o" , description : "Base path of the URL at which code-server is hosted (used for login redirects)." } ) ;
2019-07-24 03:38:00 +07:00
options . push ( { id : "cert" , type : "string" , cat : "o" , description : "Path to certificate. If the path is omitted, both this and --cert-key will be generated." } ) ;
options . push ( { id : "cert-key" , type : "string" , cat : "o" , description : "Path to the certificate's key if one was provided." } ) ;
options . push ( { id : "extra-builtin-extensions-dir" , type : "string" , cat : "o" , description : "Path to an extra builtin extension directory." } ) ;
options . push ( { id : "extra-extensions-dir" , type : "string" , cat : "o" , description : "Path to an extra user extension directory." } ) ;
2019-07-11 06:33:18 +07:00
options . push ( { id : "host" , type : "string" , cat : "o" , description : "Host for the main and webview servers." } ) ;
2019-07-24 03:38:00 +07:00
options . push ( { id : "auth" , type : "string" , cat : "o" , description : ` The type of authentication to use. ${ buildAllowedMessage ( AuthType ) } . ` } ) ;
2019-07-11 06:33:18 +07:00
options . push ( { id : "open" , type : "boolean" , cat : "o" , description : "Open in the browser on startup." } ) ;
2019-07-03 06:29:48 +07:00
options . push ( { id : "port" , type : "string" , cat : "o" , description : "Port for the main server." } ) ;
2019-07-11 06:33:18 +07:00
options . push ( { id : "socket" , type : "string" , cat : "o" , description : "Listen on a socket instead of host:port." } ) ;
2019-07-03 06:29:48 +07:00
options . push ( { id : "webview-port" , type : "string" , cat : "o" , description : "Port for the webview server." } ) ;
2019-07-11 06:33:18 +07:00
options . push ( { id : "webview-socket" , type : "string" , cat : "o" , description : "Listen on a socket instead of host:port." } ) ;
options . push ( last ) ;
2019-07-03 06:29:48 +07:00
2019-07-03 04:55:54 +07:00
interface IMainCli {
main : ( argv : ParsedArgs ) = > Promise < void > ;
}
const main = async ( ) : Promise < void > = > {
2019-07-03 06:29:48 +07:00
const args = validatePaths ( parseMainProcessArgv ( process . argv ) ) as Args ;
2019-07-13 04:39:38 +07:00
[ "extra-extensions-dir" , "extra-builtin-extensions-dir" ] . forEach ( ( key ) = > {
if ( typeof args [ key ] === "string" ) {
args [ key ] = [ args [ key ] ] ;
}
} ) ;
2019-07-03 04:55:54 +07:00
if ( ! product . extensionsGallery ) {
product . extensionsGallery = {
serviceUrl : process.env.SERVICE_URL || "https://v1.extapi.coder.com" ,
itemUrl : process.env.ITEM_URL || "" ,
controlUrl : "" ,
recommendationsUrl : "" ,
} ;
}
2019-07-11 06:33:18 +07:00
const version = ` ${ ( pkg as any ) . codeServerVersion || "development" } -vsc ${ pkg . version } ` ;
2019-07-03 04:55:54 +07:00
if ( args . help ) {
const executable = ` ${ product . applicationName } ${ os . platform ( ) === "win32" ? ".exe" : "" } ` ;
2019-07-20 05:43:54 +07:00
return console . log ( buildHelpMessage ( product . nameLong , executable , version , undefined , false ) ) ;
2019-07-03 04:55:54 +07:00
}
if ( args . version ) {
2019-07-11 06:33:18 +07:00
return console . log ( buildVersionMessage ( version , product . commit ) ) ;
2019-07-03 04:55:54 +07:00
}
const shouldSpawnCliProcess = ( ) : boolean = > {
return ! ! args [ "install-source" ]
|| ! ! args [ "list-extensions" ]
|| ! ! args [ "install-extension" ]
|| ! ! args [ "uninstall-extension" ]
|| ! ! args [ "locate-extension" ]
|| ! ! args [ "telemetry" ] ;
} ;
if ( shouldSpawnCliProcess ( ) ) {
const cli = await new Promise < IMainCli > ( ( c , e ) = > require ( [ "vs/code/node/cliProcessMain" ] , c , e ) ) ;
await cli . main ( args ) ;
2019-07-20 05:43:54 +07:00
return process . exit ( 0 ) ; // There is a WriteStream instance keeping it open.
2019-07-03 04:55:54 +07:00
}
2019-07-20 05:43:54 +07:00
const extra = args [ "_" ] || [ ] ;
2019-07-12 05:12:52 +07:00
const options = {
2019-07-24 03:38:00 +07:00
auth : args.auth ,
2019-07-24 03:17:25 +07:00
basePath : args [ "base-path" ] ,
2019-07-13 03:21:00 +07:00
cert : args.cert ,
certKey : args [ "cert-key" ] ,
2019-07-20 05:43:54 +07:00
folderUri : extra.length > 1 ? extra [ extra . length - 1 ] : undefined ,
host : args.host ,
2019-07-13 03:21:00 +07:00
password : process.env.PASSWORD ,
2019-07-12 05:12:52 +07:00
} ;
2019-07-24 03:38:00 +07:00
if ( options . auth && Object . keys ( AuthType ) . filter ( ( k ) = > AuthType [ k ] === options . auth ) . length === 0 ) {
throw new Error ( ` ' ${ options . auth } ' is not a valid authentication type. ` ) ;
} else if ( options . auth && ! options . password ) {
options . password = await generatePassword ( ) ;
2019-07-13 03:21:00 +07:00
}
2019-07-24 03:38:00 +07:00
if ( ! options . certKey && typeof options . certKey !== "undefined" ) {
throw new Error ( ` --cert-key cannot be blank ` ) ;
} else if ( options . certKey && ! options . cert ) {
throw new Error ( ` --cert-key was provided but --cert was not ` ) ;
} if ( ! options . cert && typeof options . cert !== "undefined" ) {
2019-07-12 05:12:52 +07:00
const { cert , certKey } = await generateCertificate ( ) ;
options . cert = cert ;
options . certKey = certKey ;
}
2019-07-20 05:43:54 +07:00
const webviewPort = args [ "webview-port" ] ;
2019-07-12 05:12:52 +07:00
const webviewServer = new WebviewServer ( {
. . . options ,
2019-07-20 05:43:54 +07:00
port : typeof webviewPort !== "undefined" && parseInt ( webviewPort , 10 ) || 8444 ,
2019-07-12 05:12:52 +07:00
socket : args [ "webview-socket" ] ,
} ) ;
const server = new MainServer ( {
. . . options ,
2019-07-20 05:43:54 +07:00
port : typeof args . port !== "undefined" && parseInt ( args . port , 10 ) || 8443 ,
2019-07-12 05:12:52 +07:00
socket : args.socket ,
} , webviewServer , args ) ;
2019-07-17 07:26:05 +07:00
const [ webviewAddress , serverAddress , /* ignore */ ] = await Promise . all ( [
2019-07-05 22:54:44 +07:00
webviewServer . listen ( ) ,
2019-07-17 07:26:05 +07:00
server . listen ( ) ,
unpackExecutables ( ) ,
2019-07-05 22:54:44 +07:00
] ) ;
2019-07-12 05:12:52 +07:00
console . log ( ` Main server listening on ${ serverAddress } ` ) ;
console . log ( ` Webview server listening on ${ webviewAddress } ` ) ;
2019-07-13 03:21:00 +07:00
2019-07-24 03:38:00 +07:00
if ( options . auth && ! process . env . PASSWORD ) {
2019-07-13 03:21:00 +07:00
console . log ( " - Password is" , options . password ) ;
console . log ( " - To use your own password, set the PASSWORD environment variable" ) ;
} else if ( options . auth ) {
console . log ( " - Using custom password for authentication" ) ;
} else {
console . log ( " - No authentication" ) ;
}
2019-07-24 03:38:00 +07:00
if ( server . protocol === "https" ) {
2019-07-13 03:21:00 +07:00
console . log (
2019-07-24 03:38:00 +07:00
args . cert
? ` - Using provided certificate ${ args [ "cert-key" ] ? " and key" : "" } for HTTPS `
: ` - Using generated certificate and key for HTTPS ` ,
2019-07-13 03:21:00 +07:00
) ;
} else {
console . log ( " - Not serving HTTPS" ) ;
}
2019-07-16 01:31:05 +07:00
2019-07-24 03:38:00 +07:00
if ( ! server . options . socket && args . open ) {
2019-07-17 07:23:58 +07:00
// The web socket doesn't seem to work if using 0.0.0.0.
2019-07-20 05:43:54 +07:00
const openAddress = ` http://localhost: ${ server . options . port } ` ;
2019-07-17 07:23:58 +07:00
await open ( openAddress ) . catch ( console . error ) ;
console . log ( ` - Opened ${ openAddress } ` ) ;
2019-07-16 01:31:05 +07:00
}
2019-07-03 04:55:54 +07:00
} ;
main ( ) . catch ( ( error ) = > {
console . error ( error ) ;
process . exit ( 1 ) ;
} ) ;