Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/microsoft/vscode.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/vs/workbench/services/extensions/electron-sandbox/nativeLocalProcessExtensionHost.ts')
-rw-r--r--src/vs/workbench/services/extensions/electron-sandbox/nativeLocalProcessExtensionHost.ts123
1 files changed, 123 insertions, 0 deletions
diff --git a/src/vs/workbench/services/extensions/electron-sandbox/nativeLocalProcessExtensionHost.ts b/src/vs/workbench/services/extensions/electron-sandbox/nativeLocalProcessExtensionHost.ts
new file mode 100644
index 00000000000..35d0657b669
--- /dev/null
+++ b/src/vs/workbench/services/extensions/electron-sandbox/nativeLocalProcessExtensionHost.ts
@@ -0,0 +1,123 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+/* eslint-disable code-import-patterns */
+/* eslint-disable code-layering */
+
+import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
+import * as platform from 'vs/base/common/platform';
+import { StopWatch } from 'vs/base/common/stopwatch';
+import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
+import { PersistentProtocol } from 'vs/base/parts/ipc/common/ipc.net';
+import { createRandomIPCHandle, NodeSocket } from 'vs/base/parts/ipc/node/ipc.net';
+import { IExtensionHostProcessOptions } from 'vs/platform/extensions/common/extensionHostStarter';
+import { ILogService } from 'vs/platform/log/common/log';
+import { IPCExtHostConnection, writeExtHostConnection } from 'vs/workbench/services/extensions/common/extensionHostEnv';
+import { createMessageOfType, MessageType } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
+import { ExtensionHostProcess, ExtHostMessagePortCommunication, IExtHostCommunication, SandboxLocalProcessExtensionHost } from 'vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost';
+import { process } from 'vs/base/parts/sandbox/electron-sandbox/globals';
+
+export class NativeLocalProcessExtensionHost extends SandboxLocalProcessExtensionHost {
+ protected override async _start(): Promise<IMessagePassingProtocol> {
+ const canUseUtilityProcess = await this._extensionHostStarter.canUseUtilityProcess();
+ if (canUseUtilityProcess && (this._configurationService.getValue<boolean | undefined>('extensions.experimental.useUtilityProcess') || process.sandboxed)) {
+ const communication = this._toDispose.add(new ExtHostMessagePortCommunication(this._logService));
+ return this._startWithCommunication(communication);
+ } else {
+ const communication = this._toDispose.add(new ExtHostNamedPipeCommunication(this._logService));
+ return this._startWithCommunication(communication);
+ }
+ }
+}
+
+interface INamedPipePreparedData {
+ pipeName: string;
+ namedPipeServer: import('net').Server;
+}
+
+class ExtHostNamedPipeCommunication extends Disposable implements IExtHostCommunication<INamedPipePreparedData> {
+
+ readonly useUtilityProcess = false;
+
+ constructor(
+ @ILogService private readonly _logService: ILogService
+ ) {
+ super();
+ }
+
+ async prepare(): Promise<INamedPipePreparedData> {
+ const { createServer } = await import('net');
+ return new Promise<{ pipeName: string; namedPipeServer: import('net').Server }>((resolve, reject) => {
+ const pipeName = createRandomIPCHandle();
+
+ const namedPipeServer = createServer();
+ namedPipeServer.on('error', reject);
+ namedPipeServer.listen(pipeName, () => {
+ namedPipeServer?.removeListener('error', reject);
+ resolve({ pipeName, namedPipeServer });
+ });
+ this._register(toDisposable(() => {
+ if (namedPipeServer.listening) {
+ namedPipeServer.close();
+ }
+ }));
+ });
+ }
+
+ establishProtocol(prepared: INamedPipePreparedData, extensionHostProcess: ExtensionHostProcess, opts: IExtensionHostProcessOptions): Promise<IMessagePassingProtocol> {
+ const { namedPipeServer, pipeName } = prepared;
+
+ writeExtHostConnection(new IPCExtHostConnection(pipeName), opts.env);
+
+ return new Promise<PersistentProtocol>((resolve, reject) => {
+
+ // Wait for the extension host to connect to our named pipe
+ // and wrap the socket in the message passing protocol
+ const handle = setTimeout(() => {
+ if (namedPipeServer.listening) {
+ namedPipeServer.close();
+ }
+ reject('The local extension host took longer than 60s to connect.');
+ }, 60 * 1000);
+
+ namedPipeServer.on('connection', (socket) => {
+
+ clearTimeout(handle);
+ if (namedPipeServer.listening) {
+ namedPipeServer.close();
+ }
+
+ const nodeSocket = new NodeSocket(socket, 'renderer-exthost');
+ const protocol = new PersistentProtocol(nodeSocket);
+
+ this._register(toDisposable(() => {
+ // Send the extension host a request to terminate itself
+ // (graceful termination)
+ protocol.send(createMessageOfType(MessageType.Terminate));
+ protocol.flush();
+
+ socket.end();
+ nodeSocket.dispose();
+ protocol.dispose();
+ }));
+
+ resolve(protocol);
+ });
+
+ // Now that the named pipe listener is installed, start the ext host process
+ const sw = StopWatch.create(false);
+ extensionHostProcess.start(opts).then(() => {
+ const duration = sw.elapsed();
+ if (platform.isCI) {
+ this._logService.info(`IExtensionHostStarter.start() took ${duration} ms.`);
+ }
+ }, (err) => {
+ // Starting the ext host process resulted in an error
+ reject(err);
+ });
+
+ });
+ }
+}