Skip to content

Commit 548d095

Browse files
committed
Add support for running extensions in the browser
1 parent 846dcbb commit 548d095

24 files changed

+727
-51
lines changed

main.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
// while still allowing us to access files within the binary.
55
process.env.NBIN_BYPASS = true;
66

7-
require("../../bootstrap-amd").load("vs/server/src/cli");
7+
require("../../bootstrap-amd").load("vs/server/src/node/cli");

package.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,13 @@
2727
},
2828
"dependencies": {
2929
"@coder/logger": "^1.1.8",
30+
"@coder/node-browser": "^1.0.0",
31+
"@coder/requirefs": "^1.0.3",
3032
"httpolyglot": "^0.1.2",
3133
"pem": "^1.14.2",
3234
"safe-compare": "^1.1.4",
3335
"tar-fs": "^2.0.0",
34-
"tar-stream": "^2.1.0"
36+
"tar-stream": "^2.1.0",
37+
"util": "^0.12.1"
3538
}
3639
}

scripts/build-json.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ const writeProduct = () => {
4545
"vs/workbench/workbench.web.api.css",
4646
"vs/code/browser/workbench/workbench.html",
4747
"vs/code/browser/workbench/workbench.js",
48-
"vs/server/src/cli.js",
49-
"vs/server/src/uriTransformer.js",
48+
"vs/server/src/node/cli.js",
49+
"vs/server/src/node/uriTransformer.js",
5050
"vs/server/src/login/index.html"
5151
]);
5252
const date = new Date().toISOString();

scripts/vscode.patch

+337-11
Large diffs are not rendered by default.

src/api.ts renamed to src/browser/api.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as vscode from "vscode";
2-
import { CoderApi, VSCodeApi } from "../typings/api";
2+
import { CoderApi, VSCodeApi } from "../../typings/api";
33
import { createCSSRule } from "vs/base/browser/dom";
44
import { Emitter, Event } from "vs/base/common/event";
55
import { IDisposable } from "vs/base/common/lifecycle";

src/client.ts renamed to src/browser/client.ts

+25-8
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
1+
import { Emitter } from "vs/base/common/event";
12
import { URI } from "vs/base/common/uri";
23
import { registerSingleton } from "vs/platform/instantiation/common/extensions";
34
import { ServiceCollection } from "vs/platform/instantiation/common/serviceCollection";
4-
import { ITelemetryService } from "vs/platform/telemetry/common/telemetry";
55
import { ILocalizationsService } from "vs/platform/localizations/common/localizations";
66
import { LocalizationsService } from "vs/platform/localizations/electron-browser/localizationsService";
7+
import { ITelemetryService } from "vs/platform/telemetry/common/telemetry";
78
import { IUpdateService } from "vs/platform/update/common/update";
89
import { UpdateService } from "vs/platform/update/electron-browser/updateService";
9-
import { TelemetryChannelClient } from "vs/server/src/telemetry";
10-
import { IUploadService, UploadService } from 'vs/server/src/upload';
10+
import { coderApi, vscodeApi } from "vs/server/src/browser/api";
11+
import { IUploadService, UploadService } from "vs/server/src/browser/upload";
12+
import { INodeProxyService, NodeProxyChannelClient } from "vs/server/src/common/nodeProxy";
13+
import { TelemetryChannelClient } from "vs/server/src/common/telemetry";
14+
import "vs/workbench/contrib/localizations/browser/localizations.contribution";
15+
import "vs/workbench/contrib/update/electron-browser/update.contribution";
1116
import { IRemoteAgentService } from "vs/workbench/services/remote/common/remoteAgentService";
1217

1318
class TelemetryService extends TelemetryChannelClient {
@@ -18,16 +23,28 @@ class TelemetryService extends TelemetryChannelClient {
1823
}
1924
}
2025

