import * as http from "http" import * as querystring from "querystring" import { Application } from "../../common/api" import { HttpCode, HttpError } from "../../common/http" import { normalize } from "../../common/util" import { HttpProvider, HttpProviderOptions, HttpResponse, Route } from "../http" import { ApiHttpProvider } from "./api" import { UpdateHttpProvider } from "./update" /** * Dashboard HTTP provider. */ export class DashboardHttpProvider extends HttpProvider { public constructor( options: HttpProviderOptions, private readonly api: ApiHttpProvider, private readonly update: UpdateHttpProvider, ) { super(options) } public async handleRequest(route: Route, request: http.IncomingMessage): Promise { if (route.requestPath !== "/index.html") { throw new HttpError("Not found", HttpCode.NotFound) } switch (route.base) { case "/spawn": { this.ensureAuthenticated(request) this.ensureMethod(request, "POST") const data = await this.getData(request) const app = data ? querystring.parse(data) : {} if (app.path) { return { redirect: Array.isArray(app.path) ? app.path[0] : app.path } } if (!app.exec) { throw new Error("No exec was provided") } this.api.spawnProcess(Array.isArray(app.exec) ? app.exec[0] : app.exec) return { redirect: this.options.base } } case "/app": case "/": { this.ensureMethod(request) if (!this.authenticated(request)) { return { redirect: "/login", query: { to: this.options.base } } } return route.base === "/" ? this.getRoot(route) : this.getAppRoot(route) } } throw new HttpError("Not found", HttpCode.NotFound) } public async getRoot(route: Route): Promise { const base = this.base(route) const apps = await this.api.installedApplications() const response = await this.getUtf8Resource(this.rootPath, "src/browser/pages/home.html") response.content = response.content .replace(/{{UPDATE:NAME}}/, await this.getUpdate(base)) .replace( /{{APP_LIST:EDITORS}}/, this.getAppRows( base, apps.filter((app) => app.categories && app.categories.includes("Editor")), ), ) .replace( /{{APP_LIST:OTHER}}/, this.getAppRows( base, apps.filter((app) => !app.categories || !app.categories.includes("Editor")), ), ) return this.replaceTemplates(route, response) } public async getAppRoot(route: Route): Promise { const response = await this.getUtf8Resource(this.rootPath, "src/browser/pages/app.html") return this.replaceTemplates(route, response) } private getAppRows(base: string, apps: ReadonlyArray): string { return apps.length > 0 ? apps.map((app) => this.getAppRow(base, app)).join("\n") : `
No applications found.
` } private getAppRow(base: string, app: Application): string { return `
` } private async getUpdate(base: string): Promise { if (!this.update.enabled) { return `
Updates are disabled
` } const humanize = (time: number): string => { const d = new Date(time) const pad = (t: number): string => (t < 10 ? "0" : "") + t return ( `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}` + ` ${pad(d.getHours())}:${pad(d.getMinutes())}` ) } const update = await this.update.getUpdate() if (this.update.isLatestVersion(update)) { return `
Latest: ${update.version}
Up to date
${humanize(update.checked)} Check now
Current: ${this.update.currentVersion}
` } return `
Latest: ${update.version}
Out of date
${humanize(update.checked)} Update now
Current: ${this.update.currentVersion}
` } }