Make providers endpoint-agnostic
A provider can now be registered on multiple endpoints (or potentially moved if needed).
This commit is contained in:
parent
2819fd51e2
commit
e8f6d30055
|
@ -24,7 +24,7 @@ export class ProxyHttpProvider extends HttpProvider {
|
||||||
const port = route.base.replace(/^\//, "")
|
const port = route.base.replace(/^\//, "")
|
||||||
return {
|
return {
|
||||||
proxy: {
|
proxy: {
|
||||||
base: `${this.options.base}/${port}`,
|
base: `${route.providerBase}/${port}`,
|
||||||
port,
|
port,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ export class ProxyHttpProvider extends HttpProvider {
|
||||||
const port = route.base.replace(/^\//, "")
|
const port = route.base.replace(/^\//, "")
|
||||||
return {
|
return {
|
||||||
proxy: {
|
proxy: {
|
||||||
base: `${this.options.base}/${port}`,
|
base: `${route.providerBase}/${port}`,
|
||||||
port,
|
port,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,7 +131,7 @@ export class VscodeHttpProvider extends HttpProvider {
|
||||||
if (!this.isRoot(route)) {
|
if (!this.isRoot(route)) {
|
||||||
throw new HttpError("Not found", HttpCode.NotFound)
|
throw new HttpError("Not found", HttpCode.NotFound)
|
||||||
} else if (!this.authenticated(request)) {
|
} else if (!this.authenticated(request)) {
|
||||||
return { redirect: "/login", query: { to: this.options.base } }
|
return { redirect: "/login", query: { to: route.providerBase } }
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return await this.getRoot(request, route)
|
return await this.getRoot(request, route)
|
||||||
|
|
|
@ -71,7 +71,7 @@ const main = async (args: Args, cliArgs: Args, configArgs: Args): Promise<void>
|
||||||
}
|
}
|
||||||
|
|
||||||
const httpServer = new HttpServer(options)
|
const httpServer = new HttpServer(options)
|
||||||
httpServer.registerHttpProvider("/", VscodeHttpProvider, args)
|
httpServer.registerHttpProvider(["/", "/vscode"], VscodeHttpProvider, args)
|
||||||
httpServer.registerHttpProvider("/update", UpdateHttpProvider, false)
|
httpServer.registerHttpProvider("/update", UpdateHttpProvider, false)
|
||||||
httpServer.registerHttpProvider("/proxy", ProxyHttpProvider)
|
httpServer.registerHttpProvider("/proxy", ProxyHttpProvider)
|
||||||
httpServer.registerHttpProvider("/login", LoginHttpProvider, args.config!, envPassword)
|
httpServer.registerHttpProvider("/login", LoginHttpProvider, args.config!, envPassword)
|
||||||
|
|
|
@ -79,9 +79,8 @@ export interface HttpResponse<T = string | Buffer | object> {
|
||||||
*/
|
*/
|
||||||
mime?: string
|
mime?: string
|
||||||
/**
|
/**
|
||||||
* Redirect to this path. Will rewrite against the base path but NOT the
|
* Redirect to this path. This is constructed against the site base (not the
|
||||||
* provider endpoint so you must include it. This allows redirecting outside
|
* provider's base).
|
||||||
* of your endpoint.
|
|
||||||
*/
|
*/
|
||||||
redirect?: string
|
redirect?: string
|
||||||
/**
|
/**
|
||||||
|
@ -133,12 +132,16 @@ export interface HttpServerOptions {
|
||||||
|
|
||||||
export interface Route {
|
export interface Route {
|
||||||
/**
|
/**
|
||||||
* Base path part (in /test/path it would be "/test").
|
* Provider base path part (for /provider/base/path it would be /provider).
|
||||||
|
*/
|
||||||
|
providerBase: string
|
||||||
|
/**
|
||||||
|
* Base path part (for /provider/base/path it would be /base).
|
||||||
*/
|
*/
|
||||||
base: string
|
base: string
|
||||||
/**
|
/**
|
||||||
* Remaining part of the route (in /test/path it would be "/path"). It can be
|
* Remaining part of the route after factoring out the base and provider base
|
||||||
* blank.
|
* (for /provider/base/path it would be /path). It can be blank.
|
||||||
*/
|
*/
|
||||||
requestPath: string
|
requestPath: string
|
||||||
/**
|
/**
|
||||||
|
@ -161,7 +164,6 @@ interface ProviderRoute extends Route {
|
||||||
|
|
||||||
export interface HttpProviderOptions {
|
export interface HttpProviderOptions {
|
||||||
readonly auth: AuthType
|
readonly auth: AuthType
|
||||||
readonly base: string
|
|
||||||
readonly commit: string
|
readonly commit: string
|
||||||
readonly password?: string
|
readonly password?: string
|
||||||
}
|
}
|
||||||
|
@ -518,41 +520,51 @@ 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: HttpProvider0<T>): T
|
public registerHttpProvider<T extends HttpProvider>(endpoint: string | string[], provider: HttpProvider0<T>): T
|
||||||
public registerHttpProvider<A1, T extends HttpProvider>(endpoint: string, provider: HttpProvider1<A1, T>, a1: A1): T
|
public registerHttpProvider<A1, T extends HttpProvider>(
|
||||||
|
endpoint: string | string[],
|
||||||
|
provider: HttpProvider1<A1, T>,
|
||||||
|
a1: A1,
|
||||||
|
): T
|
||||||
public registerHttpProvider<A1, A2, T extends HttpProvider>(
|
public registerHttpProvider<A1, A2, T extends HttpProvider>(
|
||||||
endpoint: string,
|
endpoint: string | string[],
|
||||||
provider: HttpProvider2<A1, A2, T>,
|
provider: HttpProvider2<A1, A2, T>,
|
||||||
a1: A1,
|
a1: A1,
|
||||||
a2: A2,
|
a2: A2,
|
||||||
): T
|
): T
|
||||||
public registerHttpProvider<A1, A2, A3, T extends HttpProvider>(
|
public registerHttpProvider<A1, A2, A3, T extends HttpProvider>(
|
||||||
endpoint: string,
|
endpoint: string | string[],
|
||||||
provider: HttpProvider3<A1, A2, A3, T>,
|
provider: HttpProvider3<A1, A2, A3, T>,
|
||||||
a1: A1,
|
a1: A1,
|
||||||
a2: A2,
|
a2: A2,
|
||||||
a3: A3,
|
a3: A3,
|
||||||
): T
|
): T
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
public registerHttpProvider(endpoint: string, provider: any, ...args: any[]): any {
|
public registerHttpProvider(endpoint: string | string[], provider: any, ...args: any[]): void {
|
||||||
endpoint = endpoint.replace(/^\/+|\/+$/g, "")
|
|
||||||
if (this.providers.has(`/${endpoint}`)) {
|
|
||||||
throw new Error(`${endpoint} is already registered`)
|
|
||||||
}
|
|
||||||
if (/\//.test(endpoint)) {
|
|
||||||
throw new Error(`Only top-level endpoints are supported (got ${endpoint})`)
|
|
||||||
}
|
|
||||||
const p = new provider(
|
const p = new provider(
|
||||||
{
|
{
|
||||||
auth: this.options.auth || AuthType.None,
|
auth: this.options.auth || AuthType.None,
|
||||||
base: `/${endpoint}`,
|
|
||||||
commit: this.options.commit,
|
commit: this.options.commit,
|
||||||
password: this.options.password,
|
password: this.options.password,
|
||||||
},
|
},
|
||||||
...args,
|
...args,
|
||||||
)
|
)
|
||||||
this.providers.set(`/${endpoint}`, p)
|
const endpoints = (typeof endpoint === "string" ? [endpoint] : endpoint).map((e) => e.replace(/^\/+|\/+$/g, ""))
|
||||||
return p
|
endpoints.forEach((endpoint) => {
|
||||||
|
if (/\//.test(endpoint)) {
|
||||||
|
throw new Error(`Only top-level endpoints are supported (got ${endpoint})`)
|
||||||
|
}
|
||||||
|
const existingProvider = this.providers.get(`/${endpoint}`)
|
||||||
|
this.providers.set(`/${endpoint}`, p)
|
||||||
|
if (existingProvider) {
|
||||||
|
logger.debug(`Overridding existing /${endpoint} provider`)
|
||||||
|
// If the existing provider isn't registered elsewhere we can dispose.
|
||||||
|
if (!Array.from(this.providers.values()).find((p) => p === existingProvider)) {
|
||||||
|
logger.debug(`Disposing existing /${endpoint} provider`)
|
||||||
|
existingProvider.dispose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -759,7 +771,7 @@ export class HttpServer {
|
||||||
// that by shifting the next base out of the request path.
|
// that by shifting the next base out of the request path.
|
||||||
let provider = this.providers.get(base)
|
let provider = this.providers.get(base)
|
||||||
if (base !== "/" && provider) {
|
if (base !== "/" && provider) {
|
||||||
return { ...parse(requestPath), fullPath, query: parsedUrl.query, provider, originalPath }
|
return { ...parse(requestPath), providerBase: base, fullPath, query: parsedUrl.query, provider, originalPath }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fall back to the top-level provider.
|
// Fall back to the top-level provider.
|
||||||
|
@ -767,7 +779,7 @@ export class HttpServer {
|
||||||
if (!provider) {
|
if (!provider) {
|
||||||
throw new Error(`No provider for ${base}`)
|
throw new Error(`No provider for ${base}`)
|
||||||
}
|
}
|
||||||
return { base, fullPath, requestPath, query: parsedUrl.query, provider, originalPath }
|
return { base, providerBase: "/", fullPath, requestPath, query: parsedUrl.query, provider, originalPath }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -51,7 +51,6 @@ describe("update", () => {
|
||||||
_provider = new UpdateHttpProvider(
|
_provider = new UpdateHttpProvider(
|
||||||
{
|
{
|
||||||
auth: AuthType.None,
|
auth: AuthType.None,
|
||||||
base: "/update",
|
|
||||||
commit: "test",
|
commit: "test",
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
|
|
Loading…
Reference in New Issue