26+
class NodeProxyService extends NodeProxyChannelClient implements INodeProxyService {
27+
private readonly _onClose = new Emitter<void>();
28+
public readonly onClose = this._onClose.event;
29+
private readonly _onDown = new Emitter<void>();
30+
public readonly onDown = this._onDown.event;
31+
private readonly _onUp = new Emitter<void>();
32+
public readonly onUp = this._onUp.event;
33+
34+
public constructor(
35+
@IRemoteAgentService remoteAgentService: IRemoteAgentService,
36+
) {
37+
// TODO: up/down/close
38+
super(remoteAgentService.getConnection()!.getChannel("nodeProxy"));
39+
}
40+
}
41+
2142
registerSingleton(ILocalizationsService, LocalizationsService);
43+
registerSingleton(INodeProxyService, NodeProxyService);
2244
registerSingleton(ITelemetryService, TelemetryService);
2345
registerSingleton(IUpdateService, UpdateService);
2446
registerSingleton(IUploadService, UploadService, true);
2547

26-
import "vs/workbench/contrib/update/electron-browser/update.contribution";
27-
import 'vs/workbench/contrib/localizations/browser/localizations.contribution';
28-
29-
import { coderApi, vscodeApi } from "vs/server/src/api";
30-
3148
/**
3249
* This is called by vs/workbench/browser/web.main.ts after the workbench has
3350
* been initialized so we can initialize our own client-side code.

src/browser/extHostNodeProxy.ts

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { Emitter } from "vs/base/common/event";
2+
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
3+
import { ExtHostNodeProxyShape, MainContext, MainThreadNodeProxyShape } from "vs/workbench/api/common/extHost.protocol";
4+
import { IExtHostRpcService } from "vs/workbench/api/common/extHostRpcService";
5+
6+
export class ExtHostNodeProxy implements ExtHostNodeProxyShape {
7+
_serviceBrand: any;
8+
9+
private readonly _onMessage = new Emitter<string>();
10+
public readonly onMessage = this._onMessage.event;
11+
private readonly _onClose = new Emitter<void>();
12+
public readonly onClose = this._onClose.event;
13+
private readonly _onDown = new Emitter<void>();
14+
public readonly onDown = this._onDown.event;
15+
private readonly _onUp = new Emitter<void>();
16+
public readonly onUp = this._onUp.event;
17+
18+
private readonly proxy: MainThreadNodeProxyShape;
19+
20+
constructor(@IExtHostRpcService rpc: IExtHostRpcService) {
21+
this.proxy = rpc.getProxy(MainContext.MainThreadNodeProxy);
22+
}
23+
24+
public $onMessage(message: string): void {
25+
this._onMessage.fire(message);
26+
}
27+
28+
public $onClose(): void {
29+
this._onClose.fire();
30+
}
31+
32+
public $onUp(): void {
33+
this._onUp.fire();
34+
}
35+
36+
public $onDown(): void {
37+
this._onDown.fire();
38+
}
39+
40+
public send(message: string): void {
41+
this.proxy.$send(message);
42+
}
43+
}
44+
45+
export interface IExtHostNodeProxy extends ExtHostNodeProxy { }
46+
export const IExtHostNodeProxy = createDecorator<IExtHostNodeProxy>('IExtHostNodeProxy');

src/browser/mainThreadNodeProxy.ts

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { IDisposable } from "vs/base/common/lifecycle";
2+
import { INodeProxyService } from "vs/server/src/common/nodeProxy";
3+
import { ExtHostContext, IExtHostContext, MainContext, MainThreadNodeProxyShape } from "vs/workbench/api/common/extHost.protocol";
4+
import { extHostNamedCustomer } from "vs/workbench/api/common/extHostCustomers";
5+
6+
@extHostNamedCustomer(MainContext.MainThreadNodeProxy)
7+
export class MainThreadNodeProxy implements MainThreadNodeProxyShape {
8+
private disposed = false;
9+
private disposables = <IDisposable[]>[];
10+
11+
constructor(
12+
extHostContext: IExtHostContext,
13+
@INodeProxyService private readonly proxyService: INodeProxyService,
14+
) {
15+
if (!extHostContext.remoteAuthority) { // HACK: A terrible way to detect if running in the worker.
16+
const proxy = extHostContext.getProxy(ExtHostContext.ExtHostNodeProxy);
17+
this.disposables = [
18+
this.proxyService.onMessage((message: string) => proxy.$onMessage(message)),
19+
this.proxyService.onClose(() => proxy.$onClose()),
20+
this.proxyService.onDown(() => proxy.$onDown()),
21+
this.proxyService.onUp(() => proxy.$onUp()),
22+
];
23+
}
24+
}
25+
26+
$send(message: string): void {
27+
if (!this.disposed) {
28+
this.proxyService.send(message);
29+
}
30+
}
31+
32+
dispose(): void {
33+
this.disposables.forEach((d) => d.dispose());
34+
this.disposables = [];
35+
this.disposed = true;
36+
}
37+
}
File renamed without changes.

src/common/nodeProxy.ts

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { Event } from "vs/base/common/event";
2+
import { IChannel, IServerChannel } from "vs/base/parts/ipc/common/ipc";
3+
import { createDecorator } from "vs/platform/instantiation/common/instantiation";
4+
import { ReadWriteConnection } from "vs/server/node_modules/@coder/node-browser/out/common/connection";
5+
6+
export const INodeProxyService = createDecorator<INodeProxyService>("nodeProxyService");
7+
8+
export interface INodeProxyService extends ReadWriteConnection {
9+
_serviceBrand: any;
10+
send(message: string): void;
11+
onMessage: Event<string>;
12+
onUp: Event<void>;
13+
onClose: Event<void>;
14+
onDown: Event<void>;
15+
}
16+
17+
export class NodeProxyChannel implements IServerChannel {
18+
constructor(private service: INodeProxyService) {}
19+
20+
listen(_: unknown, event: string): Event<any> {
21+
switch (event) {
22+
case "onMessage": return this.service.onMessage;
23+
}
24+
throw new Error(`Invalid listen ${event}`);
25+
}
26+
27+
async call(_: unknown, command: string, args?: any): Promise<any> {
28+
switch (command) {
29+
case "send": return this.service.send(args[0]);
30+
}
31+
throw new Error(`Invalid call ${command}`);
32+
}
33+
}
34+
35+
export class NodeProxyChannelClient {
36+
_serviceBrand: any;
37+
38+
public readonly onMessage: Event<string>;
39+
40+
constructor(private readonly channel: IChannel) {
41+
this.onMessage = this.channel.listen<string>("onMessage");
42+
}
43+
44+
public send(data: string): void {
45+
this.channel.call("send", [data]);
46+
}
47+
}
File renamed without changes.

src/channel.ts renamed to src/node/channel.ts

+38-2
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@ import pkg from "vs/platform/product/node/package";
1616
import product from "vs/platform/product/node/product";
1717
import { IRemoteAgentEnvironment } from "vs/platform/remote/common/remoteAgentEnvironment";
1818
import { ITelemetryService } from "vs/platform/telemetry/common/telemetry";
19-
import { getTranslations } from "vs/server/src/nls";
20-
import { getUriTransformer } from "vs/server/src/util";
19+
import { INodeProxyService } from "vs/server/src/common/nodeProxy";
20+
import { getTranslations } from "vs/server/src/node/nls";
21+
import { getUriTransformer } from "vs/server/src/node/util";
2122
import { ExtensionScanner, ExtensionScannerInput } from "vs/workbench/services/extensions/node/extensionPoints";
23+
import { Server } from "vs/server/node_modules/@coder/node-browser/out/server/server";
2224

2325
/**
2426
* Extend the file provider to allow unwatching.
@@ -274,3 +276,37 @@ export class ExtensionEnvironmentChannel implements IServerChannel {
274276
this.telemetry.setEnabled(false);
275277
}
276278
}
279+
280+
export class NodeProxyService implements INodeProxyService {
281+
public _serviceBrand = undefined;
282+
283+
public readonly server: Server;
284+
285+
private readonly _onMessage = new Emitter<string>();
286+
public readonly onMessage = this._onMessage.event;
287+
private readonly _$onMessage = new Emitter<string>();
288+
public readonly $onMessage = this._$onMessage.event;
289+
private readonly _onClose = new Emitter<void>();
290+
public readonly onClose = this._onClose.event;
291+
private readonly _onDown = new Emitter<void>();
292+
public readonly onDown = this._onDown.event;
293+
private readonly _onUp = new Emitter<void>();
294+
public readonly onUp = this._onUp.event;
295+
296+
public constructor() {
297+
// TODO: close/down/up
298+
this.server = new Server({
299+
onMessage: this.$onMessage,
300+
onClose: this.onClose,
301+
onDown: this.onDown,
302+
onUp: this.onUp,
303+
send: (message: string): void => {
304+
this._onMessage.fire(message);
305+
}
306+
});
307+
}
308+
309+
public send(message: string): void {
310+
this._$onMessage.fire(message);
311+
}
312+
}

src/cli.ts renamed to src/node/cli.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ import { buildHelpMessage, buildVersionMessage, Option as VsOption, options as v
99
import { parseMainProcessArgv } from "vs/platform/environment/node/argvHelper";
1010
import pkg from "vs/platform/product/node/package";
1111
import product from "vs/platform/product/node/product";
12-
import { ipcMain } from "vs/server/src/ipc";
13-
import { enableCustomMarketplace } from "vs/server/src/marketplace";
14-
import { MainServer } from "vs/server/src/server";
15-
import { AuthType, buildAllowedMessage, enumToArray, FormatType, generateCertificate, generatePassword, localRequire, open, unpackExecutables } from "vs/server/src/util";
12+
import { ipcMain } from "vs/server/src/node/ipc";
13+
import { enableCustomMarketplace } from "vs/server/src/node/marketplace";
14+
import { MainServer } from "vs/server/src/node/server";
15+
import { AuthType, buildAllowedMessage, enumToArray, FormatType, generateCertificate, generatePassword, localRequire, open, unpackExecutables } from "vs/server/src/node/util";
1616

1717
const { logger } = localRequire<typeof import("@coder/logger/out/index")>("@coder/logger/out/index");
1818
setUnexpectedErrorHandler((error) => logger.warn(error.message));

src/connection.ts renamed to src/node/connection.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ import { ISocket } from "vs/base/parts/ipc/common/ipc.net";
66
import { NodeSocket } from "vs/base/parts/ipc/node/ipc.net";
77
import { IEnvironmentService } from "vs/platform/environment/common/environment";
88
import { ILogService } from "vs/platform/log/common/log";
9-
import { getNlsConfiguration } from "vs/server/src/nls";
10-
import { Protocol } from "vs/server/src/protocol";
11-
import { uriTransformerPath } from "vs/server/src/util";
9+
import { getNlsConfiguration } from "vs/server/src/node/nls";
10+
import { Protocol } from "vs/server/src/node/protocol";
11+
import { uriTransformerPath } from "vs/server/src/node/util";
1212
import { IExtHostReadyMessage } from "vs/workbench/services/extensions/common/extensionHostProtocol";
1313

1414
export abstract class Connection {
File renamed without changes.
File renamed without changes.

src/marketplace.ts renamed to src/node/marketplace.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { mkdirp } from "vs/base/node/pfs";
66
import * as vszip from "vs/base/node/zip";
77
import * as nls from "vs/nls";
88
import product from "vs/platform/product/node/product";
9-
import { localRequire } from "vs/server/src/util";
9+
import { localRequire } from "vs/server/src/node/util";
1010

1111
const tarStream = localRequire<typeof import("tar-stream")>("tar-stream/index");
1212

File renamed without changes.
File renamed without changes.

src/server.ts renamed to src/node/server.ts

+12-9
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,15 @@ import { combinedAppender, LogAppender, NullTelemetryService } from "vs/platform
5757
import { AppInsightsAppender } from "vs/platform/telemetry/node/appInsightsAppender";
5858
import { resolveCommonProperties } from "vs/platform/telemetry/node/commonProperties";
5959
import { UpdateChannel } from "vs/platform/update/node/updateIpc";
60-
import { ExtensionEnvironmentChannel, FileProviderChannel } from "vs/server/src/channel";
61-
import { Connection, ExtensionHostConnection, ManagementConnection } from "vs/server/src/connection";
62-
import { TelemetryClient } from "vs/server/src/insights";
63-
import { getLocaleFromConfig, getNlsConfiguration } from "vs/server/src/nls";
64-
import { Protocol } from "vs/server/src/protocol";
65-
import { TelemetryChannel } from "vs/server/src/telemetry";
66-
import { UpdateService } from "vs/server/src/update";
67-
import { AuthType, getMediaMime, getUriTransformer, localRequire, tmpdir } from "vs/server/src/util";
60+
import { ExtensionEnvironmentChannel, FileProviderChannel, NodeProxyService } from "vs/server/src/node/channel";
61+
import { Connection, ExtensionHostConnection, ManagementConnection } from "vs/server/src/node/connection";
62+
import { TelemetryClient } from "vs/server/src/node/insights";
63+
import { getLocaleFromConfig, getNlsConfiguration } from "vs/server/src/node/nls";
64+
import { NodeProxyChannel } from "vs/server/src/common/nodeProxy";
65+
import { Protocol } from "vs/server/src/node/protocol";
66+
import { TelemetryChannel } from "vs/server/src/common/telemetry";
67+
import { UpdateService } from "vs/server/src/node/update";
68+
import { AuthType, getMediaMime, getUriTransformer, localRequire, tmpdir } from "vs/server/src/node/util";
6869
import { RemoteExtensionLogFileName } from "vs/workbench/services/remote/common/remoteAgentService";
6970
import { IWorkbenchConstructionOptions } from "vs/workbench/workbench.web.api";
7071

@@ -125,7 +126,7 @@ export interface ServerOptions {
125126

126127
export abstract class Server {
127128
protected readonly server: http.Server | https.Server;
128-
protected rootPath = path.resolve(__dirname, "../../../..");
129+
protected rootPath = path.resolve(__dirname, "../../../../..");
129130
protected serverRoot = path.join(this.rootPath, "/out/vs/server/src");
130131
protected readonly allowedRequestPaths: string[] = [this.rootPath];
131132
private listenPromise: Promise<string> | undefined;
@@ -707,11 +708,13 @@ export class MainServer extends Server {
707708
const requestChannel = new RequestChannel(this.services.get(IRequestService) as IRequestService);
708709
const telemetryChannel = new TelemetryChannel(telemetryService);
709710
const updateChannel = new UpdateChannel(instantiationService.createInstance(UpdateService));
711+
const nodeProxyChannel = new NodeProxyChannel(instantiationService.createInstance(NodeProxyService));
710712

711713
this.ipc.registerChannel("extensions", extensionsChannel);
712714
this.ipc.registerChannel("remoteextensionsenvironment", extensionsEnvironmentChannel);
713715
this.ipc.registerChannel("request", requestChannel);
714716
this.ipc.registerChannel("telemetry", telemetryChannel);
717+
this.ipc.registerChannel("nodeProxy", nodeProxyChannel);
715718
this.ipc.registerChannel("update", updateChannel);
716719
this.ipc.registerChannel(REMOTE_FILE_SYSTEM_CHANNEL_NAME, fileChannel);
717720
resolve(new ErrorTelemetry(telemetryService));

src/update.ts renamed to src/node/update.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ import pkg from "vs/platform/product/node/package";
1515
import { asJson, IRequestService } from "vs/platform/request/common/request";
1616
import { AvailableForDownload, State, StateType, UpdateType } from "vs/platform/update/common/update";
1717
import { AbstractUpdateService } from "vs/platform/update/electron-main/abstractUpdateService";
18-
import { ipcMain } from "vs/server/src/ipc";
19-
import { extract } from "vs/server/src/marketplace";
20-
import { tmpdir } from "vs/server/src/util";
18+
import { ipcMain } from "vs/server/src/node/ipc";
19+
import { extract } from "vs/server/src/node/marketplace";
20+
import { tmpdir } from "vs/server/src/node/util";
2121
import * as zlib from "zlib";
2222

2323
interface IUpdate {

0 commit comments

Comments
 (0)