Archived
1
0

Improve HTTP provider registration

This commit is contained in:
Asher 2020-02-04 16:55:27 -06:00
parent 4a54e914fc
commit dbc5c065f8
No known key found for this signature in database
GPG Key ID: D63C1EF81242354A
4 changed files with 40 additions and 16 deletions

View File

@ -18,7 +18,7 @@ interface LoginPayload extends PostData {
export class ApiHttpProvider extends HttpProvider { export class ApiHttpProvider extends HttpProvider {
private readonly ws = new ws.Server({ noServer: true }) private readonly ws = new ws.Server({ noServer: true })
public constructor(private readonly server: HttpServer, options: HttpProviderOptions) { public constructor(options: HttpProviderOptions, private readonly server: HttpServer) {
super(options) super(options)
} }

View File

@ -20,6 +20,9 @@ export interface Args {
} }
const main = async (args: Args = {}): Promise<void> => { const main = async (args: Args = {}): Promise<void> => {
const auth = args.auth || AuthType.Password
const originalPassword = auth === AuthType.Password && (process.env.PASSWORD || (await generatePassword()))
// Spawn the main HTTP server. // Spawn the main HTTP server.
const options = { const options = {
basePath: args["base-path"], basePath: args["base-path"],
@ -28,6 +31,8 @@ const main = async (args: Args = {}): Promise<void> => {
host: args.host || (args.auth === AuthType.Password && typeof args.cert !== "undefined" ? "0.0.0.0" : "localhost"), host: args.host || (args.auth === AuthType.Password && typeof args.cert !== "undefined" ? "0.0.0.0" : "localhost"),
port: typeof args.port !== "undefined" ? parseInt(args.port, 10) : 8080, port: typeof args.port !== "undefined" ? parseInt(args.port, 10) : 8080,
socket: args.socket, socket: args.socket,
auth,
password: originalPassword ? hash(originalPassword) : undefined,
} }
if (!options.cert && typeof options.cert !== "undefined") { if (!options.cert && typeof options.cert !== "undefined") {
const { cert, certKey } = await generateCertificate() const { cert, certKey } = await generateCertificate()
@ -37,17 +42,9 @@ const main = async (args: Args = {}): Promise<void> => {
const httpServer = new HttpServer(options) const httpServer = new HttpServer(options)
// Register all the providers. // Register all the providers.
// TODO: Might be cleaner to be able to register with just the class name httpServer.registerHttpProvider("/", MainHttpProvider)
// then let HttpServer instantiate with the common arguments. httpServer.registerHttpProvider("/api", ApiHttpProvider, httpServer)
const auth = args.auth || AuthType.Password httpServer.registerHttpProvider("/vscode-embed", VscodeHttpProvider, [])
const originalPassword = auth === AuthType.Password && (process.env.PASSWORD || (await generatePassword()))
const password = originalPassword && hash(originalPassword)
httpServer.registerHttpProvider("/", new MainHttpProvider({ base: "/", auth, password }))
httpServer.registerHttpProvider("/api", new ApiHttpProvider(httpServer, { base: "/", auth, password }))
httpServer.registerHttpProvider(
"/vscode-embed",
new VscodeHttpProvider([], { base: "/vscode-embed", auth, password })
)
ipcMain().onDispose(() => httpServer.dispose()) ipcMain().onDispose(() => httpServer.dispose())

View File

@ -88,10 +88,12 @@ export interface HttpStringFileResponse extends HttpResponse {
} }
export interface HttpServerOptions { export interface HttpServerOptions {
readonly auth?: AuthType
readonly basePath?: string readonly basePath?: string
readonly cert?: string readonly cert?: string
readonly certKey?: string readonly certKey?: string
readonly host?: string readonly host?: string
readonly password?: string
readonly port?: number readonly port?: number
readonly socket?: string readonly socket?: string
} }
@ -108,7 +110,7 @@ interface ProviderRoute {
export interface HttpProviderOptions { export interface HttpProviderOptions {
readonly base: string readonly base: string
readonly auth: AuthType readonly auth: AuthType
readonly password: string | false readonly password?: string
} }
/** /**
@ -320,6 +322,14 @@ export class Heart {
} }
} }
export interface HttpProvider0<T> {
new (options: HttpProviderOptions): T
}
export interface HttpProvider1<A1, T> {
new (options: HttpProviderOptions, a1: A1): T
}
/** /**
* An HTTP server. Its main role is to route incoming HTTP requests to the * An HTTP server. Its main role is to route incoming HTTP requests to the
* appropriate provider for that endpoint then write out the response. It also * appropriate provider for that endpoint then write out the response. It also
@ -372,7 +382,14 @@ export class HttpServer {
/** /**
* Register a provider for a top-level endpoint. * Register a provider for a top-level endpoint.
*/ */
public registerHttpProvider<T extends HttpProvider>(endpoint: string, provider: T): void { public registerHttpProvider<T extends HttpProvider>(endpoint: string, provider: HttpProvider0<T>): void
public registerHttpProvider<A1, T extends HttpProvider>(
endpoint: string,
provider: HttpProvider1<A1, T>,
a1: A1
): void
// eslint-disable-next-line @typescript-eslint/no-explicit-any
public registerHttpProvider(endpoint: string, provider: any, a1?: any): void {
endpoint = endpoint.replace(/^\/+|\/+$/g, "") endpoint = endpoint.replace(/^\/+|\/+$/g, "")
if (this.providers.has(`/${endpoint}`)) { if (this.providers.has(`/${endpoint}`)) {
throw new Error(`${endpoint} is already registered`) throw new Error(`${endpoint} is already registered`)
@ -380,7 +397,17 @@ export class HttpServer {
if (/\//.test(endpoint)) { if (/\//.test(endpoint)) {
throw new Error(`Only top-level endpoints are supported (got ${endpoint})`) throw new Error(`Only top-level endpoints are supported (got ${endpoint})`)
} }
this.providers.set(`/${endpoint}`, provider) this.providers.set(
`/${endpoint}`,
new provider(
{
auth: this.options.auth || AuthType.None,
base: endpoint,
password: this.options.password,
},
a1
)
)
} }
/** /**

View File

@ -24,7 +24,7 @@ export class VscodeHttpProvider extends HttpProvider {
private _vscode?: Promise<cp.ChildProcess> private _vscode?: Promise<cp.ChildProcess>
private workbenchOptions?: WorkbenchOptions private workbenchOptions?: WorkbenchOptions
public constructor(private readonly args: string[], options: HttpProviderOptions) { public constructor(options: HttpProviderOptions, private readonly args: string[]) {
super(options) super(options)
this.vsRootPath = path.resolve(this.rootPath, "lib/vscode") this.vsRootPath = path.resolve(this.rootPath, "lib/vscode")
this.serverRootPath = path.join(this.vsRootPath, "out/vs/server") this.serverRootPath = path.join(this.vsRootPath, "out/vs/server")