Skip to content

Commit 21cfeb9

Browse files
committed
Add the ability to kill running VS Code instance
1 parent fd65cad commit 21cfeb9

File tree

9 files changed

+96
-58
lines changed

9 files changed

+96
-58
lines changed

src/browser/pages/error.css

+4
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,7 @@
2626
.error-display > .links > .link:hover {
2727
text-decoration: underline;
2828
}
29+
30+
.error-display .success {
31+
color: green;
32+
}

src/browser/pages/home.css

+3-16
Original file line numberDiff line numberDiff line change
@@ -32,28 +32,15 @@
3232
}
3333

3434
.block-row > .item > .icon.-missing {
35-
background-color: rgb(87, 114, 245);
36-
color: #fff;
35+
background-color: rgba(87, 114, 245, 0.2);
3736
text-align: center;
3837
}
3938

40-
.block-row > .item > .icon.-missing::after {
41-
content: "?";
42-
font-size: 0.7rem;
43-
vertical-align: middle;
44-
}
45-
4639
.kill-form {
4740
display: inline-block;
4841
}
4942

5043
.kill-form > .kill {
51-
background-color: rgb(87, 114, 245);
52-
border: none;
53-
color: #fff;
54-
cursor: pointer;
55-
font-size: 1rem;
56-
line-height: 1rem;
57-
margin: 0;
58-
padding: 0;
44+
border-radius: 3px;
45+
padding: 2px 5px;
5946
}

src/browser/pages/home.html

+22-23
Original file line numberDiff line numberDiff line change
@@ -20,27 +20,36 @@
2020
</head>
2121
<body>
2222
<div class="center-container">
23-
<!-- TEMP: Only VS Code for now. -->
24-
<!-- <div class="info-block"> -->
25-
<!-- <h2 class="header">Running Applications</h2> -->
26-
<!-- {{APP_LIST:RUNNING}} -->
27-
<!-- </div> -->
23+
<div class="card-box">
24+
<div class="header">
25+
<h2 class="main">Running</h2>
26+
<div class="sub">Currently running applications.</div>
27+
</div>
28+
<div class="content">
29+
{{APP_LIST:RUNNING}}
30+
</div>
31+
</div>
2832

2933
<div class="card-box">
3034
<div class="header">
31-
<h2 class="main">Launch</h2>
32-
<div class="sub">Choose an application to launch below.</div>
35+
<h2 class="main">Editors</h2>
36+
<div class="sub">Choose an editor to launch below.</div>
3337
</div>
3438
<div class="content">
35-
<div class="block-row">
36-
<a class="item -link" href="./vscode">
37-
<img class="icon" src="./static-{{COMMIT}}/lib/vscode/resources/linux/code.png" />
38-
VS Code
39-
</a>
40-
</div>
39+
{{APP_LIST:EDITORS}}
4140
</div>
4241
</div>
4342

43+
<!-- <div class="card-box"> -->
44+
<!-- <div class="header"> -->
45+
<!-- <h2 class="main">Other</h2> -->
46+
<!-- <div class="sub">Choose an application to launch below.</div> -->
47+
<!-- </div> -->
48+
<!-- <div class="content"> -->
49+
<!-- {{APP_LIST:OTHER}} -->
50+
<!-- </div> -->
51+
<!-- </div> -->
52+
4453
<div class="card-box">
4554
<div class="header">
4655
<h2 class="main">Version</h2>
@@ -50,16 +59,6 @@ <h2 class="main">Version</h2>
5059
{{UPDATE:NAME}}
5160
</div>
5261
</div>
53-
54-
<!-- <div class="info-block"> -->
55-
<!-- <h2 class="header">Editors</h2> -->
56-
<!-- {{APP_LIST:EDITORS}} -->
57-
<!-- </div> -->
58-
59-
<!-- <div class="info-block"> -->
60-
<!-- <h2 class="header">Other</h2> -->
61-
<!-- {{APP_LIST:OTHER}} -->
62-
<!-- </div> -->
6362
</div>
6463
</body>
6564
</html>

