Register a service worker
To make installing as a PWA possible. Fixes #1181.
This commit is contained in:
parent
eef2ed0e78
commit
963ebaca5b
29
ci/build.ts
29
ci/build.ts
|
@ -339,17 +339,24 @@ class Builder {
|
||||||
}
|
}
|
||||||
|
|
||||||
private createBundler(out = "dist", commit?: string): Bundler {
|
private createBundler(out = "dist", commit?: string): Bundler {
|
||||||
return new Bundler(path.join(this.rootPath, "src/browser/pages/app.ts"), {
|
return new Bundler(
|
||||||
cache: true,
|
[
|
||||||
cacheDir: path.join(this.rootPath, ".cache"),
|
path.join(this.rootPath, "src/browser/pages/app.ts"),
|
||||||
detailedReport: true,
|
path.join(this.rootPath, "src/browser/register.ts"),
|
||||||
minify: !!process.env.MINIFY,
|
path.join(this.rootPath, "src/browser/serviceWorker.ts"),
|
||||||
hmr: false,
|
],
|
||||||
logLevel: 1,
|
{
|
||||||
outDir: path.join(this.rootPath, out),
|
cache: true,
|
||||||
publicUrl: `/static-${commit}/dist`,
|
cacheDir: path.join(this.rootPath, ".cache"),
|
||||||
target: "browser",
|
detailedReport: true,
|
||||||
})
|
minify: !!process.env.MINIFY,
|
||||||
|
hmr: false,
|
||||||
|
logLevel: 1,
|
||||||
|
outDir: path.join(this.rootPath, out),
|
||||||
|
publicUrl: `/static-${commit || "development"}/dist`,
|
||||||
|
target: "browser",
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
"sizes": "96x96"
|
"sizes": "96x96"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "/{{BASE}}/static-{{COMMIT}}/src/browser/media/pwa-icon-128.png",
|
"src": "{{BASE}}/static-{{COMMIT}}/src/browser/media/pwa-icon-128.png",
|
||||||
"type": "image/png",
|
"type": "image/png",
|
||||||
"sizes": "128x128"
|
"sizes": "128x128"
|
||||||
},
|
},
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
<meta id="coder-options" data-settings="{{OPTIONS}}" />
|
<meta id="coder-options" data-settings="{{OPTIONS}}" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<script src="{{BASE}}/static-{{COMMIT}}/dist/register.js"></script>
|
||||||
<script src="{{BASE}}/static-{{COMMIT}}/dist/app.js"></script>
|
<script src="{{BASE}}/static-{{COMMIT}}/dist/app.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -8,8 +8,5 @@ import "./login.css"
|
||||||
import "./update.css"
|
import "./update.css"
|
||||||
|
|
||||||
const options = getOptions()
|
const options = getOptions()
|
||||||
const parts = window.location.pathname.replace(/^\//g, "").split("/")
|
|
||||||
parts[parts.length - 1] = options.base
|
|
||||||
const url = new URL(window.location.origin + "/" + parts.join("/"))
|
|
||||||
|
|
||||||
console.log(url)
|
console.log(options)
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
/>
|
/>
|
||||||
<link rel="apple-touch-icon" href="{{BASE}}/static-{{COMMIT}}/src/browser/media/code-server.png" />
|
<link rel="apple-touch-icon" href="{{BASE}}/static-{{COMMIT}}/src/browser/media/code-server.png" />
|
||||||
<link href="{{BASE}}/static-{{COMMIT}}/dist/app.css" rel="stylesheet" />
|
<link href="{{BASE}}/static-{{COMMIT}}/dist/app.css" rel="stylesheet" />
|
||||||
|
<meta id="coder-options" data-settings="{{OPTIONS}}" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="center-container">
|
<div class="center-container">
|
||||||
|
@ -29,5 +30,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<script src="{{BASE}}/static-{{COMMIT}}/dist/register.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -60,5 +60,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<script src="{{BASE}}/static-{{COMMIT}}/dist/register.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
/>
|
/>
|
||||||
<meta
|
<meta
|
||||||
http-equiv="Content-Security-Policy"
|
http-equiv="Content-Security-Policy"
|
||||||
content="style-src 'self'; script-src 'unsafe-inline'; manifest-src 'self'; img-src 'self' data:;"
|
content="style-src 'self'; script-src 'self' 'unsafe-inline'; manifest-src 'self'; img-src 'self' data:;"
|
||||||
/>
|
/>
|
||||||
<title>code-server login</title>
|
<title>code-server login</title>
|
||||||
<link rel="icon" href="{{BASE}}/static-{{COMMIT}}/src/browser/media/favicon.ico" type="image/x-icon" />
|
<link rel="icon" href="{{BASE}}/static-{{COMMIT}}/src/browser/media/favicon.ico" type="image/x-icon" />
|
||||||
|
@ -19,6 +19,7 @@
|
||||||
/>
|
/>
|
||||||
<link rel="apple-touch-icon" href="{{BASE}}/static-{{COMMIT}}/src/browser/media/code-server.png" />
|
<link rel="apple-touch-icon" href="{{BASE}}/static-{{COMMIT}}/src/browser/media/code-server.png" />
|
||||||
<link href="{{BASE}}/static-{{COMMIT}}/dist/app.css" rel="stylesheet" />
|
<link href="{{BASE}}/static-{{COMMIT}}/dist/app.css" rel="stylesheet" />
|
||||||
|
<meta id="coder-options" data-settings="{{OPTIONS}}" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="center-container">
|
<div class="center-container">
|
||||||
|
@ -52,6 +53,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
<script src="{{BASE}}/static-{{COMMIT}}/dist/register.js"></script>
|
||||||
<script>
|
<script>
|
||||||
const parts = window.location.pathname.replace(/^\//g, "").split("/")
|
const parts = window.location.pathname.replace(/^\//g, "").split("/")
|
||||||
parts[parts.length - 1] = "{{BASE}}"
|
parts[parts.length - 1] = "{{BASE}}"
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
/>
|
/>
|
||||||
<link rel="apple-touch-icon" href="{{BASE}}/static-{{COMMIT}}/src/browser/media/code-server.png" />
|
<link rel="apple-touch-icon" href="{{BASE}}/static-{{COMMIT}}/src/browser/media/code-server.png" />
|
||||||
<link href="{{BASE}}/static-{{COMMIT}}/dist/app.css" rel="stylesheet" />
|
<link href="{{BASE}}/static-{{COMMIT}}/dist/app.css" rel="stylesheet" />
|
||||||
|
<meta id="coder-options" data-settings="{{OPTIONS}}" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="center-container">
|
<div class="center-container">
|
||||||
|
@ -32,5 +33,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<script src="{{BASE}}/static-{{COMMIT}}/dist/register.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -41,6 +41,8 @@
|
||||||
<!-- PROD_ONLY
|
<!-- PROD_ONLY
|
||||||
<link rel="prefetch" href="{{VS_BASE}}/static-{{COMMIT}}/node_modules/semver-umd/lib/semver-umd.js">
|
<link rel="prefetch" href="{{VS_BASE}}/static-{{COMMIT}}/node_modules/semver-umd/lib/semver-umd.js">
|
||||||
END_PROD_ONLY -->
|
END_PROD_ONLY -->
|
||||||
|
|
||||||
|
<meta id="coder-options" data-settings="{{OPTIONS}}" />
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body aria-label=""></body>
|
<body aria-label=""></body>
|
||||||
|
@ -91,6 +93,7 @@
|
||||||
"vs/nls": nlsConfig,
|
"vs/nls": nlsConfig,
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
<script src="{{BASE}}/static-{{COMMIT}}/dist/register.js"></script>
|
||||||
<script src="{{VS_BASE}}/static-{{COMMIT}}/out/vs/loader.js"></script>
|
<script src="{{VS_BASE}}/static-{{COMMIT}}/out/vs/loader.js"></script>
|
||||||
<!-- PROD_ONLY
|
<!-- PROD_ONLY
|
||||||
<script src="{{VS_BASE}}/static-{{COMMIT}}/out/vs/workbench/workbench.web.api.nls.js"></script>
|
<script src="{{VS_BASE}}/static-{{COMMIT}}/out/vs/workbench/workbench.web.api.nls.js"></script>
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { getOptions, normalize } from "../common/util"
|
||||||
|
|
||||||
|
const options = getOptions()
|
||||||
|
|
||||||
|
if ("serviceWorker" in navigator) {
|
||||||
|
const path = normalize(`${options.base}/static-${options.commit}/dist/serviceWorker.js`)
|
||||||
|
navigator.serviceWorker
|
||||||
|
.register(path, {
|
||||||
|
scope: options.base || "/",
|
||||||
|
})
|
||||||
|
.then(function() {
|
||||||
|
console.log("[Service Worker] registered")
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
|
||||||
|
self.addEventListener("install", () => {
|
||||||
|
console.log("[Service Worker] install")
|
||||||
|
})
|
||||||
|
|
||||||
|
self.addEventListener("activate", (event: any) => {
|
||||||
|
event.waitUntil((self as any).clients.claim())
|
||||||
|
})
|
||||||
|
|
||||||
|
self.addEventListener("fetch", (event: any) => {
|
||||||
|
if (!navigator.onLine) {
|
||||||
|
event.respondWith(
|
||||||
|
new Promise((resolve) => {
|
||||||
|
resolve(
|
||||||
|
new Response("OFFLINE", {
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
|
@ -2,8 +2,9 @@ import { logger } from "@coder/logger"
|
||||||
|
|
||||||
export interface Options {
|
export interface Options {
|
||||||
base: string
|
base: string
|
||||||
|
commit: string
|
||||||
logLevel: number
|
logLevel: number
|
||||||
sessionId: string
|
sessionId?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -25,6 +26,13 @@ export const generateUuid = (length = 24): string => {
|
||||||
.join("")
|
.join("")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove extra slashes in a URL.
|
||||||
|
*/
|
||||||
|
export const normalize = (url: string, keepTrailing = false): string => {
|
||||||
|
return url.replace(/\/\/+/g, "/").replace(/\/+$/, keepTrailing ? "/" : "")
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get options embedded in the HTML from the server.
|
* Get options embedded in the HTML from the server.
|
||||||
*/
|
*/
|
||||||
|
@ -45,16 +53,15 @@ export const getOptions = <T extends Options>(): T => {
|
||||||
if (typeof options.logLevel !== "undefined") {
|
if (typeof options.logLevel !== "undefined") {
|
||||||
logger.level = options.logLevel
|
logger.level = options.logLevel
|
||||||
}
|
}
|
||||||
return options
|
const parts = window.location.pathname.replace(/^\//g, "").split("/")
|
||||||
|
parts[parts.length - 1] = options.base
|
||||||
|
const url = new URL(window.location.origin + "/" + parts.join("/"))
|
||||||
|
return {
|
||||||
|
...options,
|
||||||
|
base: normalize(url.pathname, true),
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.warn(error.message)
|
logger.warn(error.message)
|
||||||
return {} as T
|
return {} as T
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove extra slashes in a URL.
|
|
||||||
*/
|
|
||||||
export const normalize = (url: string, keepTrailing = false): string => {
|
|
||||||
return url.replace(/\/\/+/g, "/").replace(/\/+$/, keepTrailing ? "/" : "")
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
import { logger } from "@coder/logger"
|
|
||||||
import * as http from "http"
|
import * as http from "http"
|
||||||
import * as querystring from "querystring"
|
import * as querystring from "querystring"
|
||||||
import { Application } from "../../common/api"
|
import { Application } from "../../common/api"
|
||||||
import { HttpCode, HttpError } from "../../common/http"
|
import { HttpCode, HttpError } from "../../common/http"
|
||||||
import { Options } from "../../common/util"
|
|
||||||
import { HttpProvider, HttpProviderOptions, HttpResponse, Route } from "../http"
|
import { HttpProvider, HttpProviderOptions, HttpResponse, Route } from "../http"
|
||||||
import { ApiHttpProvider } from "./api"
|
import { ApiHttpProvider } from "./api"
|
||||||
import { UpdateHttpProvider } from "./update"
|
import { UpdateHttpProvider } from "./update"
|
||||||
|
@ -61,15 +59,7 @@ export class MainHttpProvider extends HttpProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sessionId) {
|
if (sessionId) {
|
||||||
return this.getAppRoot(
|
return this.getAppRoot(route, (app && app.name) || "", sessionId)
|
||||||
route,
|
|
||||||
{
|
|
||||||
sessionId,
|
|
||||||
base: this.base(route),
|
|
||||||
logLevel: logger.level,
|
|
||||||
},
|
|
||||||
(app && app.name) || "",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.getErrorRoot(route, "404", "404", "Application not found")
|
return this.getErrorRoot(route, "404", "404", "Application not found")
|
||||||
|
@ -79,12 +69,12 @@ export class MainHttpProvider extends HttpProvider {
|
||||||
* Return a resource with variables replaced where necessary.
|
* Return a resource with variables replaced where necessary.
|
||||||
*/
|
*/
|
||||||
protected async getReplacedResource(route: Route): Promise<HttpResponse> {
|
protected async getReplacedResource(route: Route): Promise<HttpResponse> {
|
||||||
if (route.requestPath.endsWith("/manifest.json")) {
|
const split = route.requestPath.split("/")
|
||||||
const response = await this.getUtf8Resource(this.rootPath, route.requestPath)
|
switch (split[split.length - 1]) {
|
||||||
response.content = response.content
|
case "manifest.json": {
|
||||||
.replace(/{{BASE}}/g, this.base(route))
|
const response = await this.getUtf8Resource(this.rootPath, route.requestPath)
|
||||||
.replace(/{{COMMIT}}/g, this.options.commit)
|
return this.replaceTemplates(route, response)
|
||||||
return response
|
}
|
||||||
}
|
}
|
||||||
return this.getResource(this.rootPath, route.requestPath)
|
return this.getResource(this.rootPath, route.requestPath)
|
||||||
}
|
}
|
||||||
|
@ -94,8 +84,6 @@ export class MainHttpProvider extends HttpProvider {
|
||||||
const apps = await this.api.installedApplications()
|
const apps = await this.api.installedApplications()
|
||||||
const response = await this.getUtf8Resource(this.rootPath, "src/browser/pages/home.html")
|
const response = await this.getUtf8Resource(this.rootPath, "src/browser/pages/home.html")
|
||||||
response.content = response.content
|
response.content = response.content
|
||||||
.replace(/{{COMMIT}}/g, this.options.commit)
|
|
||||||
.replace(/{{BASE}}/g, this.base(route))
|
|
||||||
.replace(/{{UPDATE:NAME}}/, await this.getUpdate())
|
.replace(/{{UPDATE:NAME}}/, await this.getUpdate())
|
||||||
.replace(/{{APP_LIST:RUNNING}}/, this.getAppRows(running.applications))
|
.replace(/{{APP_LIST:RUNNING}}/, this.getAppRows(running.applications))
|
||||||
.replace(
|
.replace(
|
||||||
|
@ -106,17 +94,13 @@ export class MainHttpProvider extends HttpProvider {
|
||||||
/{{APP_LIST:OTHER}}/,
|
/{{APP_LIST:OTHER}}/,
|
||||||
this.getAppRows(apps.filter((app) => !app.categories || !app.categories.includes("Editor"))),
|
this.getAppRows(apps.filter((app) => !app.categories || !app.categories.includes("Editor"))),
|
||||||
)
|
)
|
||||||
return response
|
return this.replaceTemplates(route, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getAppRoot(route: Route, options: Options, name: string): Promise<HttpResponse> {
|
public async getAppRoot(route: Route, name: string, sessionId: string): Promise<HttpResponse> {
|
||||||
const response = await this.getUtf8Resource(this.rootPath, "src/browser/pages/app.html")
|
const response = await this.getUtf8Resource(this.rootPath, "src/browser/pages/app.html")
|
||||||
response.content = response.content
|
response.content = response.content.replace(/{{APP_NAME}}/, name)
|
||||||
.replace(/{{COMMIT}}/g, this.options.commit)
|
return this.replaceTemplates(route, response, sessionId)
|
||||||
.replace(/{{BASE}}/g, this.base(route))
|
|
||||||
.replace(/{{APP_NAME}}/, name)
|
|
||||||
.replace(/"{{OPTIONS}}"/, `'${JSON.stringify(options)}'`)
|
|
||||||
return response
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async handleWebSocket(): Promise<undefined> {
|
public async handleWebSocket(): Promise<undefined> {
|
||||||
|
|
|
@ -48,11 +48,9 @@ export class LoginHttpProvider extends HttpProvider {
|
||||||
public async getRoot(route: Route, value?: string, error?: Error): Promise<HttpResponse> {
|
public async getRoot(route: Route, value?: string, error?: Error): Promise<HttpResponse> {
|
||||||
const response = await this.getUtf8Resource(this.rootPath, "src/browser/pages/login.html")
|
const response = await this.getUtf8Resource(this.rootPath, "src/browser/pages/login.html")
|
||||||
response.content = response.content
|
response.content = response.content
|
||||||
.replace(/{{COMMIT}}/g, this.options.commit)
|
|
||||||
.replace(/{{BASE}}/g, this.base(route))
|
|
||||||
.replace(/{{VALUE}}/, value || "")
|
.replace(/{{VALUE}}/, value || "")
|
||||||
.replace(/{{ERROR}}/, error ? `<div class="error">${error.message}</div>` : "")
|
.replace(/{{ERROR}}/, error ? `<div class="error">${error.message}</div>` : "")
|
||||||
return response
|
return this.replaceTemplates(route, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -86,11 +86,9 @@ export class UpdateHttpProvider extends HttpProvider {
|
||||||
public async getRoot(route: Route, error?: Error): Promise<HttpResponse> {
|
public async getRoot(route: Route, error?: Error): Promise<HttpResponse> {
|
||||||
const response = await this.getUtf8Resource(this.rootPath, "src/browser/pages/update.html")
|
const response = await this.getUtf8Resource(this.rootPath, "src/browser/pages/update.html")
|
||||||
response.content = response.content
|
response.content = response.content
|
||||||
.replace(/{{COMMIT}}/g, this.options.commit)
|
|
||||||
.replace(/{{BASE}}/g, this.base(route))
|
|
||||||
.replace(/{{UPDATE_STATUS}}/, await this.getUpdateHtml())
|
.replace(/{{UPDATE_STATUS}}/, await this.getUpdateHtml())
|
||||||
.replace(/{{ERROR}}/, error ? `<div class="error">${error.message}</div>` : "")
|
.replace(/{{ERROR}}/, error ? `<div class="error">${error.message}</div>` : "")
|
||||||
return response
|
return this.replaceTemplates(route, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
public async handleWebSocket(): Promise<undefined> {
|
public async handleWebSocket(): Promise<undefined> {
|
||||||
|
|
|
@ -219,17 +219,13 @@ export class VscodeHttpProvider extends HttpProvider {
|
||||||
response.content = response.content.replace(/<!-- PROD_ONLY/g, "").replace(/END_PROD_ONLY -->/g, "")
|
response.content = response.content.replace(/<!-- PROD_ONLY/g, "").replace(/END_PROD_ONLY -->/g, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
response.content = response.content
|
||||||
...response,
|
.replace(/{{VS_BASE}}/g, this.base(route) + this.options.base)
|
||||||
content: response.content
|
.replace(`"{{REMOTE_USER_DATA_URI}}"`, `'${JSON.stringify(options.remoteUserDataUri)}'`)
|
||||||
.replace(/{{COMMIT}}/g, options.commit)
|
.replace(`"{{PRODUCT_CONFIGURATION}}"`, `'${JSON.stringify(options.productConfiguration)}'`)
|
||||||
.replace(/{{BASE}}/g, this.base(route))
|
.replace(`"{{WORKBENCH_WEB_CONFIGURATION}}"`, `'${JSON.stringify(options.workbenchWebConfiguration)}'`)
|
||||||
.replace(/{{VS_BASE}}/g, this.base(route) + this.options.base)
|
.replace(`"{{NLS_CONFIGURATION}}"`, `'${JSON.stringify(options.nlsConfiguration)}'`)
|
||||||
.replace(`"{{REMOTE_USER_DATA_URI}}"`, `'${JSON.stringify(options.remoteUserDataUri)}'`)
|
return this.replaceTemplates(route, response)
|
||||||
.replace(`"{{PRODUCT_CONFIGURATION}}"`, `'${JSON.stringify(options.productConfiguration)}'`)
|
|
||||||
.replace(`"{{WORKBENCH_WEB_CONFIGURATION}}"`, `'${JSON.stringify(options.workbenchWebConfiguration)}'`)
|
|
||||||
.replace(`"{{NLS_CONFIGURATION}}"`, `'${JSON.stringify(options.nlsConfiguration)}'`),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -12,7 +12,7 @@ import * as tarFs from "tar-fs"
|
||||||
import * as tls from "tls"
|
import * as tls from "tls"
|
||||||
import * as url from "url"
|
import * as url from "url"
|
||||||
import { HttpCode, HttpError } from "../common/http"
|
import { HttpCode, HttpError } from "../common/http"
|
||||||
import { normalize, plural, split } from "../common/util"
|
import { normalize, Options, plural, split } from "../common/util"
|
||||||
import { SocketProxyProvider } from "./socket"
|
import { SocketProxyProvider } from "./socket"
|
||||||
import { getMediaMime, xdgLocalDir } from "./util"
|
import { getMediaMime, xdgLocalDir } from "./util"
|
||||||
|
|
||||||
|
@ -165,14 +165,36 @@ export abstract class HttpProvider {
|
||||||
return normalize("./" + (depth > 1 ? "../".repeat(depth - 1) : ""))
|
return normalize("./" + (depth > 1 ? "../".repeat(depth - 1) : ""))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get error response.
|
||||||
|
*/
|
||||||
public async getErrorRoot(route: Route, title: string, header: string, body: string): Promise<HttpResponse> {
|
public async getErrorRoot(route: Route, title: string, header: string, body: string): Promise<HttpResponse> {
|
||||||
const response = await this.getUtf8Resource(this.rootPath, "src/browser/pages/error.html")
|
const response = await this.getUtf8Resource(this.rootPath, "src/browser/pages/error.html")
|
||||||
response.content = response.content
|
response.content = response.content
|
||||||
.replace(/{{COMMIT}}/g, this.options.commit)
|
|
||||||
.replace(/{{BASE}}/g, this.base(route))
|
|
||||||
.replace(/{{ERROR_TITLE}}/g, title)
|
.replace(/{{ERROR_TITLE}}/g, title)
|
||||||
.replace(/{{ERROR_HEADER}}/g, header)
|
.replace(/{{ERROR_HEADER}}/g, header)
|
||||||
.replace(/{{ERROR_BODY}}/g, body)
|
.replace(/{{ERROR_BODY}}/g, body)
|
||||||
|
return this.replaceTemplates(route, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace common templates strings.
|
||||||
|
*/
|
||||||
|
protected replaceTemplates(
|
||||||
|
route: Route,
|
||||||
|
response: HttpStringFileResponse,
|
||||||
|
sessionId?: string,
|
||||||
|
): HttpStringFileResponse {
|
||||||
|
const options: Options = {
|
||||||
|
base: this.base(route),
|
||||||
|
commit: this.options.commit,
|
||||||
|
logLevel: logger.level,
|
||||||
|
sessionId,
|
||||||
|
}
|
||||||
|
response.content = response.content
|
||||||
|
.replace(/{{COMMIT}}/g, this.options.commit)
|
||||||
|
.replace(/{{BASE}}/g, this.base(route))
|
||||||
|
.replace(/"{{OPTIONS}}"/, `'${JSON.stringify(options)}'`)
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,11 +360,15 @@ export class Heart {
|
||||||
clearTimeout(this.heartbeatTimer)
|
clearTimeout(this.heartbeatTimer)
|
||||||
}
|
}
|
||||||
this.heartbeatTimer = setTimeout(() => {
|
this.heartbeatTimer = setTimeout(() => {
|
||||||
this.isActive().then((active) => {
|
this.isActive()
|
||||||
if (active) {
|
.then((active) => {
|
||||||
this.beat()
|
if (active) {
|
||||||
}
|
this.beat()
|
||||||
})
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
logger.warn(error.message)
|
||||||
|
})
|
||||||
}, this.heartbeatInterval)
|
}, this.heartbeatInterval)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue