提交 330901dd 编写于 作者: J Joao Moreno

run shared process in a browser window

上级 b518405b
<!-- Copyright (C) Microsoft Corporation. All rights reserved. -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body class="monaco-shell vs-dark" aria-label="">
<script>
(function () {
try {
window.location.search.substring(1).split('&').forEach(p => {
var kv = p.split('=');
if (kv[0] === 'config' && kv[1]) {
let config = JSON.parse(decodeURIComponent(kv[1]));
window.document.body.className = 'monaco-shell ' + config.baseTheme;
}
});
} catch (error) {
console.error(error);
}
})();
</script>
Shared Process
</body>
<!-- Startup via index.js -->
<script src="sharedProcess.js"></script>
</html>
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
// Warning: Do not use the `let` declarator in this file, it breaks our minification
'use strict';
/*global window,document,define*/
const path = require('path');
const electron = require('electron');
const remote = electron.remote;
const ipc = electron.ipcRenderer;
function assign(destination, source) {
return Object.keys(source)
.reduce(function (r, key) { r[key] = source[key]; return r; }, destination);
}
function parseURLQueryArgs() {
const search = window.location.search || '';
return search.split(/[?&]/)
.filter(function (param) { return !!param; })
.map(function (param) { return param.split('='); })
.filter(function (param) { return param.length === 2; })
.reduce(function (r, param) { r[param[0]] = decodeURIComponent(param[1]); return r; }, {});
}
function createScript(src, onload) {
const script = document.createElement('script');
script.src = src;
script.addEventListener('load', onload);
const head = document.getElementsByTagName('head')[0];
head.insertBefore(script, head.lastChild);
}
function uriFromPath(_path) {
var pathName = path.resolve(_path).replace(/\\/g, '/');
if (pathName.length > 0 && pathName.charAt(0) !== '/') {
pathName = '/' + pathName;
}
return encodeURI('file://' + pathName);
}
function main() {
const args = parseURLQueryArgs();
const configuration = JSON.parse(args['config'] || '{}') || {};
// Correctly inherit the parent's environment
assign(process.env, configuration.userEnv);
// Get the nls configuration into the process.env as early as possible.
var nlsConfig = { availableLanguages: {} };
const config = process.env['VSCODE_NLS_CONFIG'];
if (config) {
process.env['VSCODE_NLS_CONFIG'] = config;
try {
nlsConfig = JSON.parse(config);
} catch (e) { /*noop*/ }
}
var locale = nlsConfig.availableLanguages['*'] || 'en';
if (locale === 'zh-tw') {
locale = 'zh-Hant';
} else if (locale === 'zh-cn') {
locale = 'zh-Hans';
}
window.document.documentElement.setAttribute('lang', locale);
// Load the loader and start loading the workbench
const rootUrl = uriFromPath(configuration.appRoot) + '/out';
// In the bundled version the nls plugin is packaged with the loader so the NLS Plugins
// loads as soon as the loader loads. To be able to have pseudo translation
createScript(rootUrl + '/vs/loader.js', function () {
define('fs', ['original-fs'], function (originalFS) { return originalFS; }); // replace the patched electron fs with the original node fs for all AMD code
window.MonacoEnvironment = {};
const nodeCachedDataErrors = window.MonacoEnvironment.nodeCachedDataErrors = [];
require.config({
baseUrl: rootUrl,
'vs/nls': nlsConfig,
nodeCachedDataDir: configuration.nodeCachedDataDir,
onNodeCachedDataError: function (err) { nodeCachedDataErrors.push(err) },
nodeModules: [/*BUILD->INSERT_NODE_MODULES*/]
});
if (nlsConfig.pseudo) {
require(['vs/nls'], function (nlsPlugin) {
nlsPlugin.setPseudoTranslation(nlsConfig.pseudo);
});
}
require(['vs/code/electron-browser/sharedProcessMain'], function () {
});
});
}
main();
......@@ -28,32 +28,16 @@ import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProper
import { TelemetryAppenderChannel } from 'vs/platform/telemetry/common/telemetryIpc';
import { TelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService';
import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppender';
import { ISharedProcessInitData } from './sharedProcess';
// import { ISharedProcessInitData } from './sharedProcess';
import { IChoiceService } from 'vs/platform/message/common/message';
import { ChoiceChannelClient } from 'vs/platform/message/common/messageIpc';
import { IWindowsService } from 'vs/platform/windows/common/windows';
import { WindowsChannelClient } from 'vs/platform/windows/common/windowsIpc';
import { ActiveWindowManager } from 'vs/code/common/windows';
import { ipcRenderer } from 'electron';
function quit(err?: Error) {
if (err) {
console.error(err.stack || err);
}
process.exit(err ? 1 : 0);
}
/**
* Plan B is to kill oneself if one's parent dies. Much drama.
*/
function setupPlanB(parentPid: number): void {
setInterval(function () {
try {
process.kill(parentPid, 0); // throws an exception if the main process doesn't exist anymore.
} catch (e) {
process.exit();
}
}, 5000);
interface ISharedProcessInitData {
args: any;
}
const eventPrefix = 'monacoworkbench';
......@@ -161,14 +145,13 @@ function setupIPC(hook: string): TPromise<Server> {
function handshake(): TPromise<ISharedProcessInitData> {
return new TPromise<ISharedProcessInitData>((c, e) => {
process.once('message', c);
process.once('error', e);
process.send('hello');
ipcRenderer.once('handshake', (_, r) => c(r));
ipcRenderer.send('handshake');
});
}
setupIPC(process.env['VSCODE_SHARED_IPC_HOOK'])
.then(server => handshake()
.then(data => main(server, data))
.then(() => setupPlanB(process.env['VSCODE_PID']))
.done(null, quit));
\ No newline at end of file
.then(data => main(server, data)));
// .then(() => setupPlanB(process.env['VSCODE_PID']))
// .done(null, quit));
......@@ -27,9 +27,8 @@ import { Server, serve, connect } from 'vs/base/parts/ipc/node/ipc.net';
import { TPromise } from 'vs/base/common/winjs.base';
import { AskpassChannel } from 'vs/workbench/parts/git/common/gitIpc';
import { GitAskpassService } from 'vs/workbench/parts/git/electron-main/askpassService';
import { spawnSharedProcess } from 'vs/code/node/sharedProcess';
import { spawnSharedProcess } from 'vs/code/electron-main/sharedProcess';
import { Mutex } from 'windows-mutex';
import { IDisposable } from 'vs/base/common/lifecycle';
import { LaunchService, ILaunchChannel, LaunchChannel, LaunchChannelClient, ILaunchService } from './launch';
import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
......@@ -144,17 +143,9 @@ function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: platfo
// Spawn shared process
const initData = { args: environmentService.args };
const options = {
allowOutput: !environmentService.isBuilt || environmentService.verbose,
debugPort: environmentService.isBuilt ? null : 5871
};
let sharedProcessDisposable: IDisposable;
const sharedProcess = spawnSharedProcess(initData, options).then(disposable => {
sharedProcessDisposable = disposable;
return connect(environmentService.sharedIPCHandle, 'main');
});
const sharedProcess = spawnSharedProcess(initData)
.then(disposable => connect(environmentService.sharedIPCHandle, 'main'));
// Create a new service collection, because the telemetry service
// requires a connection to shared process, which was only established
......@@ -220,10 +211,6 @@ function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: platfo
mainIpcServer = null;
}
if (sharedProcessDisposable) {
sharedProcessDisposable.dispose();
}
if (windowsMutex) {
windowsMutex.release();
}
......
......@@ -3,75 +3,40 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as cp from 'child_process';
import URI from 'vs/base/common/uri';
import { IDisposable } from 'vs/base/common/lifecycle';
import { assign } from 'vs/base/common/objects';
import { ParsedArgs } from 'vs/platform/environment/common/environment';
import { TPromise } from 'vs/base/common/winjs.base';
import { BrowserWindow, ipcMain } from 'electron';
export interface ISharedProcessInitData {
args: ParsedArgs;
}
export interface ISharedProcessOptions {
allowOutput?: boolean;
debugPort?: number;
}
const boostrapPath = URI.parse(require.toUrl('bootstrap')).fsPath;
function _spawnSharedProcess(initData: ISharedProcessInitData, options: ISharedProcessOptions): cp.ChildProcess {
const execArgv: string[] = [];
const env = assign({}, process.env, {
AMD_ENTRYPOINT: 'vs/code/node/sharedProcessMain',
ELECTRON_NO_ASAR: '1'
export function spawnSharedProcess(initData: ISharedProcessInitData): TPromise<void> {
const window = new BrowserWindow();
const config = assign({
userEnv: {},
appRoot: '',
nodeCachedDataDir: ''
});
if (options.allowOutput) {
env['VSCODE_ALLOW_IO'] = 'true';
}
if (options.debugPort) {
execArgv.push(`--debug=${options.debugPort}`);
}
const result = cp.fork(boostrapPath, ['--type=SharedProcess'], { env, execArgv });
return result;
}
const url = `${require.toUrl('vs/code/electron-browser/sharedProcess.html')}?config=${encodeURIComponent(JSON.stringify(config))}`;
window.loadURL(url);
// window.hide();
window.webContents.openDevTools();
export function spawnSharedProcess(initData: ISharedProcessInitData, options: ISharedProcessOptions = {}): TPromise<IDisposable> {
let spawnCount = 0;
let child: cp.ChildProcess;
let promise: TPromise<IDisposable>;
const spawn = () => {
if (++spawnCount > 10) {
return;
// Prevent the window from dying
window.on('close', e => {
if (window.isVisible()) {
e.preventDefault();
window.hide();
}
});
child = _spawnSharedProcess(initData, options);
promise = new TPromise<IDisposable>((c, e) => {
// handshake
child.once('message', () => {
child.send(initData);
c({
dispose: () => {
if (child) {
child.removeListener('exit', spawn);
child.kill();
child = null;
}
}
});
});
return new TPromise<void>((c, e) => {
ipcMain.once('handshake', ({ sender }) => {
sender.send('handshake', initData);
c(null);
});
child.on('exit', spawn);
};
spawn();
return promise;
});
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册