mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
145 lines
5.4 KiB
TypeScript
145 lines
5.4 KiB
TypeScript
import Call from "@hapi/call"
|
|
import Subtext from "@hapi/subtext"
|
|
import http from "http"
|
|
import path from "path"
|
|
import { readFile } from "fs-extra"
|
|
import { Cluster } from "./cluster"
|
|
import { apiPrefix, appName, outDir } from "../common/vars";
|
|
import { configRoute, helmRoute, kubeconfigRoute, metricsRoute, portForwardRoute, resourceApplierRoute, watchRoute } from "./routes";
|
|
|
|
export interface RouterRequestOpts {
|
|
req: http.IncomingMessage;
|
|
res: http.ServerResponse;
|
|
cluster: Cluster;
|
|
params: RouteParams;
|
|
url: URL;
|
|
}
|
|
|
|
export interface RouteParams extends Record<string, string> {
|
|
path?: string; // *-route
|
|
namespace?: string;
|
|
service?: string;
|
|
account?: string;
|
|
release?: string;
|
|
repo?: string;
|
|
chart?: string;
|
|
}
|
|
|
|
export interface LensApiRequest<P = any> {
|
|
path: string;
|
|
payload: P;
|
|
params: RouteParams;
|
|
cluster: Cluster;
|
|
response: http.ServerResponse;
|
|
query: URLSearchParams;
|
|
raw: {
|
|
req: http.IncomingMessage;
|
|
}
|
|
}
|
|
|
|
export class Router {
|
|
protected router: any;
|
|
|
|
public constructor() {
|
|
this.router = new Call.Router();
|
|
this.addRoutes()
|
|
}
|
|
|
|
public async route(cluster: Cluster, req: http.IncomingMessage, res: http.ServerResponse): Promise<boolean> {
|
|
const url = new URL(req.url, "http://localhost");
|
|
const path = url.pathname
|
|
const method = req.method.toLowerCase()
|
|
const matchingRoute = this.router.route(method, path);
|
|
const routeFound = !matchingRoute.isBoom;
|
|
if (routeFound) {
|
|
const request = await this.getRequest({ req, res, cluster, url, params: matchingRoute.params });
|
|
await matchingRoute.route(request)
|
|
return true
|
|
}
|
|
return false;
|
|
}
|
|
|
|
protected async getRequest(opts: RouterRequestOpts): Promise<LensApiRequest> {
|
|
const { req, res, url, cluster, params } = opts
|
|
const { payload } = await Subtext.parse(req, null, {
|
|
parse: true,
|
|
output: "data",
|
|
});
|
|
return {
|
|
cluster: cluster,
|
|
path: url.pathname,
|
|
raw: {
|
|
req: req,
|
|
},
|
|
response: res,
|
|
query: url.searchParams,
|
|
payload: payload,
|
|
params: params
|
|
}
|
|
}
|
|
|
|
protected getMimeType(filename: string) {
|
|
const mimeTypes: Record<string, string> = {
|
|
html: "text/html",
|
|
txt: "text/plain",
|
|
css: "text/css",
|
|
gif: "image/gif",
|
|
jpg: "image/jpeg",
|
|
png: "image/png",
|
|
svg: "image/svg+xml",
|
|
js: "application/javascript",
|
|
woff2: "font/woff2",
|
|
ttf: "font/ttf"
|
|
};
|
|
return mimeTypes[path.extname(filename).slice(1)] || "text/plain"
|
|
}
|
|
|
|
async handleStaticFile(filePath: string, res: http.ServerResponse) {
|
|
const asset = path.join(outDir, filePath);
|
|
try {
|
|
const data = await readFile(asset);
|
|
res.setHeader("Content-Type", this.getMimeType(asset));
|
|
res.write(data)
|
|
res.end()
|
|
} catch (err) {
|
|
this.handleStaticFile(`${appName}.html`, res);
|
|
}
|
|
}
|
|
|
|
protected addRoutes() {
|
|
// Static assets
|
|
this.router.add({ method: 'get', path: '/{path*}' }, ({ params, response }: LensApiRequest) => {
|
|
this.handleStaticFile(params.path, response);
|
|
});
|
|
|
|
this.router.add({ method: "get", path: `${apiPrefix}/config` }, configRoute.routeConfig.bind(configRoute))
|
|
this.router.add({ method: "get", path: `${apiPrefix}/kubeconfig/service-account/{namespace}/{account}` }, kubeconfigRoute.routeServiceAccountRoute.bind(kubeconfigRoute))
|
|
|
|
// Watch API
|
|
this.router.add({ method: "get", path: `${apiPrefix}/watch` }, watchRoute.routeWatch.bind(watchRoute))
|
|
|
|
// Metrics API
|
|
this.router.add({ method: "post", path: `${apiPrefix}/metrics` }, metricsRoute.routeMetrics.bind(metricsRoute))
|
|
|
|
// Port-forward API
|
|
this.router.add({ method: "post", path: `${apiPrefix}/services/{namespace}/{service}/port-forward/{port}` }, portForwardRoute.routeServicePortForward.bind(portForwardRoute))
|
|
|
|
// Helm API
|
|
this.router.add({ method: "get", path: `${apiPrefix}/v2/charts` }, helmRoute.listCharts.bind(helmRoute))
|
|
this.router.add({ method: "get", path: `${apiPrefix}/v2/charts/{repo}/{chart}` }, helmRoute.getChart.bind(helmRoute))
|
|
this.router.add({ method: "get", path: `${apiPrefix}/v2/charts/{repo}/{chart}/values` }, helmRoute.getChartValues.bind(helmRoute))
|
|
|
|
this.router.add({ method: "post", path: `${apiPrefix}/v2/releases` }, helmRoute.installChart.bind(helmRoute))
|
|
this.router.add({ method: `put`, path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, helmRoute.updateRelease.bind(helmRoute))
|
|
this.router.add({ method: `put`, path: `${apiPrefix}/v2/releases/{namespace}/{release}/rollback` }, helmRoute.rollbackRelease.bind(helmRoute))
|
|
this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace?}` }, helmRoute.listReleases.bind(helmRoute))
|
|
this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, helmRoute.getRelease.bind(helmRoute))
|
|
this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}/values` }, helmRoute.getReleaseValues.bind(helmRoute))
|
|
this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}/history` }, helmRoute.getReleaseHistory.bind(helmRoute))
|
|
this.router.add({ method: "delete", path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, helmRoute.deleteRelease.bind(helmRoute))
|
|
|
|
// Resource Applier API
|
|
this.router.add({ method: "post", path: `${apiPrefix}/stack` }, resourceApplierRoute.applyResource.bind(resourceApplierRoute))
|
|
}
|
|
}
|