Archived
1
0

Integrate update notifications into VS Code

This commit is contained in:
Asher
2020-03-02 14:39:12 -06:00
parent 069c5230cd
commit ccd01c49b9
15 changed files with 161 additions and 75 deletions

View File

@ -59,6 +59,9 @@ export class ApiHttpProvider extends HttpProvider {
public async handleRequest(route: Route, request: http.IncomingMessage): Promise<HttpResponse> {
this.ensureAuthenticated(request)
if (route.requestPath !== "/index.html") {
throw new HttpError("Not found", HttpCode.NotFound)
}
switch (route.base) {
case ApiEndpoint.applications:

View File

@ -16,6 +16,11 @@ export class AppHttpProvider extends HttpProvider {
return { redirect: "/login", query: { to: route.fullPath } }
}
this.ensureMethod(request)
if (route.requestPath !== "/index.html") {
throw new HttpError("Not found", HttpCode.NotFound)
}
// Run an existing app, but if it doesn't exist go ahead and start it.
let app = this.api.getRunningApplication(route.base)
let sessionId = app && app.sessionId
@ -38,8 +43,4 @@ export class AppHttpProvider extends HttpProvider {
response.content = response.content.replace(/{{APP_NAME}}/, name)
return this.replaceTemplates(route, response, sessionId)
}
public async handleWebSocket(): Promise<true> {
throw new HttpError("Not found", HttpCode.NotFound)
}
}

View File

@ -20,10 +20,14 @@ export class DashboardHttpProvider extends HttpProvider {
}
public async handleRequest(route: Route, request: http.IncomingMessage): Promise<HttpResponse> {
if (route.requestPath !== "/index.html") {
throw new HttpError("Not found", HttpCode.NotFound)
}
switch (route.base) {
case "/delete": {
this.ensureMethod(request, "POST")
this.ensureAuthenticated(request)
this.ensureMethod(request, "POST")
const data = await this.getData(request)
const p = data ? querystring.parse(data) : {}
this.api.deleteSession(p.sessionId as string)
@ -32,9 +36,7 @@ export class DashboardHttpProvider extends HttpProvider {
case "/": {
this.ensureMethod(request)
if (route.requestPath !== "/index.html") {
throw new HttpError("Not found", HttpCode.NotFound)
} else if (!this.authenticated(request)) {
if (!this.authenticated(request)) {
return { redirect: "/login", query: { to: this.options.base } }
}
return this.getRoot(route)
@ -69,10 +71,6 @@ export class DashboardHttpProvider extends HttpProvider {
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") +
@ -151,7 +149,7 @@ export class DashboardHttpProvider extends HttpProvider {
</div>
<div class="item">
${humanize(update.checked)}
<a class="sub -link" href="${base}/update">Update now</a>
<a class="sub -link" href="${base}/update?to=${this.options.base}">Update now</a>
</div>
<div class="item" >Current: ${this.update.currentVersion}</div>
</div>`

View File

@ -18,17 +18,14 @@ interface LoginPayload {
*/
export class LoginHttpProvider extends HttpProvider {
public async handleRequest(route: Route, request: http.IncomingMessage): Promise<HttpResponse> {
if (this.options.auth !== AuthType.Password) {
if (this.options.auth !== AuthType.Password || route.requestPath !== "/index.html") {
throw new HttpError("Not found", HttpCode.NotFound)
}
switch (route.base) {
case "/":
if (route.requestPath !== "/index.html") {
throw new HttpError("Not found", HttpCode.NotFound)
}
switch (request.method) {
case "POST":
this.ensureMethod(request, ["GET", "POST"])
return this.tryLogin(route, request)
default:
this.ensureMethod(request)
@ -110,8 +107,4 @@ export class LoginHttpProvider extends HttpProvider {
throw new Error("Missing password")
}
public async handleWebSocket(): Promise<undefined> {
return undefined
}
}

View File

@ -1,5 +1,4 @@
import * as http from "http"
import { HttpCode, HttpError } from "../../common/http"
import { HttpProvider, HttpResponse, Route } from "../http"
/**
@ -32,8 +31,4 @@ export class StaticHttpProvider extends HttpProvider {
}
return this.getResource(this.rootPath, ...split)
}
public async handleWebSocket(): Promise<true> {
throw new HttpError("Not found", HttpCode.NotFound)
}
}

View File

@ -59,10 +59,14 @@ export class UpdateHttpProvider extends HttpProvider {
public async handleRequest(route: Route, request: http.IncomingMessage): Promise<HttpResponse> {
this.ensureAuthenticated(request)
this.ensureMethod(request)
if (route.requestPath !== "/index.html") {
throw new HttpError("Not found", HttpCode.NotFound)
}
switch (route.base) {
case "/check":
this.ensureMethod(request)
this.getUpdate(true)
if (route.query && route.query.to) {
return {
@ -70,37 +74,45 @@ export class UpdateHttpProvider extends HttpProvider {
query: { to: undefined },
}
}
return this.getRoot(route)
case "/": {
this.ensureMethod(request, ["GET", "POST"])
if (route.requestPath !== "/index.html") {
throw new HttpError("Not found", HttpCode.NotFound)
}
switch (request.method) {
case "GET":
return this.getRoot(route)
case "POST":
return this.tryUpdate(route)
}
}
return this.getRoot(route, request)
case "/apply":
return this.tryUpdate(route, request)
case "/":
return this.getRoot(route, request)
}
throw new HttpError("Not found", HttpCode.NotFound)
}
public async getRoot(route: Route, error?: Error): Promise<HttpResponse> {
public async getRoot(
route: Route,
request: http.IncomingMessage,
appliedUpdate?: string,
error?: Error,
): Promise<HttpResponse> {
if (request.headers["content-type"] === "application/json") {
if (!this.enabled) {
return {
content: {
isLatest: true,
},
}
}
const update = await this.getUpdate()
return {
content: {
...update,
isLatest: this.isLatestVersion(update),
},
}
}
const response = await this.getUtf8Resource(this.rootPath, "src/browser/pages/update.html")
response.content = response.content
.replace(/{{UPDATE_STATUS}}/, await this.getUpdateHtml())
.replace(/{{UPDATE_STATUS}}/, appliedUpdate ? `Updated to ${appliedUpdate}` : await this.getUpdateHtml())
.replace(/{{ERROR}}/, error ? `<div class="error">${error.message}</div>` : "")
return this.replaceTemplates(route, response)
}
public async handleWebSocket(): Promise<true> {
throw new HttpError("Not found", HttpCode.NotFound)
}
/**
* Query for and return the latest update.
*/
@ -163,25 +175,26 @@ export class UpdateHttpProvider extends HttpProvider {
const update = await this.getUpdate()
if (this.isLatestVersion(update)) {
throw new Error("No update available")
return "No update available"
}
return `<button type="submit" class="apply -button">Update to ${update.version}</button>`
}
public async tryUpdate(route: Route): Promise<HttpResponse> {
public async tryUpdate(route: Route, request: http.IncomingMessage): Promise<HttpResponse> {
try {
const update = await this.getUpdate()
if (!this.isLatestVersion(update)) {
await this.downloadUpdate(update)
await this.downloadAndApplyUpdate(update)
return this.getRoot(route, request, update.version)
}
return this.getRoot(route)
return this.getRoot(route, request)
} catch (error) {
return this.getRoot(route, error)
return this.getRoot(route, request, undefined, error)
}
}
public async downloadUpdate(update: Update, targetPath?: string, target?: string): Promise<void> {
public async downloadAndApplyUpdate(update: Update, targetPath?: string, target?: string): Promise<void> {
const releaseName = await this.getReleaseName(update, target)
const url = this.downloadUrl.replace("{{VERSION}}", update.version).replace("{{RELEASE_NAME}}", releaseName)

View File

@ -140,12 +140,16 @@ export abstract class HttpProvider {
/**
* Handle web sockets on the registered endpoint.
*/
public abstract handleWebSocket(
route: Route,
request: http.IncomingMessage,
socket: net.Socket,
head: Buffer,
): Promise<true | undefined>
public handleWebSocket(
/* eslint-disable @typescript-eslint/no-unused-vars */
_route: Route,
_request: http.IncomingMessage,
_socket: net.Socket,
_head: Buffer,
/* eslint-enable @typescript-eslint/no-unused-vars */
): Promise<true | undefined> {
throw new HttpError("Not found", HttpCode.NotFound)
}
/**
* Handle requests to the registered endpoint.
@ -194,6 +198,7 @@ export abstract class HttpProvider {
}
response.content = response.content
.replace(/{{COMMIT}}/g, this.options.commit)
.replace(/{{TO}}/g, Array.isArray(route.query.to) ? route.query.to[0] : route.query.to || "/dashboard")
.replace(/{{BASE}}/g, this.base(route))
.replace(/"{{OPTIONS}}"/, `'${JSON.stringify(options)}'`)
return response