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

import * as fs from 'fs';
7
import * as platform from 'vs/base/common/platform';
8 9
import product from 'vs/platform/product/node/product';
import pkg from 'vs/platform/product/node/package';
J
Joao Moreno 已提交
10
import { serve, Server, connect } from 'vs/base/parts/ipc/node/ipc.net';
J
Joao Moreno 已提交
11 12 13
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 已提交
14 15
import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment';
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
J
Joao Moreno 已提交
16
import { ExtensionManagementChannel } from 'vs/platform/extensionManagement/node/extensionManagementIpc';
17
import { IExtensionManagementService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement';
J
Joao Moreno 已提交
18
import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
19
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService';
J
Joao Moreno 已提交
20
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
21
import { ConfigurationService } from 'vs/platform/configuration/node/configurationService';
J
Joao Moreno 已提交
22
import { IRequestService } from 'vs/platform/request/node/request';
23
import { RequestService } from 'vs/platform/request/electron-browser/requestService';
24
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
25
import { combinedAppender, NullTelemetryService, ITelemetryAppender, NullAppender, LogAppender } from 'vs/platform/telemetry/common/telemetryUtils';
26
import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties';
J
Joao Moreno 已提交
27
import { TelemetryAppenderChannel } from 'vs/platform/telemetry/node/telemetryIpc';
28
import { TelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService';
29
import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppender';
J
Joao Moreno 已提交
30
import { IWindowsService, ActiveWindowManager } from 'vs/platform/windows/common/windows';
31
import { WindowsService } from 'vs/platform/windows/electron-browser/windowsService';
32
import { ipcRenderer } from 'electron';
S
Sandeep Somavarapu 已提交
33
import { ILogService, LogLevel } from 'vs/platform/log/common/log';
34
import { LogLevelSetterChannelClient, FollowerLogService } from 'vs/platform/log/common/logIpc';
S
Sandeep Somavarapu 已提交
35 36
import { LocalizationsService } from 'vs/platform/localizations/node/localizations';
import { ILocalizationsService } from 'vs/platform/localizations/common/localizations';
J
Joao Moreno 已提交
37 38
import { LocalizationsChannel } from 'vs/platform/localizations/node/localizationsIpc';
import { DialogChannelClient } from 'vs/platform/dialogs/node/dialogIpc';
39
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
40
import { combinedDisposable, DisposableStore } from 'vs/base/common/lifecycle';
S
Sandeep Somavarapu 已提交
41
import { DownloadService } from 'vs/platform/download/node/downloadService';
42
import { IDownloadService } from 'vs/platform/download/common/download';
A
Alex Dima 已提交
43
import { IChannel, IServerChannel, StaticRouter } from 'vs/base/parts/ipc/common/ipc';
S
Sandeep Somavarapu 已提交
44 45 46 47
import { NodeCachedDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/nodeCachedDataCleaner';
import { LanguagePackCachedDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/languagePackCachedDataCleaner';
import { StorageDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/storageDataCleaner';
import { LogsDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/logsDataCleaner';
48 49
import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService';
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
50
import { SpdLogService } from 'vs/platform/log/node/spdlogService';
51 52 53
import { DiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsService';
import { IDiagnosticsService } from 'vs/platform/diagnostics/common/diagnosticsService';
import { DiagnosticsChannel } from 'vs/platform/diagnostics/node/diagnosticsIpc';
54

55
export interface ISharedProcessConfiguration {
B
Benjamin Pasero 已提交
56
	readonly machineId: string;
57 58 59 60 61 62
}

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

63
interface ISharedProcessInitData {
64
	sharedIPCHandle: string;
J
Joao Moreno 已提交
65
	args: ParsedArgs;
S
Sandeep Somavarapu 已提交
66
	logLevel: LogLevel;
E
Erich Gamma 已提交
67 68
}

69 70
const eventPrefix = 'monacoworkbench';

71 72 73 74 75 76 77 78 79 80 81 82 83 84
class MainProcessService implements IMainProcessService {
	constructor(private server: Server, private mainRouter: StaticRouter) { }

	_serviceBrand: ServiceIdentifier<any>;

	getChannel(channelName: string): IChannel {
		return this.server.getChannel(channelName, this.mainRouter);
	}

	registerChannel(channelName: string, channel: IServerChannel<string>): void {
		this.server.registerChannel(channelName, channel);
	}
}

S
Sandeep Somavarapu 已提交
85
async function main(server: Server, initData: ISharedProcessInitData, configuration: ISharedProcessConfiguration): Promise<void> {
J
Joao Moreno 已提交
86
	const services = new ServiceCollection();
J
Joao Moreno 已提交
87

88
	const disposables = new DisposableStore();
J
Joao Moreno 已提交
89

90
	const onExit = () => disposables.dispose();
J
Joao Moreno 已提交
91 92 93
	process.once('exit', onExit);
	ipcRenderer.once('handshake:goodbye', onExit);

94
	disposables.add(server);
E
Erich Gamma 已提交
95

96
	const environmentService = new EnvironmentService(initData.args, process.execPath);
J
Joao Moreno 已提交
97 98 99

	const mainRouter = new StaticRouter(ctx => ctx === 'main');
	const logLevelClient = new LogLevelSetterChannelClient(server.getChannel('loglevel', mainRouter));
100
	const logService = new FollowerLogService(logLevelClient, new SpdLogService('sharedprocess', environmentService.logsPath, initData.logLevel));
101
	disposables.add(logService);
102 103
	logService.info('main', JSON.stringify(configuration));

S
Sandeep Somavarapu 已提交
104
	const configurationService = new ConfigurationService(environmentService.settingsResource);
105
	disposables.add(configurationService);
S
Sandeep Somavarapu 已提交
106 107
	await configurationService.initialize();

108 109
	services.set(IEnvironmentService, environmentService);
	services.set(ILogService, logService);
S
Sandeep Somavarapu 已提交
110
	services.set(IConfigurationService, configurationService);
J
Joao Moreno 已提交
111
	services.set(IRequestService, new SyncDescriptor(RequestService));
S
Sandeep Somavarapu 已提交
112
	services.set(IDownloadService, new SyncDescriptor(DownloadService));
J
Joao Moreno 已提交
113

114 115 116 117
	const mainProcessService = new MainProcessService(server, mainRouter);
	services.set(IMainProcessService, mainProcessService);

	const windowsService = new WindowsService(mainProcessService);
J
Joao Moreno 已提交
118
	services.set(IWindowsService, windowsService);
S
Sandeep Somavarapu 已提交
119

J
Joao Moreno 已提交
120
	const activeWindowManager = new ActiveWindowManager(windowsService);
J
Joao Moreno 已提交
121 122
	const activeWindowRouter = new StaticRouter(ctx => activeWindowManager.getActiveClientId().then(id => ctx === id));
	const dialogChannel = server.getChannel('dialog', activeWindowRouter);
123
	services.set(IDialogService, new DialogChannelClient(dialogChannel));
S
Sandeep Somavarapu 已提交
124

J
Joao Moreno 已提交
125 126
	const instantiationService = new InstantiationService(services);

127
	let telemetryService: ITelemetryService;
J
Joao Moreno 已提交
128
	instantiationService.invokeFunction(accessor => {
129
		const services = new ServiceCollection();
130
		const environmentService = accessor.get(IEnvironmentService);
131
		const { appRoot, extensionsPath, extensionDevelopmentLocationURI: extensionDevelopmentLocationURI, isBuilt, installSourcePath } = environmentService;
132
		const telemetryLogService = new FollowerLogService(logLevelClient, new SpdLogService('telemetry', environmentService.logsPath, initData.logLevel));
133 134
		telemetryLogService.info('The below are logs for every telemetry event sent from VS Code once the log level is set to trace.');
		telemetryLogService.info('===========================================================');
135

136
		let appInsightsAppender: ITelemetryAppender | null = NullAppender;
137
		if (!extensionDevelopmentLocationURI && !environmentService.args['disable-telemetry'] && product.enableTelemetry) {
138 139
			if (product.aiConfig && product.aiConfig.asimovKey && isBuilt) {
				appInsightsAppender = new AppInsightsAppender(eventPrefix, null, product.aiConfig.asimovKey, telemetryLogService);
140
				disposables.add(appInsightsAppender); // Ensure the AI appender is disposed so that it flushes remaining data
141
			}
142
			const config: ITelemetryServiceConfig = {
143
				appender: combinedAppender(appInsightsAppender, new LogAppender(logService)),
144
				commonProperties: resolveCommonProperties(product.commit, pkg.version, configuration.machineId, installSourcePath),
145 146 147
				piiPaths: [appRoot, extensionsPath]
			};

148 149
			telemetryService = new TelemetryService(config, configurationService);
			services.set(ITelemetryService, telemetryService);
150
		} else {
151
			telemetryService = NullTelemetryService;
152 153
			services.set(ITelemetryService, NullTelemetryService);
		}
154
		server.registerChannel('telemetryAppender', new TelemetryAppenderChannel(appInsightsAppender));
155

156
		services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService));
157
		services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService));
S
Sandeep Somavarapu 已提交
158
		services.set(ILocalizationsService, new SyncDescriptor(LocalizationsService));
159
		services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService));
160

161 162 163
		const instantiationService2 = instantiationService.createChild(services);

		instantiationService2.invokeFunction(accessor => {
A
Tweaks  
Alex Dima 已提交
164

165
			const extensionManagementService = accessor.get(IExtensionManagementService);
166
			const channel = new ExtensionManagementChannel(extensionManagementService, () => null);
167
			server.registerChannel('extensions', channel);
J
Joao Moreno 已提交
168

S
Sandeep Somavarapu 已提交
169 170 171 172
			const localizationsService = accessor.get(ILocalizationsService);
			const localizationsChannel = new LocalizationsChannel(localizationsService);
			server.registerChannel('localizations', localizationsChannel);

173 174 175 176
			const diagnosticsService = accessor.get(IDiagnosticsService);
			const diagnosticsChannel = new DiagnosticsChannel(diagnosticsService);
			server.registerChannel('diagnostics', diagnosticsChannel);

177 178 179 180 181
			// clean up deprecated extensions
			(extensionManagementService as ExtensionManagementService).removeDeprecatedExtensions();
			// update localizations cache
			(localizationsService as LocalizationsService).update();
			// cache clean ups
182
			disposables.add(combinedDisposable(
S
Sandeep Somavarapu 已提交
183 184 185 186
				instantiationService2.createInstance(NodeCachedDataCleaner),
				instantiationService2.createInstance(LanguagePackCachedDataCleaner),
				instantiationService2.createInstance(StorageDataCleaner),
				instantiationService2.createInstance(LogsDataCleaner)
187
			));
188
			disposables.add(extensionManagementService as ExtensionManagementService);
189
		});
J
Joao Moreno 已提交
190
	});
E
Erich Gamma 已提交
191 192
}

J
Johannes Rieken 已提交
193 194
function setupIPC(hook: string): Promise<Server> {
	function setup(retry: boolean): Promise<Server> {
R
Ron Buckton 已提交
195
		return serve(hook).then(null, err => {
E
Erich Gamma 已提交
196
			if (!retry || platform.isWindows || err.code !== 'EADDRINUSE') {
J
Joao Moreno 已提交
197
				return Promise.reject(err);
E
Erich Gamma 已提交
198 199 200 201
			}

			// should retry, not windows and eaddrinuse

202
			return connect(hook, '').then(
E
Erich Gamma 已提交
203 204 205
				client => {
					// we could connect to a running instance. this is not good, abort
					client.dispose();
J
Joao Moreno 已提交
206
					return Promise.reject(new Error('There is an instance already running.'));
E
Erich Gamma 已提交
207 208 209 210 211 212 213 214
				},
				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) {
J
Joao Moreno 已提交
215
						return Promise.reject(new Error('Error deleting the shared ipc hook.'));
E
Erich Gamma 已提交
216
					}
S
Sandeep Somavarapu 已提交
217

E
Erich Gamma 已提交
218 219 220 221 222 223 224 225 226
					return setup(false);
				}
			);
		});
	}

	return setup(true);
}

227 228
async function handshake(configuration: ISharedProcessConfiguration): Promise<void> {
	const data = await new Promise<ISharedProcessInitData>(c => {
M
Matt Bierner 已提交
229
		ipcRenderer.once('handshake:hey there', (_: any, r: ISharedProcessInitData) => c(r));
230
		ipcRenderer.send('handshake:hello');
E
Erich Gamma 已提交
231 232
	});

233 234
	const server = await setupIPC(data.sharedIPCHandle);

S
Sandeep Somavarapu 已提交
235
	await main(server, data, configuration);
236
	ipcRenderer.send('handshake:im ready');
237
}