src/node/app/api.ts

+33-14
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ import {
1919
import { ApiEndpoint, HttpCode } from "../../common/http"
2020
import { normalize } from "../../common/util"
2121
import { HttpProvider, HttpProviderOptions, HttpResponse, HttpServer, Route } from "../http"
22-
import { findApplications, findWhitelistedApplications } from "./bin"
22+
import { findApplications, findWhitelistedApplications, Vscode } from "./bin"
23+
import { VscodeHttpProvider } from "./vscode"
2324

2425
interface ServerSession {
2526
process?: cp.ChildProcess
@@ -42,6 +43,7 @@ export class ApiHttpProvider extends HttpProvider {
4243
public constructor(
4344
options: HttpProviderOptions,
4445
private readonly server: HttpServer,
46+
private readonly vscode: VscodeHttpProvider,
4547
private readonly dataDir?: string,
4648
) {
4749
super(options)
@@ -256,17 +258,24 @@ export class ApiHttpProvider extends HttpProvider {
256258
/**
257259
* Kill a session identified by `app.sessionId`.
258260
*/
259-
public deleteSession(sessionId: string): HttpResponse {
261+
public async deleteSession(sessionId: string): Promise<HttpResponse> {
260262
logger.debug("deleting session", field("sessionId", sessionId))
261-
const session = this.sessions.get(sessionId)
262-
if (!session) {
263-
throw new Error("session does not exist")
264-
}
265-
if (session.process) {
266-
session.process.kill()
263+
switch (sessionId) {
264+
case "vscode":
265+
await this.vscode.dispose()
266+
return { code: HttpCode.Ok }
267+
default: {
268+
const session = this.sessions.get(sessionId)
269+
if (!session) {
270+
throw new Error("session does not exist")
271+
}
272+
if (session.process) {
273+
session.process.kill()
274+
}
275+
this.sessions.delete(sessionId)
276+
return { code: HttpCode.Ok }
277+
}
267278
}
268-
this.sessions.delete(sessionId)
269-
return { code: HttpCode.Ok }
270279
}
271280

272281
/**
@@ -350,10 +359,20 @@ export class ApiHttpProvider extends HttpProvider {
350359
*/
351360
public async running(): Promise<RunningResponse> {
352361
return {
353-
applications: Array.from(this.sessions).map(([sessionId, session]) => ({
354-
...session.app,
355-
sessionId,
356-
})),
362+
applications: (this.vscode.running
363+
? [
364+
{
365+
...Vscode,
366+
sessionId: "vscode",
367+
},
368+
]
369+
: []
370+
).concat(
371+
Array.from(this.sessions).map(([sessionId, session]) => ({
372+
...session.app,
373+
sessionId,
374+
})),
375+
),
357376
}
358377
}
359378

src/node/app/app.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,9 @@ export class MainHttpProvider extends HttpProvider {
124124
}
125125

126126
private getAppRows(apps: ReadonlyArray<Application>): string {
127-
return apps.length > 0 ? apps.map((app) => this.getAppRow(app)).join("\n") : `<div class="none">None</div>`
127+
return apps.length > 0
128+
? apps.map((app) => this.getAppRow(app)).join("\n")
129+
: `<div class="none">No applications are currently running.</div>`
128130
}
129131

130132
private getAppRow(app: Application): string {
@@ -141,7 +143,7 @@ export class MainHttpProvider extends HttpProvider {
141143
app.sessionId
142144
? `<form class="kill-form" action="./delete" method="POST">
143145
<input type="hidden" name="sessionId" value="${app.sessionId}">
144-
<button class="kill" type="submit">Kill</button>
146+
<button class="kill -button" type="submit">Kill</button>
145147
</form>`
146148
: ""
147149
}

src/node/app/bin.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import * as fs from "fs"
12
import * as path from "path"
23
import { Application } from "../../common/api"
34

@@ -11,6 +12,7 @@ const getVscodeVersion = (): string => {
1112

1213
export const Vscode: Application = {
1314
categories: ["Editor"],
15+
icon: fs.readFileSync(path.resolve(__dirname, "../../../lib/vscode/resources/linux/code.png")).toString("base64"),
1416
installed: true,
1517
name: "VS Code",
1618
path: "/vscode",

src/node/app/vscode.ts

+15-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,19 @@ export class VscodeHttpProvider extends HttpProvider {
3131
this.serverRootPath = path.join(this.vsRootPath, "out/vs/server")
3232
}
3333

34+
public get running(): boolean {
35+
return !!this._vscode
36+
}
37+
38+
public async dispose(): Promise<void> {
39+
if (this._vscode) {
40+
const vscode = await this._vscode
41+
vscode.removeAllListeners()
42+
this._vscode = undefined
43+
vscode.kill()
44+
}
45+
}
46+
3447
private async initialize(options: VscodeOptions): Promise<WorkbenchOptions> {
3548
const id = generateUuid()
3649
const vscode = await this.fork()
@@ -126,7 +139,8 @@ export class VscodeHttpProvider extends HttpProvider {
126139
} catch (error) {
127140
const message = `<div>VS Code failed to load.</div> ${
128141
this.isDev
129-
? "<div>It might not have finished compiling.</div>Check for 'Finished compilation' in the output."
142+
? `<div>It might not have finished compiling.</div>` +
143+
`Check for <code>Finished <span class="success">compilation</span></code> in the output.`
130144
: ""
131145
} <br><br>${error}`
132146
return this.getErrorRoot(route, "VS Code failed to load", "500", message)

src/node/entry.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ const main = async (args: Args): Promise<void> => {
4444
}
4545

4646
const httpServer = new HttpServer(options)
47-
const api = httpServer.registerHttpProvider("/api", ApiHttpProvider, httpServer, args["user-data-dir"])
47+
const vscode = httpServer.registerHttpProvider("/vscode", VscodeHttpProvider, args)
48+
const api = httpServer.registerHttpProvider("/api", ApiHttpProvider, httpServer, vscode, args["user-data-dir"])
4849
const update = httpServer.registerHttpProvider("/update", UpdateHttpProvider, !args["disable-updates"])
49-
httpServer.registerHttpProvider("/vscode", VscodeHttpProvider, args)
5050
httpServer.registerHttpProvider("/login", LoginHttpProvider)
5151
httpServer.registerHttpProvider("/", MainHttpProvider, api, update)
5252

src/node/http.ts

+11
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,10 @@ export interface HttpProvider2<A1, A2, T> {
360360
new (options: HttpProviderOptions, a1: A1, a2: A2): T
361361
}
362362

363+
export interface HttpProvider3<A1, A2, A3, T> {
364+
new (options: HttpProviderOptions, a1: A1, a2: A2, a3: A3): T
365+
}
366+
363367
/**
364368
* An HTTP server. Its main role is to route incoming HTTP requests to the
365369
* appropriate provider for that endpoint then write out the response. It also
@@ -417,6 +421,13 @@ export class HttpServer {
417421
a1: A1,
418422
a2: A2,
419423
): T
424+
public registerHttpProvider<A1, A2, A3, T extends HttpProvider>(
425+
endpoint: string,
426+
provider: HttpProvider3<A1, A2, A3, T>,
427+
a1: A1,
428+
a2: A2,
429+
a3: A3,
430+
): T
420431
// eslint-disable-next-line @typescript-eslint/no-explicit-any
421432
public registerHttpProvider(endpoint: string, provider: any, ...args: any[]): any {
422433
endpoint = endpoint.replace(/^\/+|\/+$/g, "")

0 commit comments

Comments
 (0)