2019-07-02 21:55:54 +00:00
import * as os from "os" ;
2019-07-11 22:12:52 +00:00
2019-07-02 21:55:54 +00: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-02 23:29:48 +00:00
import { buildHelpMessage , buildVersionMessage , options } from "vs/platform/environment/node/argv" ;
2019-07-02 21:55:54 +00:00
import pkg from "vs/platform/product/node/package" ;
2019-07-16 19:57:02 +00:00
import product from "vs/platform/product/node/product" ;
2019-07-11 22:12:52 +00:00
2019-07-25 22:39:43 +00:00
import { MainServer } from "vs/server/src/server" ;
2019-07-31 20:29:11 +00:00
import { enableExtensionTars } from "vs/server/src/tar" ;
2019-07-31 20:22:05 +00:00
import { AuthType , buildAllowedMessage , generateCertificate , generatePassword , localRequire , open , unpackExecutables } from "vs/server/src/util" ;
2019-08-03 00:26:41 +00:00
import { main as vsCli } from "vs/code/node/cliProcessMain" ;
2019-07-31 20:22:05 +00:00
const { logger } = localRequire < typeof import ( " @ coder / logger / out / index " ) > ( "@coder/logger/out/index" ) ;
2019-07-02 21:55:54 +00:00
2019-07-02 23:29:48 +00:00
interface Args extends ParsedArgs {
2019-07-23 20:38:00 +00:00
auth? : AuthType ;
2019-07-23 20:17:25 +00:00
"base-path" ? : string ;
2019-07-10 23:33:18 +00:00
cert? : string ;
"cert-key" ? : string ;
"extra-builtin-extensions-dir" ? : string ;
"extra-extensions-dir" ? : string ;
host? : string ;
open? : string ;
2019-07-02 23:29:48 +00:00
port? : string ;
2019-07-10 23:33:18 +00:00
socket? : string ;
2019-07-02 23:29:48 +00:00
}
2019-07-10 23:33:18 +00: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-23 20:17:25 +00: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-23 20:38:00 +00: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-24 00:06:40 +00:00
options . push ( { id : "host" , type : "string" , cat : "o" , description : "Host for the server." } ) ;
2019-07-23 20:38:00 +00:00
options . push ( { id : "auth" , type : "string" , cat : "o" , description : ` The type of authentication to use. ${ buildAllowedMessage ( AuthType ) } . ` } ) ;
2019-07-10 23:33:18 +00:00
options . push ( { id : "open" , type : "boolean" , cat : "o" , description : "Open in the browser on startup." } ) ;
2019-07-02 23:29:48 +00:00
options . push ( { id : "port" , type : "string" , cat : "o" , description : "Port for the main server." } ) ;
2019-07-10 23:33:18 +00:00
options . push ( { id : "socket" , type : "string" , cat : "o" , description : "Listen on a socket instead of host:port." } ) ;
options . push ( last ) ;
2019-07-02 23:29:48 +00:00
2019-07-31 20:22:05 +00:00
const main = async ( ) : Promise < void | void [ ] > = > {
2019-07-02 23:29:48 +00:00
const args = validatePaths ( parseMainProcessArgv ( process . argv ) ) as Args ;
2019-07-12 21:39:38 +00:00
[ "extra-extensions-dir" , "extra-builtin-extensions-dir" ] . forEach ( ( key ) = > {
if ( typeof args [ key ] === "string" ) {
args [ key ] = [ args [ key ] ] ;
}
} ) ;
2019-07-02 21:55:54 +00: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-10 23:33:18 +00:00
const version = ` ${ ( pkg as any ) . codeServerVersion || "development" } -vsc ${ pkg . version } ` ;
2019-07-02 21:55:54 +00:00
if ( args . help ) {
const executable = ` ${ product . applicationName } ${ os . platform ( ) === "win32" ? ".exe" : "" } ` ;
2019-07-19 22:43:54 +00:00
return console . log ( buildHelpMessage ( product . nameLong , executable , version , undefined , false ) ) ;
2019-07-02 21:55:54 +00:00
}
if ( args . version ) {
2019-07-31 20:22:05 +00:00
return buildVersionMessage ( version , product . commit ) . split ( "\n" ) . map ( ( line ) = > logger . info ( line ) ) ;
2019-07-02 21:55:54 +00:00
}
2019-07-31 20:29:11 +00:00
enableExtensionTars ( ) ;
2019-07-02 21:55:54 +00:00
const shouldSpawnCliProcess = ( ) : boolean = > {
return ! ! args [ "install-source" ]
|| ! ! args [ "list-extensions" ]
|| ! ! args [ "install-extension" ]
|| ! ! args [ "uninstall-extension" ]
|| ! ! args [ "locate-extension" ]
|| ! ! args [ "telemetry" ] ;
} ;
if ( shouldSpawnCliProcess ( ) ) {
2019-08-03 00:26:41 +00:00
await vsCli ( args ) ;
2019-07-19 22:43:54 +00:00
return process . exit ( 0 ) ; // There is a WriteStream instance keeping it open.
2019-07-02 21:55:54 +00:00
}
2019-07-19 22:43:54 +00:00
const extra = args [ "_" ] || [ ] ;
2019-07-11 22:12:52 +00:00
const options = {
2019-07-23 20:38:00 +00:00
auth : args.auth ,
2019-07-23 20:17:25 +00:00
basePath : args [ "base-path" ] ,
2019-07-12 20:21:00 +00:00
cert : args.cert ,
certKey : args [ "cert-key" ] ,
2019-07-19 22:43:54 +00:00
folderUri : extra.length > 1 ? extra [ extra . length - 1 ] : undefined ,
host : args.host ,
2019-07-12 20:21:00 +00:00
password : process.env.PASSWORD ,
2019-07-11 22:12:52 +00:00
} ;
2019-07-23 20:38:00 +00: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-12 20:21:00 +00:00
}
2019-07-23 20:38:00 +00: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-11 22:12:52 +00:00
const { cert , certKey } = await generateCertificate ( ) ;
options . cert = cert ;
options . certKey = certKey ;
}
const server = new MainServer ( {
. . . options ,
2019-07-19 22:43:54 +00:00
port : typeof args . port !== "undefined" && parseInt ( args . port , 10 ) || 8443 ,
2019-07-11 22:12:52 +00:00
socket : args.socket ,
2019-07-24 00:06:40 +00:00
} , args ) ;
2019-07-11 22:12:52 +00:00
2019-07-24 00:06:40 +00:00
const [ serverAddress , /* ignore */ ] = await Promise . all ( [
2019-07-17 00:26:05 +00:00
server . listen ( ) ,
unpackExecutables ( ) ,
2019-07-05 15:54:44 +00:00
] ) ;
2019-07-31 20:22:05 +00:00
logger . info ( ` Server listening on ${ serverAddress } ` ) ;
2019-07-12 20:21:00 +00:00
2019-07-23 20:38:00 +00:00
if ( options . auth && ! process . env . PASSWORD ) {
2019-07-31 20:22:05 +00:00
logger . info ( ` - Password is ${ options . password } ` ) ;
logger . info ( " - To use your own password, set the PASSWORD environment variable" ) ;
2019-07-12 20:21:00 +00:00
} else if ( options . auth ) {
2019-07-31 20:22:05 +00:00
logger . info ( " - Using custom password for authentication" ) ;
2019-07-12 20:21:00 +00:00
} else {
2019-07-31 20:22:05 +00:00
logger . info ( " - No authentication" ) ;
2019-07-12 20:21:00 +00:00
}
2019-07-23 20:38:00 +00:00
if ( server . protocol === "https" ) {
2019-07-31 20:22:05 +00:00
logger . info (
2019-07-23 20:38:00 +00:00
args . cert
? ` - Using provided certificate ${ args [ "cert-key" ] ? " and key" : "" } for HTTPS `
: ` - Using generated certificate and key for HTTPS ` ,
2019-07-12 20:21:00 +00:00
) ;
} else {
2019-07-31 20:22:05 +00:00
logger . info ( " - Not serving HTTPS" ) ;
2019-07-12 20:21:00 +00:00
}
2019-07-15 18:31:05 +00:00
2019-07-23 20:38:00 +00:00
if ( ! server . options . socket && args . open ) {
2019-07-17 00:23:58 +00:00
// The web socket doesn't seem to work if using 0.0.0.0.
2019-07-19 22:43:54 +00:00
const openAddress = ` http://localhost: ${ server . options . port } ` ;
2019-07-17 00:23:58 +00:00
await open ( openAddress ) . catch ( console . error ) ;
2019-07-31 20:22:05 +00:00
logger . info ( ` - Opened ${ openAddress } ` ) ;
2019-07-15 18:31:05 +00:00
}
2019-07-02 21:55:54 +00:00
} ;
main ( ) . catch ( ( error ) = > {
console . error ( error ) ;
process . exit ( 1 ) ;
} ) ;