sharedProcessMain.ts 9.6 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4 5
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

B
Benjamin Pasero 已提交
6 7
'use strict';

E
Erich Gamma 已提交
8
import * as fs from 'fs';
9
import * as platform from 'vs/base/common/platform';
10 11
import product from 'vs/platform/node/product';
import pkg from 'vs/platform/node/package';
J
Joao Moreno 已提交
12
import { serve, Server, connect } from 'vs/base/parts/ipc/node/ipc.net';
E
Erich Gamma 已提交
13
import { TPromise } from 'vs/base/common/winjs.base';
J
Joao Moreno 已提交
14 15 16
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
J
Joao Moreno 已提交
17 18
import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment';
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
J
Joao Moreno 已提交
19
import { ExtensionManagementChannel } from 'vs/platform/extensionManagement/node/extensionManagementIpc';
20
import { IExtensionManagementService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement';
J
Joao Moreno 已提交
21
import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
22
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService';
J
Joao Moreno 已提交
23
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
24
import { ConfigurationService } from 'vs/platform/configuration/node/configurationService';
J
Joao Moreno 已提交
25
import { IRequestService } from 'vs/platform/request/node/request';
26
import { RequestService } from 'vs/platform/request/electron-browser/requestService';
27
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
28
import { combinedAppender, NullTelemetryService, ITelemetryAppender, NullAppender, LogAppender } from 'vs/platform/telemetry/common/telemetryUtils';
29
import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties';
J
Joao Moreno 已提交
30
import { TelemetryAppenderChannel } from 'vs/platform/telemetry/node/telemetryIpc';
31
import { TelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService';
32
import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppender';
J
Joao Moreno 已提交
33
import { IWindowsService, ActiveWindowManager } from 'vs/platform/windows/common/windows';
J
Joao Moreno 已提交
34
import { WindowsChannelClient } from 'vs/platform/windows/node/windowsIpc';
35
import { ipcRenderer } from 'electron';
36
import { createSharedProcessContributions } from 'vs/code/electron-browser/sharedProcess/contrib/contributions';
37
import { createSpdLogService } from 'vs/platform/log/node/spdlogService';
S
Sandeep Somavarapu 已提交
38
import { ILogService, LogLevel } from 'vs/platform/log/common/log';
J
Joao Moreno 已提交
39
import { LogLevelSetterChannelClient, FollowerLogService } from 'vs/platform/log/node/logIpc';
S
Sandeep Somavarapu 已提交
40 41
import { LocalizationsService } from 'vs/platform/localizations/node/localizations';
import { ILocalizationsService } from 'vs/platform/localizations/common/localizations';
J
Joao Moreno 已提交
42 43
import { LocalizationsChannel } from 'vs/platform/localizations/node/localizationsIpc';
import { DialogChannelClient } from 'vs/platform/dialogs/node/dialogIpc';
44
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
S
Sandeep Somavarapu 已提交
45
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
46 47
import { IDownloadService } from 'vs/platform/download/common/download';
import { DownloadServiceChannelClient } from 'vs/platform/download/node/downloadIpc';
48
import { DefaultURITransformer } from 'vs/base/common/uriIpc';
49

50
export interface ISharedProcessConfiguration {
B
Benjamin Pasero 已提交
51
	readonly machineId: string;
52 53 54 55 56 57
}

export function startup(configuration: ISharedProcessConfiguration) {
	handshake(configuration);
}

58
interface ISharedProcessInitData {
59
	sharedIPCHandle: string;
J
Joao Moreno 已提交
60
	args: ParsedArgs;
S
Sandeep Somavarapu 已提交
61
	logLevel: LogLevel;
E
Erich Gamma 已提交
62 63
}

64 65
const eventPrefix = 'monacoworkbench';

66
function main(server: Server, initData: ISharedProcessInitData, configuration: ISharedProcessConfiguration): void {
J
Joao Moreno 已提交
67
	const services = new ServiceCollection();
S
Sandeep Somavarapu 已提交
68 69
	const disposables: IDisposable[] = [];
	process.once('exit', () => dispose(disposables));
E
Erich Gamma 已提交
70

71
	const environmentService = new EnvironmentService(initData.args, process.execPath);
J
Joao Moreno 已提交
72 73
	const mainRoute = () => TPromise.as('main');
	const logLevelClient = new LogLevelSetterChannelClient(server.getChannel('loglevel', { routeCall: mainRoute, routeEvent: mainRoute }));
S
Sandeep Somavarapu 已提交
74
	const logService = new FollowerLogService(logLevelClient, createSpdLogService('sharedprocess', initData.logLevel, environmentService.logsPath));
S
Sandeep Somavarapu 已提交
75
	disposables.push(logService);
J
Joao Moreno 已提交
76

77 78 79 80
	logService.info('main', JSON.stringify(configuration));

	services.set(IEnvironmentService, environmentService);
	services.set(ILogService, logService);
81
	services.set(IConfigurationService, new SyncDescriptor(ConfigurationService));
J
Joao Moreno 已提交
82
	services.set(IRequestService, new SyncDescriptor(RequestService));
J
Joao Moreno 已提交
83

J
Joao Moreno 已提交
84
	const windowsChannel = server.getChannel('windows', { routeCall: mainRoute, routeEvent: mainRoute });
J
Joao Moreno 已提交
85 86
	const windowsService = new WindowsChannelClient(windowsChannel);
	services.set(IWindowsService, windowsService);
S
Sandeep Somavarapu 已提交
87

J
Joao Moreno 已提交
88
	const activeWindowManager = new ActiveWindowManager(windowsService);
J
Joao Moreno 已提交
89
	const route = () => activeWindowManager.getActiveClientId();
90

J
Joao Moreno 已提交
91
	const dialogChannel = server.getChannel('dialog', { routeCall: route, routeEvent: route });
92
	services.set(IDialogService, new DialogChannelClient(dialogChannel));
S
Sandeep Somavarapu 已提交
93

94
	const downloadChannel = server.getChannel('download', { routeCall: route, routeEvent: route });
95
	services.set(IDownloadService, new DownloadServiceChannelClient(downloadChannel, DefaultURITransformer));
96

J
Joao Moreno 已提交
97 98 99
	const instantiationService = new InstantiationService(services);

	instantiationService.invokeFunction(accessor => {
100
		const services = new ServiceCollection();
101
		const environmentService = accessor.get(IEnvironmentService);
102
		const { appRoot, extensionsPath, extensionDevelopmentPath, isBuilt, installSourcePath } = environmentService;
103 104 105 106 107 108 109 110
		const telemetryLogService = new FollowerLogService(logLevelClient, createSpdLogService('telemetry', initData.logLevel, environmentService.logsPath));

		let appInsightsAppender: ITelemetryAppender = NullAppender;
		if (product.aiConfig && product.aiConfig.asimovKey && isBuilt) {
			appInsightsAppender = new AppInsightsAppender(eventPrefix, null, product.aiConfig.asimovKey, telemetryLogService);
			disposables.push(appInsightsAppender); // Ensure the AI appender is disposed so that it flushes remaining data
		}
		server.registerChannel('telemetryAppender', new TelemetryAppenderChannel(appInsightsAppender));
111

112
		if (!extensionDevelopmentPath && !environmentService.args['disable-telemetry'] && product.enableTelemetry) {
113
			const config: ITelemetryServiceConfig = {
114
				appender: combinedAppender(appInsightsAppender, new LogAppender(logService)),
115
				commonProperties: resolveCommonProperties(product.commit, pkg.version, configuration.machineId, installSourcePath),
116 117 118 119 120 121 122 123
				piiPaths: [appRoot, extensionsPath]
			};

			services.set(ITelemetryService, new SyncDescriptor(TelemetryService, config));
		} else {
			services.set(ITelemetryService, NullTelemetryService);
		}

124 125
		services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService));
		services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService));
S
Sandeep Somavarapu 已提交
126
		services.set(ILocalizationsService, new SyncDescriptor(LocalizationsService));
127

128 129 130 131
		const instantiationService2 = instantiationService.createChild(services);

		instantiationService2.invokeFunction(accessor => {
			const extensionManagementService = accessor.get(IExtensionManagementService);
132
			const channel = new ExtensionManagementChannel(extensionManagementService);
133
			server.registerChannel('extensions', channel);
J
Joao Moreno 已提交
134

135 136
			// clean up deprecated extensions
			(extensionManagementService as ExtensionManagementService).removeDeprecatedExtensions();
137

S
Sandeep Somavarapu 已提交
138 139 140 141
			const localizationsService = accessor.get(ILocalizationsService);
			const localizationsChannel = new LocalizationsChannel(localizationsService);
			server.registerChannel('localizations', localizationsChannel);

142
			createSharedProcessContributions(instantiationService2);
S
Sandeep Somavarapu 已提交
143
			disposables.push(extensionManagementService as ExtensionManagementService);
144
		});
J
Joao Moreno 已提交
145
	});
E
Erich Gamma 已提交
146 147 148 149
}

function setupIPC(hook: string): TPromise<Server> {
	function setup(retry: boolean): TPromise<Server> {
R
Ron Buckton 已提交
150
		return serve(hook).then(null, err => {
E
Erich Gamma 已提交
151 152 153 154 155 156
			if (!retry || platform.isWindows || err.code !== 'EADDRINUSE') {
				return TPromise.wrapError(err);
			}

			// should retry, not windows and eaddrinuse

157
			return connect(hook, '').then(
E
Erich Gamma 已提交
158 159 160 161 162 163 164 165 166 167 168 169 170 171
				client => {
					// we could connect to a running instance. this is not good, abort
					client.dispose();
					return TPromise.wrapError(new Error('There is an instance already running.'));
				},
				err => {
					// it happens on Linux and OS X that the pipe is left behind
					// let's delete it, since we can't connect to it
					// and the retry the whole thing
					try {
						fs.unlinkSync(hook);
					} catch (e) {
						return TPromise.wrapError(new Error('Error deleting the shared ipc hook.'));
					}
S
Sandeep Somavarapu 已提交
172

E
Erich Gamma 已提交
173 174 175 176 177 178 179 180 181
					return setup(false);
				}
			);
		});
	}

	return setup(true);
}

182
function startHandshake(): TPromise<ISharedProcessInitData> {
J
Joao Moreno 已提交
183
	return new TPromise<ISharedProcessInitData>((c, e) => {
M
Matt Bierner 已提交
184
		ipcRenderer.once('handshake:hey there', (_: any, r: ISharedProcessInitData) => c(r));
185
		ipcRenderer.send('handshake:hello');
E
Erich Gamma 已提交
186 187 188
	});
}

189
function handshake(configuration: ISharedProcessConfiguration): TPromise<void> {
190
	return startHandshake()
191
		.then(data => setupIPC(data.sharedIPCHandle).then(server => main(server, data, configuration)))
192
		.then(() => ipcRenderer.send('handshake:im ready'));
193
}