mirror of https://github.com/coder/code-server.git
Move VS Code to the root
This commit is contained in:
parent
c146457de4
commit
069c5230cd
|
@ -353,7 +353,7 @@ class Builder {
|
||||||
hmr: false,
|
hmr: false,
|
||||||
logLevel: 1,
|
logLevel: 1,
|
||||||
outDir: path.join(this.rootPath, out),
|
outDir: path.join(this.rootPath, out),
|
||||||
publicUrl: `/static-${commit || "development"}/dist`,
|
publicUrl: `/static/${commit || "development"}/dist`,
|
||||||
target: "browser",
|
target: "browser",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
@ -2968,7 +2968,7 @@ index bbb72e9511..0785d3391d 100644
|
||||||
-registerSingleton(IExtensionStoragePaths, class extends NotImplementedProxy(IExtensionStoragePaths) { whenReady = Promise.resolve(); });
|
-registerSingleton(IExtensionStoragePaths, class extends NotImplementedProxy(IExtensionStoragePaths) { whenReady = Promise.resolve(); });
|
||||||
+registerSingleton(IExtensionStoragePaths, ExtensionStoragePaths);
|
+registerSingleton(IExtensionStoragePaths, ExtensionStoragePaths);
|
||||||
diff --git a/src/vs/workbench/services/extensions/worker/extensionHostWorkerMain.ts b/src/vs/workbench/services/extensions/worker/extensionHostWorkerMain.ts
|
diff --git a/src/vs/workbench/services/extensions/worker/extensionHostWorkerMain.ts b/src/vs/workbench/services/extensions/worker/extensionHostWorkerMain.ts
|
||||||
index 79455414c0..5ba66b2d83 100644
|
index 79455414c0..a407593b4d 100644
|
||||||
--- a/src/vs/workbench/services/extensions/worker/extensionHostWorkerMain.ts
|
--- a/src/vs/workbench/services/extensions/worker/extensionHostWorkerMain.ts
|
||||||
+++ b/src/vs/workbench/services/extensions/worker/extensionHostWorkerMain.ts
|
+++ b/src/vs/workbench/services/extensions/worker/extensionHostWorkerMain.ts
|
||||||
@@ -14,7 +14,11 @@
|
@@ -14,7 +14,11 @@
|
||||||
|
@ -2978,8 +2978,8 @@ index 79455414c0..5ba66b2d83 100644
|
||||||
- catchError: true
|
- catchError: true
|
||||||
+ catchError: true,
|
+ catchError: true,
|
||||||
+ paths: {
|
+ paths: {
|
||||||
+ '@coder/node-browser': `../../static-{{COMMIT}}/node_modules/@coder/node-browser/out/client/client.js`,
|
+ '@coder/node-browser': `../node_modules/@coder/node-browser/out/client/client.js`,
|
||||||
+ '@coder/requirefs': `../../static-{{COMMIT}}/node_modules/@coder/requirefs/out/requirefs.js`,
|
+ '@coder/requirefs': `../node_modules/@coder/requirefs/out/requirefs.js`,
|
||||||
+ }
|
+ }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -7,32 +7,32 @@
|
||||||
"description": "Run editors on a remote server.",
|
"description": "Run editors on a remote server.",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "{{BASE}}/static-{{COMMIT}}/src/browser/media/pwa-icon-96.png",
|
"src": "{{BASE}}/static/{{COMMIT}}/src/browser/media/pwa-icon-96.png",
|
||||||
"type": "image/png",
|
"type": "image/png",
|
||||||
"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"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "{{BASE}}/static-{{COMMIT}}/src/browser/media/pwa-icon-192.png",
|
"src": "{{BASE}}/static/{{COMMIT}}/src/browser/media/pwa-icon-192.png",
|
||||||
"type": "image/png",
|
"type": "image/png",
|
||||||
"sizes": "192x192"
|
"sizes": "192x192"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "{{BASE}}/static-{{COMMIT}}/src/browser/media/pwa-icon-256.png",
|
"src": "{{BASE}}/static/{{COMMIT}}/src/browser/media/pwa-icon-256.png",
|
||||||
"type": "image/png",
|
"type": "image/png",
|
||||||
"sizes": "256x256"
|
"sizes": "256x256"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "{{BASE}}/static-{{COMMIT}}/src/browser/media/pwa-icon-384.png",
|
"src": "{{BASE}}/static/{{COMMIT}}/src/browser/media/pwa-icon-384.png",
|
||||||
"type": "image/png",
|
"type": "image/png",
|
||||||
"sizes": "384x384"
|
"sizes": "384x384"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "{{BASE}}/static-{{COMMIT}}/src/browser/media/pwa-icon-512.png",
|
"src": "{{BASE}}/static/{{COMMIT}}/src/browser/media/pwa-icon-512.png",
|
||||||
"type": "image/png",
|
"type": "image/png",
|
||||||
"sizes": "512x512"
|
"sizes": "512x512"
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,18 +8,18 @@
|
||||||
/>
|
/>
|
||||||
<meta http-equiv="Content-Security-Policy" content="style-src 'self'; manifest-src 'self'; img-src 'self' data:;" />
|
<meta http-equiv="Content-Security-Policy" content="style-src 'self'; manifest-src 'self'; img-src 'self' data:;" />
|
||||||
<title>code-server — {{APP_NAME}}</title>
|
<title>code-server — {{APP_NAME}}</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" />
|
||||||
<link
|
<link
|
||||||
rel="manifest"
|
rel="manifest"
|
||||||
href="{{BASE}}/static-{{COMMIT}}/src/browser/media/manifest.json"
|
href="{{BASE}}/static/{{COMMIT}}/src/browser/media/manifest.json"
|
||||||
crossorigin="use-credentials"
|
crossorigin="use-credentials"
|
||||||
/>
|
/>
|
||||||
<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}}" />
|
<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/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,14 +8,14 @@
|
||||||
/>
|
/>
|
||||||
<meta http-equiv="Content-Security-Policy" content="style-src 'self'; manifest-src 'self'; img-src 'self' data:;" />
|
<meta http-equiv="Content-Security-Policy" content="style-src 'self'; manifest-src 'self'; img-src 'self' data:;" />
|
||||||
<title>{{ERROR_TITLE}} - code-server</title>
|
<title>{{ERROR_TITLE}} - code-server</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" />
|
||||||
<link
|
<link
|
||||||
rel="manifest"
|
rel="manifest"
|
||||||
href="{{BASE}}/static-{{COMMIT}}/src/browser/media/manifest.json"
|
href="{{BASE}}/static/{{COMMIT}}/src/browser/media/manifest.json"
|
||||||
crossorigin="use-credentials"
|
crossorigin="use-credentials"
|
||||||
/>
|
/>
|
||||||
<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}}" />
|
<meta id="coder-options" data-settings="{{OPTIONS}}" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -30,6 +30,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="{{BASE}}/static-{{COMMIT}}/dist/register.js"></script>
|
<script src="{{BASE}}/static/{{COMMIT}}/dist/register.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -8,14 +8,14 @@
|
||||||
/>
|
/>
|
||||||
<meta http-equiv="Content-Security-Policy" content="style-src 'self'; manifest-src 'self'; img-src 'self' data:;" />
|
<meta http-equiv="Content-Security-Policy" content="style-src 'self'; manifest-src 'self'; img-src 'self' data:;" />
|
||||||
<title>code-server</title>
|
<title>code-server</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" />
|
||||||
<link
|
<link
|
||||||
rel="manifest"
|
rel="manifest"
|
||||||
href="{{BASE}}/static-{{COMMIT}}/src/browser/media/manifest.json"
|
href="{{BASE}}/static/{{COMMIT}}/src/browser/media/manifest.json"
|
||||||
crossorigin="use-credentials"
|
crossorigin="use-credentials"
|
||||||
/>
|
/>
|
||||||
<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}}" />
|
<meta id="coder-options" data-settings="{{OPTIONS}}" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -70,6 +70,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="{{BASE}}/static-{{COMMIT}}/dist/register.js"></script>
|
<script src="{{BASE}}/static/{{COMMIT}}/dist/register.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -11,14 +11,14 @@
|
||||||
content="style-src 'self'; script-src 'self' '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" />
|
||||||
<link
|
<link
|
||||||
rel="manifest"
|
rel="manifest"
|
||||||
href="{{BASE}}/static-{{COMMIT}}/src/browser/media/manifest.json"
|
href="{{BASE}}/static/{{COMMIT}}/src/browser/media/manifest.json"
|
||||||
crossorigin="use-credentials"
|
crossorigin="use-credentials"
|
||||||
/>
|
/>
|
||||||
<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}}" />
|
<meta id="coder-options" data-settings="{{OPTIONS}}" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -50,7 +50,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
<script src="{{BASE}}/static-{{COMMIT}}/dist/register.js"></script>
|
<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}}"
|
||||||
|
|
|
@ -8,14 +8,14 @@
|
||||||
/>
|
/>
|
||||||
<meta http-equiv="Content-Security-Policy" content="style-src 'self'; manifest-src 'self'; img-src 'self' data:;" />
|
<meta http-equiv="Content-Security-Policy" content="style-src 'self'; manifest-src 'self'; img-src 'self' data:;" />
|
||||||
<title>code-server</title>
|
<title>code-server</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" />
|
||||||
<link
|
<link
|
||||||
rel="manifest"
|
rel="manifest"
|
||||||
href="{{BASE}}/static-{{COMMIT}}/src/browser/media/manifest.json"
|
href="{{BASE}}/static/{{COMMIT}}/src/browser/media/manifest.json"
|
||||||
crossorigin="use-credentials"
|
crossorigin="use-credentials"
|
||||||
/>
|
/>
|
||||||
<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}}" />
|
<meta id="coder-options" data-settings="{{OPTIONS}}" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -33,6 +33,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="{{BASE}}/static-{{COMMIT}}/dist/register.js"></script>
|
<script src="{{BASE}}/static/{{COMMIT}}/dist/register.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -25,21 +25,21 @@
|
||||||
<meta id="vscode-remote-nls-configuration" data-settings="{{NLS_CONFIGURATION}}" />
|
<meta id="vscode-remote-nls-configuration" data-settings="{{NLS_CONFIGURATION}}" />
|
||||||
|
|
||||||
<!-- Workbench Icon/Manifest/CSS -->
|
<!-- Workbench Icon/Manifest/CSS -->
|
||||||
<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" />
|
||||||
<link
|
<link
|
||||||
rel="manifest"
|
rel="manifest"
|
||||||
href="{{BASE}}/static-{{COMMIT}}/src/browser/media/manifest.json"
|
href="{{BASE}}/static/{{COMMIT}}/src/browser/media/manifest.json"
|
||||||
crossorigin="use-credentials"
|
crossorigin="use-credentials"
|
||||||
/>
|
/>
|
||||||
<!-- PROD_ONLY
|
<!-- PROD_ONLY
|
||||||
<link data-name="vs/workbench/workbench.web.api" rel="stylesheet" href="{{VS_BASE}}/static-{{COMMIT}}/out/vs/workbench/workbench.web.api.css">
|
<link data-name="vs/workbench/workbench.web.api" rel="stylesheet" href="{{BASE}}/static/{{COMMIT}}/lib/vscode/out/vs/workbench/workbench.web.api.css">
|
||||||
END_PROD_ONLY -->
|
END_PROD_ONLY -->
|
||||||
<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" />
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||||
|
|
||||||
<!-- Prefetch to avoid waterfall -->
|
<!-- Prefetch to avoid waterfall -->
|
||||||
<!-- PROD_ONLY
|
<!-- PROD_ONLY
|
||||||
<link rel="prefetch" href="{{VS_BASE}}/static-{{COMMIT}}/node_modules/semver-umd/lib/semver-umd.js">
|
<link rel="prefetch" href="{{BASE}}/static/{{COMMIT}}/lib/vscode/node_modules/semver-umd/lib/semver-umd.js">
|
||||||
END_PROD_ONLY -->
|
END_PROD_ONLY -->
|
||||||
|
|
||||||
<meta id="coder-options" data-settings="{{OPTIONS}}" />
|
<meta id="coder-options" data-settings="{{OPTIONS}}" />
|
||||||
|
@ -50,11 +50,11 @@
|
||||||
<!-- Startup (do not modify order of script tags!) -->
|
<!-- Startup (do not modify order of script tags!) -->
|
||||||
<script>
|
<script>
|
||||||
const parts = window.location.pathname.replace(/^\//g, "").split("/")
|
const parts = window.location.pathname.replace(/^\//g, "").split("/")
|
||||||
parts[parts.length - 1] = "{{VS_BASE}}"
|
parts[parts.length - 1] = "{{BASE}}"
|
||||||
const url = new URL(window.location.origin + "/" + parts.join("/"))
|
const url = new URL(window.location.origin + "/" + parts.join("/"))
|
||||||
const el = document.getElementById("vscode-remote-commit")
|
const el = document.getElementById("vscode-remote-commit")
|
||||||
const commit = el ? el.getAttribute("data-settings") : ""
|
const commit = el ? el.getAttribute("data-settings") : ""
|
||||||
const staticBase = url.href + "/static-" + commit
|
const staticBase = url.href + "/static/" + commit + "/lib/vscode"
|
||||||
let nlsConfig
|
let nlsConfig
|
||||||
try {
|
try {
|
||||||
nlsConfig = JSON.parse(document.getElementById("vscode-remote-nls-configuration").getAttribute("data-settings"))
|
nlsConfig = JSON.parse(document.getElementById("vscode-remote-nls-configuration").getAttribute("data-settings"))
|
||||||
|
@ -93,11 +93,11 @@
|
||||||
"vs/nls": nlsConfig,
|
"vs/nls": nlsConfig,
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script src="{{BASE}}/static-{{COMMIT}}/dist/register.js"></script>
|
<script src="{{BASE}}/static/{{COMMIT}}/dist/register.js"></script>
|
||||||
<script src="{{VS_BASE}}/static-{{COMMIT}}/out/vs/loader.js"></script>
|
<script src="{{BASE}}/static/{{COMMIT}}/lib/vscode/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="{{BASE}}/static/{{COMMIT}}/lib/vscode/out/vs/workbench/workbench.web.api.nls.js"></script>
|
||||||
<script src="{{VS_BASE}}/static-{{COMMIT}}/out/vs/workbench/workbench.web.api.js"></script>
|
<script src="{{BASE}}/static/{{COMMIT}}/lib/vscode/out/vs/workbench/workbench.web.api.js"></script>
|
||||||
END_PROD_ONLY -->
|
END_PROD_ONLY -->
|
||||||
<script>
|
<script>
|
||||||
require(["vs/code/browser/workbench/workbench"], function() {})
|
require(["vs/code/browser/workbench/workbench"], function() {})
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { getOptions, normalize } from "../common/util"
|
||||||
const options = getOptions()
|
const options = getOptions()
|
||||||
|
|
||||||
if ("serviceWorker" in navigator) {
|
if ("serviceWorker" in navigator) {
|
||||||
const path = normalize(`${options.base}/static-${options.commit}/dist/serviceWorker.js`)
|
const path = normalize(`${options.base}/static/${options.commit}/dist/serviceWorker.js`)
|
||||||
navigator.serviceWorker
|
navigator.serviceWorker
|
||||||
.register(path, {
|
.register(path, {
|
||||||
scope: options.base || "/",
|
scope: options.base || "/",
|
||||||
|
|
|
@ -16,7 +16,7 @@ import {
|
||||||
SessionError,
|
SessionError,
|
||||||
SessionResponse,
|
SessionResponse,
|
||||||
} from "../../common/api"
|
} from "../../common/api"
|
||||||
import { ApiEndpoint, HttpCode } from "../../common/http"
|
import { ApiEndpoint, HttpCode, HttpError } from "../../common/http"
|
||||||
import { normalize } from "../../common/util"
|
import { normalize } from "../../common/util"
|
||||||
import { HttpProvider, HttpProviderOptions, HttpResponse, HttpServer, Route } from "../http"
|
import { HttpProvider, HttpProviderOptions, HttpResponse, HttpServer, Route } from "../http"
|
||||||
import { findApplications, findWhitelistedApplications, Vscode } from "./bin"
|
import { findApplications, findWhitelistedApplications, Vscode } from "./bin"
|
||||||
|
@ -57,10 +57,9 @@ export class ApiHttpProvider extends HttpProvider {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public async handleRequest(route: Route, request: http.IncomingMessage): Promise<HttpResponse | undefined> {
|
public async handleRequest(route: Route, request: http.IncomingMessage): Promise<HttpResponse> {
|
||||||
if (!this.authenticated(request)) {
|
this.ensureAuthenticated(request)
|
||||||
return { code: HttpCode.Unauthorized }
|
|
||||||
}
|
|
||||||
switch (route.base) {
|
switch (route.base) {
|
||||||
case ApiEndpoint.applications:
|
case ApiEndpoint.applications:
|
||||||
this.ensureMethod(request)
|
this.ensureMethod(request)
|
||||||
|
@ -82,7 +81,8 @@ export class ApiHttpProvider extends HttpProvider {
|
||||||
content: await this.running(),
|
content: await this.running(),
|
||||||
} as HttpResponse<RunningResponse>
|
} as HttpResponse<RunningResponse>
|
||||||
}
|
}
|
||||||
return undefined
|
|
||||||
|
throw new HttpError("Not found", HttpCode.NotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
public async handleWebSocket(
|
public async handleWebSocket(
|
||||||
|
@ -90,7 +90,7 @@ export class ApiHttpProvider extends HttpProvider {
|
||||||
request: http.IncomingMessage,
|
request: http.IncomingMessage,
|
||||||
socket: net.Socket,
|
socket: net.Socket,
|
||||||
head: Buffer,
|
head: Buffer,
|
||||||
): Promise<true | undefined> {
|
): Promise<true> {
|
||||||
if (!this.authenticated(request)) {
|
if (!this.authenticated(request)) {
|
||||||
throw new Error("not authenticated")
|
throw new Error("not authenticated")
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,8 @@ export class ApiHttpProvider extends HttpProvider {
|
||||||
case ApiEndpoint.run:
|
case ApiEndpoint.run:
|
||||||
return this.handleRunSocket(route, request, socket, head)
|
return this.handleRunSocket(route, request, socket, head)
|
||||||
}
|
}
|
||||||
return undefined
|
|
||||||
|
throw new HttpError("Not found", HttpCode.NotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleStatusSocket(request: http.IncomingMessage, socket: net.Socket, head: Buffer): Promise<true> {
|
private async handleStatusSocket(request: http.IncomingMessage, socket: net.Socket, head: Buffer): Promise<true> {
|
||||||
|
@ -220,12 +221,12 @@ export class ApiHttpProvider extends HttpProvider {
|
||||||
/**
|
/**
|
||||||
* Handle /session endpoint.
|
* Handle /session endpoint.
|
||||||
*/
|
*/
|
||||||
private async session(request: http.IncomingMessage): Promise<HttpResponse | undefined> {
|
private async session(request: http.IncomingMessage): Promise<HttpResponse> {
|
||||||
this.ensureMethod(request, ["DELETE", "POST"])
|
this.ensureMethod(request, ["DELETE", "POST"])
|
||||||
|
|
||||||
const data = await this.getData(request)
|
const data = await this.getData(request)
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return undefined
|
throw new HttpError("Not found", HttpCode.NotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (request.method) {
|
switch (request.method) {
|
||||||
|
@ -252,7 +253,7 @@ export class ApiHttpProvider extends HttpProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined
|
throw new HttpError("Not found", HttpCode.NotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,51 +1,19 @@
|
||||||
import * as http from "http"
|
import * as http from "http"
|
||||||
import * as querystring from "querystring"
|
|
||||||
import { Application, RecentResponse } from "../../common/api"
|
|
||||||
import { HttpCode, HttpError } from "../../common/http"
|
import { HttpCode, HttpError } from "../../common/http"
|
||||||
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"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Top-level and fallback HTTP provider.
|
* App/fallback HTTP provider.
|
||||||
*/
|
*/
|
||||||
export class MainHttpProvider extends HttpProvider {
|
export class AppHttpProvider extends HttpProvider {
|
||||||
public constructor(
|
public constructor(options: HttpProviderOptions, private readonly api: ApiHttpProvider) {
|
||||||
options: HttpProviderOptions,
|
|
||||||
private readonly api: ApiHttpProvider,
|
|
||||||
private readonly update: UpdateHttpProvider,
|
|
||||||
) {
|
|
||||||
super(options)
|
super(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
public async handleRequest(route: Route, request: http.IncomingMessage): Promise<HttpResponse | undefined> {
|
public async handleRequest(route: Route, request: http.IncomingMessage): Promise<HttpResponse> {
|
||||||
switch (route.base) {
|
if (!this.authenticated(request)) {
|
||||||
case "/static": {
|
return { redirect: "/login", query: { to: route.fullPath } }
|
||||||
this.ensureMethod(request)
|
|
||||||
const response = await this.getReplacedResource(route)
|
|
||||||
if (!this.isDev) {
|
|
||||||
response.cache = true
|
|
||||||
}
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
|
|
||||||
case "/delete": {
|
|
||||||
this.ensureMethod(request, "POST")
|
|
||||||
const data = await this.getData(request)
|
|
||||||
const p = data ? querystring.parse(data) : {}
|
|
||||||
this.api.deleteSession(p.sessionId as string)
|
|
||||||
return { redirect: "/" }
|
|
||||||
}
|
|
||||||
|
|
||||||
case "/": {
|
|
||||||
this.ensureMethod(request)
|
|
||||||
if (route.requestPath !== "/index.html") {
|
|
||||||
throw new HttpError("Not found", HttpCode.NotFound)
|
|
||||||
} else if (!this.authenticated(request)) {
|
|
||||||
return { redirect: "/login" }
|
|
||||||
}
|
|
||||||
return this.getRoot(route)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run an existing app, but if it doesn't exist go ahead and start it.
|
// Run an existing app, but if it doesn't exist go ahead and start it.
|
||||||
|
@ -53,7 +21,7 @@ export class MainHttpProvider extends HttpProvider {
|
||||||
let sessionId = app && app.sessionId
|
let sessionId = app && app.sessionId
|
||||||
if (!app) {
|
if (!app) {
|
||||||
app = (await this.api.installedApplications()).find((a) => a.path === route.base)
|
app = (await this.api.installedApplications()).find((a) => a.path === route.base)
|
||||||
if (app) {
|
if (app && app.exec) {
|
||||||
sessionId = await this.api.createSession(app)
|
sessionId = await this.api.createSession(app)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,40 +30,7 @@ export class MainHttpProvider extends HttpProvider {
|
||||||
return this.getAppRoot(route, (app && app.name) || "", sessionId)
|
return this.getAppRoot(route, (app && app.name) || "", sessionId)
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.getErrorRoot(route, "404", "404", "Application not found")
|
throw new HttpError("Application not found", HttpCode.NotFound)
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a resource with variables replaced where necessary.
|
|
||||||
*/
|
|
||||||
protected async getReplacedResource(route: Route): Promise<HttpResponse> {
|
|
||||||
const split = route.requestPath.split("/")
|
|
||||||
switch (split[split.length - 1]) {
|
|
||||||
case "manifest.json": {
|
|
||||||
const response = await this.getUtf8Resource(this.rootPath, route.requestPath)
|
|
||||||
return this.replaceTemplates(route, response)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this.getResource(this.rootPath, route.requestPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getRoot(route: Route): Promise<HttpResponse> {
|
|
||||||
const running = await this.api.running()
|
|
||||||
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())
|
|
||||||
.replace(/{{APP_LIST:RUNNING}}/, this.getAppRows(running.applications))
|
|
||||||
.replace(/{{APP_LIST:RECENT_PROJECTS}}/, this.getRecentProjectRows(await this.api.recent()))
|
|
||||||
.replace(
|
|
||||||
/{{APP_LIST:EDITORS}}/,
|
|
||||||
this.getAppRows(apps.filter((app) => app.categories && app.categories.includes("Editor"))),
|
|
||||||
)
|
|
||||||
.replace(
|
|
||||||
/{{APP_LIST:OTHER}}/,
|
|
||||||
this.getAppRows(apps.filter((app) => !app.categories || !app.categories.includes("Editor"))),
|
|
||||||
)
|
|
||||||
return this.replaceTemplates(route, response)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getAppRoot(route: Route, name: string, sessionId: string): Promise<HttpResponse> {
|
public async getAppRoot(route: Route, name: string, sessionId: string): Promise<HttpResponse> {
|
||||||
|
@ -104,91 +39,7 @@ export class MainHttpProvider extends HttpProvider {
|
||||||
return this.replaceTemplates(route, response, sessionId)
|
return this.replaceTemplates(route, response, sessionId)
|
||||||
}
|
}
|
||||||
|
|
||||||
public async handleWebSocket(): Promise<undefined> {
|
public async handleWebSocket(): Promise<true> {
|
||||||
return undefined
|
throw new HttpError("Not found", HttpCode.NotFound)
|
||||||
}
|
|
||||||
|
|
||||||
private getRecentProjectRows(recents: RecentResponse): string {
|
|
||||||
return recents.paths.length > 0 || recents.workspaces.length > 0
|
|
||||||
? recents.paths.map((recent) => this.getRecentProjectRow(recent)).join("\n") +
|
|
||||||
recents.workspaces.map((recent) => this.getRecentProjectRow(recent, true)).join("\n")
|
|
||||||
: `<div class="none">No recent directories or workspaces.</div>`
|
|
||||||
}
|
|
||||||
|
|
||||||
private getRecentProjectRow(recent: string, workspace?: boolean): string {
|
|
||||||
return `<div class="block-row">
|
|
||||||
<a class="item -row -link" href="./vscode/?${workspace ? "workspace" : "folder"}=${recent}">
|
|
||||||
<div class="name">${recent}${workspace ? " (workspace)" : ""}</div>
|
|
||||||
</a>
|
|
||||||
</div>`
|
|
||||||
}
|
|
||||||
|
|
||||||
private getAppRows(apps: ReadonlyArray<Application>): string {
|
|
||||||
return apps.length > 0
|
|
||||||
? apps.map((app) => this.getAppRow(app)).join("\n")
|
|
||||||
: `<div class="none">No applications are currently running.</div>`
|
|
||||||
}
|
|
||||||
|
|
||||||
private getAppRow(app: Application): string {
|
|
||||||
return `<div class="block-row">
|
|
||||||
<a class="item -row -link" href=".${app.path}">
|
|
||||||
${
|
|
||||||
app.icon
|
|
||||||
? `<img class="icon" src="data:image/png;base64,${app.icon}"></img>`
|
|
||||||
: `<div class="icon -missing"></div>`
|
|
||||||
}
|
|
||||||
<div class="name">${app.name}</div>
|
|
||||||
</a>
|
|
||||||
${
|
|
||||||
app.sessionId
|
|
||||||
? `<form class="kill-form" action="./delete" method="POST">
|
|
||||||
<input type="hidden" name="sessionId" value="${app.sessionId}">
|
|
||||||
<button class="kill -button" type="submit">Kill</button>
|
|
||||||
</form>`
|
|
||||||
: ""
|
|
||||||
}
|
|
||||||
</div>`
|
|
||||||
}
|
|
||||||
|
|
||||||
private async getUpdate(): Promise<string> {
|
|
||||||
if (!this.update.enabled) {
|
|
||||||
return `<div class="block-row"><div class="item"><div class="sub">Updates are disabled</div></div></div>`
|
|
||||||
}
|
|
||||||
|
|
||||||
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 `<div class="block-row">
|
|
||||||
<div class="item">
|
|
||||||
Latest: ${update.version}
|
|
||||||
<div class="sub">Up to date</div>
|
|
||||||
</div>
|
|
||||||
<div class="item">
|
|
||||||
${humanize(update.checked)}
|
|
||||||
<a class="sub -link" href="./update/check">Check now</a>
|
|
||||||
</div>
|
|
||||||
<div class="item" >Current: ${this.update.currentVersion}</div>
|
|
||||||
</div>`
|
|
||||||
}
|
|
||||||
|
|
||||||
return `<div class="block-row">
|
|
||||||
<div class="item">
|
|
||||||
Latest: ${update.version}
|
|
||||||
<div class="sub">Out of date</div>
|
|
||||||
</div>
|
|
||||||
<div class="item">
|
|
||||||
${humanize(update.checked)}
|
|
||||||
<a class="sub -link" href="./update">Update now</a>
|
|
||||||
</div>
|
|
||||||
<div class="item" >Current: ${this.update.currentVersion}</div>
|
|
||||||
</div>`
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ export const Vscode: Application = {
|
||||||
icon: fs.readFileSync(path.resolve(__dirname, "../../../lib/vscode/resources/linux/code.png")).toString("base64"),
|
icon: fs.readFileSync(path.resolve(__dirname, "../../../lib/vscode/resources/linux/code.png")).toString("base64"),
|
||||||
installed: true,
|
installed: true,
|
||||||
name: "VS Code",
|
name: "VS Code",
|
||||||
path: "/vscode",
|
path: "/",
|
||||||
version: getVscodeVersion(),
|
version: getVscodeVersion(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,159 @@
|
||||||
|
import * as http from "http"
|
||||||
|
import * as querystring from "querystring"
|
||||||
|
import { Application, RecentResponse } from "../../common/api"
|
||||||
|
import { HttpCode, HttpError } from "../../common/http"
|
||||||
|
import { HttpProvider, HttpProviderOptions, HttpResponse, Route } from "../http"
|
||||||
|
import { ApiHttpProvider } from "./api"
|
||||||
|
import { Vscode } from "./bin"
|
||||||
|
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<HttpResponse> {
|
||||||
|
switch (route.base) {
|
||||||
|
case "/delete": {
|
||||||
|
this.ensureMethod(request, "POST")
|
||||||
|
this.ensureAuthenticated(request)
|
||||||
|
const data = await this.getData(request)
|
||||||
|
const p = data ? querystring.parse(data) : {}
|
||||||
|
this.api.deleteSession(p.sessionId as string)
|
||||||
|
return { redirect: this.options.base }
|
||||||
|
}
|
||||||
|
|
||||||
|
case "/": {
|
||||||
|
this.ensureMethod(request)
|
||||||
|
if (route.requestPath !== "/index.html") {
|
||||||
|
throw new HttpError("Not found", HttpCode.NotFound)
|
||||||
|
} else if (!this.authenticated(request)) {
|
||||||
|
return { redirect: "/login", query: { to: this.options.base } }
|
||||||
|
}
|
||||||
|
return this.getRoot(route)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new HttpError("Not found", HttpCode.NotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getRoot(route: Route): Promise<HttpResponse> {
|
||||||
|
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:RUNNING}}/, this.getAppRows(base, (await this.api.running()).applications))
|
||||||
|
.replace(/{{APP_LIST:RECENT_PROJECTS}}/, this.getRecentProjectRows(base, await this.api.recent()))
|
||||||
|
.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 handleWebSocket(): Promise<true> {
|
||||||
|
throw new HttpError("Not found", HttpCode.NotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
private getRecentProjectRows(base: string, recents: RecentResponse): string {
|
||||||
|
return recents.paths.length > 0 || recents.workspaces.length > 0
|
||||||
|
? recents.paths.map((recent) => this.getRecentProjectRow(base, recent)).join("\n") +
|
||||||
|
recents.workspaces.map((recent) => this.getRecentProjectRow(base, recent, true)).join("\n")
|
||||||
|
: `<div class="none">No recent directories or workspaces.</div>`
|
||||||
|
}
|
||||||
|
|
||||||
|
private getRecentProjectRow(base: string, recent: string, workspace?: boolean): string {
|
||||||
|
return `<div class="block-row">
|
||||||
|
<a class="item -row -link" href="${base}${Vscode.path}?${workspace ? "workspace" : "folder"}=${recent}">
|
||||||
|
<div class="name">${recent}${workspace ? " (workspace)" : ""}</div>
|
||||||
|
</a>
|
||||||
|
</div>`
|
||||||
|
}
|
||||||
|
|
||||||
|
private getAppRows(base: string, apps: ReadonlyArray<Application>): string {
|
||||||
|
return apps.length > 0
|
||||||
|
? apps.map((app) => this.getAppRow(base, app)).join("\n")
|
||||||
|
: `<div class="none">No applications are currently running.</div>`
|
||||||
|
}
|
||||||
|
|
||||||
|
private getAppRow(base: string, app: Application): string {
|
||||||
|
return `<div class="block-row">
|
||||||
|
<a class="item -row -link" href="${base}${app.path}">
|
||||||
|
${
|
||||||
|
app.icon
|
||||||
|
? `<img class="icon" src="data:image/png;base64,${app.icon}"></img>`
|
||||||
|
: `<div class="icon -missing"></div>`
|
||||||
|
}
|
||||||
|
<div class="name">${app.name}</div>
|
||||||
|
</a>
|
||||||
|
${
|
||||||
|
app.sessionId
|
||||||
|
? `<form class="kill-form" action="${base}${this.options.base}/delete" method="POST">
|
||||||
|
<input type="hidden" name="sessionId" value="${app.sessionId}">
|
||||||
|
<button class="kill -button" type="submit">Kill</button>
|
||||||
|
</form>`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
</div>`
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getUpdate(base: string): Promise<string> {
|
||||||
|
if (!this.update.enabled) {
|
||||||
|
return `<div class="block-row"><div class="item"><div class="sub">Updates are disabled</div></div></div>`
|
||||||
|
}
|
||||||
|
|
||||||
|
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 `<div class="block-row">
|
||||||
|
<div class="item">
|
||||||
|
Latest: ${update.version}
|
||||||
|
<div class="sub">Up to date</div>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
${humanize(update.checked)}
|
||||||
|
<a class="sub -link" href="${base}/update/check?to=${this.options.base}">Check now</a>
|
||||||
|
</div>
|
||||||
|
<div class="item" >Current: ${this.update.currentVersion}</div>
|
||||||
|
</div>`
|
||||||
|
}
|
||||||
|
|
||||||
|
return `<div class="block-row">
|
||||||
|
<div class="item">
|
||||||
|
Latest: ${update.version}
|
||||||
|
<div class="sub">Out of date</div>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
${humanize(update.checked)}
|
||||||
|
<a class="sub -link" href="${base}/update">Update now</a>
|
||||||
|
</div>
|
||||||
|
<div class="item" >Current: ${this.update.currentVersion}</div>
|
||||||
|
</div>`
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,7 +17,7 @@ interface LoginPayload {
|
||||||
* Login HTTP provider.
|
* Login HTTP provider.
|
||||||
*/
|
*/
|
||||||
export class LoginHttpProvider extends HttpProvider {
|
export class LoginHttpProvider extends HttpProvider {
|
||||||
public async handleRequest(route: Route, request: http.IncomingMessage): Promise<HttpResponse | undefined> {
|
public async handleRequest(route: Route, request: http.IncomingMessage): Promise<HttpResponse> {
|
||||||
if (this.options.auth !== AuthType.Password) {
|
if (this.options.auth !== AuthType.Password) {
|
||||||
throw new HttpError("Not found", HttpCode.NotFound)
|
throw new HttpError("Not found", HttpCode.NotFound)
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ export class LoginHttpProvider extends HttpProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined
|
throw new HttpError("Not found", HttpCode.NotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getRoot(route: Route, error?: Error): Promise<HttpResponse> {
|
public async getRoot(route: Route, error?: Error): Promise<HttpResponse> {
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
import * as http from "http"
|
||||||
|
import { HttpCode, HttpError } from "../../common/http"
|
||||||
|
import { HttpProvider, HttpResponse, Route } from "../http"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static file HTTP provider. Static requests do not require authentication and
|
||||||
|
* they only allow access to resources within the application.
|
||||||
|
*/
|
||||||
|
export class StaticHttpProvider extends HttpProvider {
|
||||||
|
public async handleRequest(route: Route, request: http.IncomingMessage): Promise<HttpResponse> {
|
||||||
|
this.ensureMethod(request)
|
||||||
|
const response = await this.getReplacedResource(route)
|
||||||
|
if (!this.isDev) {
|
||||||
|
response.cache = true
|
||||||
|
}
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a resource with variables replaced where necessary.
|
||||||
|
*/
|
||||||
|
protected async getReplacedResource(route: Route): Promise<HttpResponse> {
|
||||||
|
// The first part is always the commit (for caching purposes).
|
||||||
|
const split = route.requestPath.split("/").slice(1)
|
||||||
|
|
||||||
|
switch (split[split.length - 1]) {
|
||||||
|
case "manifest.json":
|
||||||
|
case "extensionHostWorkerMain.js": {
|
||||||
|
const response = await this.getUtf8Resource(this.rootPath, ...split)
|
||||||
|
return this.replaceTemplates(route, response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.getResource(this.rootPath, ...split)
|
||||||
|
}
|
||||||
|
|
||||||
|
public async handleWebSocket(): Promise<true> {
|
||||||
|
throw new HttpError("Not found", HttpCode.NotFound)
|
||||||
|
}
|
||||||
|
}
|
|
@ -57,18 +57,24 @@ export class UpdateHttpProvider extends HttpProvider {
|
||||||
super(options)
|
super(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
public async handleRequest(route: Route, request: http.IncomingMessage): Promise<HttpResponse | undefined> {
|
public async handleRequest(route: Route, request: http.IncomingMessage): Promise<HttpResponse> {
|
||||||
|
this.ensureAuthenticated(request)
|
||||||
|
|
||||||
switch (route.base) {
|
switch (route.base) {
|
||||||
case "/check":
|
case "/check":
|
||||||
this.ensureMethod(request)
|
this.ensureMethod(request)
|
||||||
this.getUpdate(true)
|
this.getUpdate(true)
|
||||||
return { redirect: "/login" }
|
if (route.query && route.query.to) {
|
||||||
|
return {
|
||||||
|
redirect: Array.isArray(route.query.to) ? route.query.to[0] : route.query.to,
|
||||||
|
query: { to: undefined },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.getRoot(route)
|
||||||
case "/": {
|
case "/": {
|
||||||
this.ensureMethod(request, ["GET", "POST"])
|
this.ensureMethod(request, ["GET", "POST"])
|
||||||
if (route.requestPath !== "/index.html") {
|
if (route.requestPath !== "/index.html") {
|
||||||
throw new HttpError("Not found", HttpCode.NotFound)
|
throw new HttpError("Not found", HttpCode.NotFound)
|
||||||
} else if (!this.authenticated(request)) {
|
|
||||||
return { redirect: "/login" }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (request.method) {
|
switch (request.method) {
|
||||||
|
@ -80,7 +86,7 @@ export class UpdateHttpProvider extends HttpProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined
|
throw new HttpError("Not found", HttpCode.NotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getRoot(route: Route, error?: Error): Promise<HttpResponse> {
|
public async getRoot(route: Route, error?: Error): Promise<HttpResponse> {
|
||||||
|
@ -91,8 +97,8 @@ export class UpdateHttpProvider extends HttpProvider {
|
||||||
return this.replaceTemplates(route, response)
|
return this.replaceTemplates(route, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
public async handleWebSocket(): Promise<undefined> {
|
public async handleWebSocket(): Promise<true> {
|
||||||
return undefined
|
throw new HttpError("Not found", HttpCode.NotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -166,13 +172,10 @@ export class UpdateHttpProvider extends HttpProvider {
|
||||||
public async tryUpdate(route: Route): Promise<HttpResponse> {
|
public async tryUpdate(route: Route): Promise<HttpResponse> {
|
||||||
try {
|
try {
|
||||||
const update = await this.getUpdate()
|
const update = await this.getUpdate()
|
||||||
if (this.isLatestVersion(update)) {
|
if (!this.isLatestVersion(update)) {
|
||||||
throw new Error("no update available")
|
|
||||||
}
|
|
||||||
await this.downloadUpdate(update)
|
await this.downloadUpdate(update)
|
||||||
return {
|
|
||||||
redirect: (Array.isArray(route.query.to) ? route.query.to[0] : route.query.to) || "/",
|
|
||||||
}
|
}
|
||||||
|
return this.getRoot(route)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return this.getRoot(route, error)
|
return this.getRoot(route, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,6 @@ export class VscodeHttpProvider extends HttpProvider {
|
||||||
private readonly serverRootPath: string
|
private readonly serverRootPath: string
|
||||||
private readonly vsRootPath: string
|
private readonly vsRootPath: string
|
||||||
private _vscode?: Promise<cp.ChildProcess>
|
private _vscode?: Promise<cp.ChildProcess>
|
||||||
private workbenchOptions?: WorkbenchOptions
|
|
||||||
|
|
||||||
public constructor(options: HttpProviderOptions, private readonly args: Args) {
|
public constructor(options: HttpProviderOptions, private readonly args: Args) {
|
||||||
super(options)
|
super(options)
|
||||||
|
@ -124,7 +123,7 @@ export class VscodeHttpProvider extends HttpProvider {
|
||||||
vscode.send(message, socket)
|
vscode.send(message, socket)
|
||||||
}
|
}
|
||||||
|
|
||||||
public async handleRequest(route: Route, request: http.IncomingMessage): Promise<HttpResponse | undefined> {
|
public async handleRequest(route: Route, request: http.IncomingMessage): Promise<HttpResponse> {
|
||||||
this.ensureMethod(request)
|
this.ensureMethod(request)
|
||||||
|
|
||||||
switch (route.base) {
|
switch (route.base) {
|
||||||
|
@ -150,22 +149,6 @@ export class VscodeHttpProvider extends HttpProvider {
|
||||||
this.ensureAuthenticated(request)
|
this.ensureAuthenticated(request)
|
||||||
|
|
||||||
switch (route.base) {
|
switch (route.base) {
|
||||||
case "/static": {
|
|
||||||
switch (route.requestPath) {
|
|
||||||
case "/out/vs/workbench/services/extensions/worker/extensionHostWorkerMain.js": {
|
|
||||||
const response = await this.getUtf8Resource(this.vsRootPath, route.requestPath)
|
|
||||||
response.content = response.content.replace(
|
|
||||||
/{{COMMIT}}/g,
|
|
||||||
this.workbenchOptions ? this.workbenchOptions.commit : "",
|
|
||||||
)
|
|
||||||
response.cache = true
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const response = await this.getResource(this.vsRootPath, route.requestPath)
|
|
||||||
response.cache = true
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
case "/resource":
|
case "/resource":
|
||||||
case "/vscode-remote-resource":
|
case "/vscode-remote-resource":
|
||||||
if (typeof route.query.path === "string") {
|
if (typeof route.query.path === "string") {
|
||||||
|
@ -183,7 +166,8 @@ export class VscodeHttpProvider extends HttpProvider {
|
||||||
}
|
}
|
||||||
return this.getResource(this.vsRootPath, "out/vs/workbench/contrib/webview/browser/pre", route.requestPath)
|
return this.getResource(this.vsRootPath, "out/vs/workbench/contrib/webview/browser/pre", route.requestPath)
|
||||||
}
|
}
|
||||||
return undefined
|
|
||||||
|
throw new HttpError("Not found", HttpCode.NotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getRoot(request: http.IncomingMessage, route: Route): Promise<HttpResponse> {
|
private async getRoot(request: http.IncomingMessage, route: Route): Promise<HttpResponse> {
|
||||||
|
@ -207,8 +191,6 @@ export class VscodeHttpProvider extends HttpProvider {
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
|
|
||||||
this.workbenchOptions = options
|
|
||||||
|
|
||||||
if (startPath) {
|
if (startPath) {
|
||||||
settings.write({
|
settings.write({
|
||||||
lastVisited: startPath,
|
lastVisited: startPath,
|
||||||
|
@ -220,7 +202,6 @@ export class VscodeHttpProvider extends HttpProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
response.content = response.content
|
response.content = response.content
|
||||||
.replace(/{{VS_BASE}}/g, this.base(route) + this.options.base)
|
|
||||||
.replace(`"{{REMOTE_USER_DATA_URI}}"`, `'${JSON.stringify(options.remoteUserDataUri)}'`)
|
.replace(`"{{REMOTE_USER_DATA_URI}}"`, `'${JSON.stringify(options.remoteUserDataUri)}'`)
|
||||||
.replace(`"{{PRODUCT_CONFIGURATION}}"`, `'${JSON.stringify(options.productConfiguration)}'`)
|
.replace(`"{{PRODUCT_CONFIGURATION}}"`, `'${JSON.stringify(options.productConfiguration)}'`)
|
||||||
.replace(`"{{WORKBENCH_WEB_CONFIGURATION}}"`, `'${JSON.stringify(options.workbenchWebConfiguration)}'`)
|
.replace(`"{{WORKBENCH_WEB_CONFIGURATION}}"`, `'${JSON.stringify(options.workbenchWebConfiguration)}'`)
|
||||||
|
|
|
@ -3,8 +3,10 @@ import * as cp from "child_process"
|
||||||
import * as path from "path"
|
import * as path from "path"
|
||||||
import { CliMessage } from "../../lib/vscode/src/vs/server/ipc"
|
import { CliMessage } from "../../lib/vscode/src/vs/server/ipc"
|
||||||
import { ApiHttpProvider } from "./app/api"
|
import { ApiHttpProvider } from "./app/api"
|
||||||
import { MainHttpProvider } from "./app/app"
|
import { AppHttpProvider } from "./app/app"
|
||||||
|
import { DashboardHttpProvider } from "./app/dashboard"
|
||||||
import { LoginHttpProvider } from "./app/login"
|
import { LoginHttpProvider } from "./app/login"
|
||||||
|
import { StaticHttpProvider } from "./app/static"
|
||||||
import { UpdateHttpProvider } from "./app/update"
|
import { UpdateHttpProvider } from "./app/update"
|
||||||
import { VscodeHttpProvider } from "./app/vscode"
|
import { VscodeHttpProvider } from "./app/vscode"
|
||||||
import { Args, optionDescriptions, parse } from "./cli"
|
import { Args, optionDescriptions, parse } from "./cli"
|
||||||
|
@ -44,11 +46,13 @@ const main = async (args: Args): Promise<void> => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const httpServer = new HttpServer(options)
|
const httpServer = new HttpServer(options)
|
||||||
const vscode = httpServer.registerHttpProvider("/vscode", VscodeHttpProvider, args)
|
const vscode = httpServer.registerHttpProvider("/", VscodeHttpProvider, args)
|
||||||
const api = httpServer.registerHttpProvider("/api", ApiHttpProvider, httpServer, vscode, args["user-data-dir"])
|
const api = httpServer.registerHttpProvider("/api", ApiHttpProvider, httpServer, vscode, args["user-data-dir"])
|
||||||
const update = httpServer.registerHttpProvider("/update", UpdateHttpProvider, !args["disable-updates"])
|
const update = httpServer.registerHttpProvider("/update", UpdateHttpProvider, !args["disable-updates"])
|
||||||
|
httpServer.registerHttpProvider("/app", AppHttpProvider, api)
|
||||||
httpServer.registerHttpProvider("/login", LoginHttpProvider)
|
httpServer.registerHttpProvider("/login", LoginHttpProvider)
|
||||||
httpServer.registerHttpProvider("/", MainHttpProvider, api, update)
|
httpServer.registerHttpProvider("/static", StaticHttpProvider)
|
||||||
|
httpServer.registerHttpProvider("/dashboard", DashboardHttpProvider, api, update)
|
||||||
|
|
||||||
ipcMain().onDispose(() => httpServer.dispose())
|
ipcMain().onDispose(() => httpServer.dispose())
|
||||||
|
|
||||||
|
|
|
@ -655,13 +655,6 @@ export class HttpServer {
|
||||||
base = "/"
|
base = "/"
|
||||||
}
|
}
|
||||||
requestPath = requestPath || "/index.html"
|
requestPath = requestPath || "/index.html"
|
||||||
// Allow for a versioned static endpoint. This lets us cache every static
|
|
||||||
// resource underneath the path based on the version without any work and
|
|
||||||
// without adding query parameters which have their own issues.
|
|
||||||
if (/^\/static-/.test(base)) {
|
|
||||||
base = "/static"
|
|
||||||
}
|
|
||||||
|
|
||||||
return { base, requestPath }
|
return { base, requestPath }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue