提交 072c0aef 编写于 作者: J Joao Moreno

add telemetry service to main process, for update

上级 2aa270d1
......@@ -47,8 +47,13 @@ import { getPathLabel } from 'vs/base/common/labels';
import { IURLService } from 'vs/platform/url/common/url';
import { URLChannel } from 'vs/platform/url/common/urlIpc';
import { URLService } from 'vs/platform/url/electron-main/urlService';
import { ITelemetryService, NullTelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { ITelemetryAppenderChannel, TelemetryAppenderClient } from 'vs/platform/telemetry/common/telemetryIpc';
import { TelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService';
import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties';
import { getDelayedChannel } from 'vs/base/parts/ipc/common/ipc';
import product from 'vs/platform/product';
import pkg from 'vs/platform/package';
import * as fs from 'original-fs';
import * as cp from 'child_process';
import * as path from 'path';
......@@ -73,6 +78,7 @@ function quit(accessor: ServicesAccessor, arg?: any) {
process.exit(exitCode); // in main, process.exit === app.exit
}
// TODO@Joao wow this is huge, clean up!
function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: platform.IProcessEnvironment): void {
const instantiationService = accessor.get(IInstantiationService);
const logService = accessor.get(ILogService);
......@@ -130,10 +136,6 @@ function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: platfo
const electronIpcServer = new ElectronIPCServer();
// Register Electron IPC services
const updateService = accessor.get(IUpdateService);
const updateChannel = new UpdateChannel(updateService);
electronIpcServer.registerChannel('update', updateChannel);
const urlService = accessor.get(IURLService);
const urlChannel = instantiationService.createInstance(URLChannel, urlService);
electronIpcServer.registerChannel('url', urlChannel);
......@@ -151,123 +153,150 @@ function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: platfo
let sharedProcessDisposable;
spawnSharedProcess(initData, options).done(disposable => {
const sharedProcess = spawnSharedProcess(initData, options).then(disposable => {
sharedProcessDisposable = disposable;
connect(environmentService.sharedIPCHandle, 'main')
.done(client => client.registerChannel('windowEvent', windowEventChannel));
return connect(environmentService.sharedIPCHandle, 'main');
});
// Make sure we associate the program with the app user model id
// This will help Windows to associate the running program with
// any shortcut that is pinned to the taskbar and prevent showing
// two icons in the taskbar for the same app.
if (platform.isWindows && product.win32AppUserModelId) {
app.setAppUserModelId(product.win32AppUserModelId);
// Create a new service collection, because the telemetry service
// requires a connection to shared process, which was only established
// now.
const services = new ServiceCollection();
services.set(IUpdateService, new SyncDescriptor(UpdateService));
if (environmentService.isBuilt && !environmentService.extensionDevelopmentPath && !!product.enableTelemetry) {
const channel = getDelayedChannel<ITelemetryAppenderChannel>(sharedProcess.then(c => c.getChannel('telemetryAppender')));
const appender = new TelemetryAppenderClient(channel);
const commonProperties = resolveCommonProperties(product.commit, pkg.version);
const piiPaths = [environmentService.appRoot, environmentService.extensionsPath];
const config: ITelemetryServiceConfig = { appender, commonProperties, piiPaths };
services.set(ITelemetryService, new SyncDescriptor(TelemetryService, config));
} else {
services.set(ITelemetryService, NullTelemetryService);
}
function dispose() {
if (mainIpcServer) {
mainIpcServer.dispose();
mainIpcServer = null;
}
const instantiationService2 = instantiationService.createChild(services);
if (sharedProcessDisposable) {
sharedProcessDisposable.dispose();
}
instantiationService2.invokeFunction(accessor => {
// Register more Electron IPC services
const updateService = accessor.get(IUpdateService);
const updateChannel = new UpdateChannel(updateService);
electronIpcServer.registerChannel('update', updateChannel);
if (windowsMutex) {
windowsMutex.release();
}
// Register windowEvent
sharedProcess.done(client => client.registerChannel('windowEvent', windowEventChannel));
configurationService.dispose();
}
// Make sure we associate the program with the app user model id
// This will help Windows to associate the running program with
// any shortcut that is pinned to the taskbar and prevent showing
// two icons in the taskbar for the same app.
if (platform.isWindows && product.win32AppUserModelId) {
app.setAppUserModelId(product.win32AppUserModelId);
}
// Dispose on app quit
app.on('will-quit', () => {
logService.log('App#will-quit: disposing resources');
function dispose() {
if (mainIpcServer) {
mainIpcServer.dispose();
mainIpcServer = null;
}
dispose();
});
if (sharedProcessDisposable) {
sharedProcessDisposable.dispose();
}
// Dispose on vscode:exit
ipc.on('vscode:exit', (event, code: number) => {
logService.log('IPC#vscode:exit', code);
if (windowsMutex) {
windowsMutex.release();
}
dispose();
process.exit(code); // in main, process.exit === app.exit
});
configurationService.dispose();
}
// Lifecycle
lifecycleService.ready();
// Dispose on app quit
app.on('will-quit', () => {
logService.log('App#will-quit: disposing resources');
// Propagate to clients
windowsMainService.ready(userEnv);
dispose();
});
// Install Menu
const menu = instantiationService.createInstance(VSCodeMenu);
menu.ready();
// Dispose on vscode:exit
ipc.on('vscode:exit', (event, code: number) => {
logService.log('IPC#vscode:exit', code);
// Install JumpList on Windows
if (platform.isWindows) {
const jumpList: Electron.JumpListCategory[] = [];
// Tasks
jumpList.push({
type: 'tasks',
items: [
{
type: 'task',
title: nls.localize('newWindow', "New Window"),
description: nls.localize('newWindowDesc', "Opens a new window"),
program: process.execPath,
args: '-n', // force new window
iconPath: process.execPath,
iconIndex: 0
}
]
dispose();
process.exit(code); // in main, process.exit === app.exit
});
// Recent Folders
const folders = windowsMainService.getRecentPathsList().folders;
if (folders.length > 0) {
// Lifecycle
lifecycleService.ready();
// Propagate to clients
windowsMainService.ready(userEnv);
// Install Menu
const menu = instantiationService2.createInstance(VSCodeMenu);
menu.ready();
// Install JumpList on Windows
if (platform.isWindows) {
const jumpList: Electron.JumpListCategory[] = [];
// Tasks
jumpList.push({
type: 'custom',
name: 'Recent Folders',
items: windowsMainService.getRecentPathsList().folders.slice(0, 7 /* limit number of entries here */).map(folder => {
return <Electron.JumpListItem>{
type: 'tasks',
items: [
{
type: 'task',
title: getPathLabel(folder),
description: nls.localize('folderDesc', "{0} {1}", path.basename(folder), getPathLabel(path.dirname(folder))),
title: nls.localize('newWindow', "New Window"),
description: nls.localize('newWindowDesc', "Opens a new window"),
program: process.execPath,
args: folder, // open folder,
iconPath: 'explorer.exe', // simulate folder icon
args: '-n', // force new window
iconPath: process.execPath,
iconIndex: 0
};
})
}
]
});
}
// Recent
jumpList.push({
type: 'recent' // this enables to show files in the "recent" category
});
// Recent Folders
const folders = windowsMainService.getRecentPathsList().folders;
if (folders.length > 0) {
jumpList.push({
type: 'custom',
name: 'Recent Folders',
items: windowsMainService.getRecentPathsList().folders.slice(0, 7 /* limit number of entries here */).map(folder => {
return <Electron.JumpListItem>{
type: 'task',
title: getPathLabel(folder),
description: nls.localize('folderDesc', "{0} {1}", path.basename(folder), getPathLabel(path.dirname(folder))),
program: process.execPath,
args: folder, // open folder,
iconPath: 'explorer.exe', // simulate folder icon
iconIndex: 0
};
})
});
}
try {
app.setJumpList(jumpList);
} catch (error) {
logService.log('#setJumpList', error); // since setJumpList is relatively new API, make sure to guard for errors
// Recent
jumpList.push({
type: 'recent' // this enables to show files in the "recent" category
});
try {
app.setJumpList(jumpList);
} catch (error) {
logService.log('#setJumpList', error); // since setJumpList is relatively new API, make sure to guard for errors
}
}
}
// Open our first window
if (environmentService.args['new-window'] && environmentService.args._.length === 0) {
windowsMainService.open({ cli: environmentService.args, forceNewWindow: true, forceEmpty: true }); // new window if "-n" was used without paths
} else if (global.macOpenFiles && global.macOpenFiles.length && (!environmentService.args._ || !environmentService.args._.length)) {
windowsMainService.open({ cli: environmentService.args, pathsToOpen: global.macOpenFiles }); // mac: open-file event received on startup
} else {
windowsMainService.open({ cli: environmentService.args, forceNewWindow: environmentService.args['new-window'], diffMode: environmentService.args.diff }); // default: read paths from cli
}
// Open our first window
if (environmentService.args['new-window'] && environmentService.args._.length === 0) {
windowsMainService.open({ cli: environmentService.args, forceNewWindow: true, forceEmpty: true }); // new window if "-n" was used without paths
} else if (global.macOpenFiles && global.macOpenFiles.length && (!environmentService.args._ || !environmentService.args._.length)) {
windowsMainService.open({ cli: environmentService.args, pathsToOpen: global.macOpenFiles }); // mac: open-file event received on startup
} else {
windowsMainService.open({ cli: environmentService.args, forceNewWindow: environmentService.args['new-window'], diffMode: environmentService.args.diff }); // default: read paths from cli
}
});
}
function setupIPC(accessor: ServicesAccessor): TPromise<Server> {
......@@ -437,19 +466,7 @@ function createPaths(environmentService: IEnvironmentService): TPromise<any> {
return TPromise.join(paths.map(p => mkdirp(p))) as TPromise<any>;
}
function start(): void {
let args: ParsedArgs;
try {
args = parseMainProcessArgv(process.argv);
args = validatePaths(args);
} catch (err) {
console.error(err.message);
process.exit(1);
return;
}
// TODO: isolate
function createServices(args): IInstantiationService {
const services = new ServiceCollection();
services.set(IEnvironmentService, new SyncDescriptor(EnvironmentService, args, process.execPath));
......@@ -460,10 +477,24 @@ function start(): void {
services.set(IStorageService, new SyncDescriptor(StorageService));
services.set(IConfigurationService, new SyncDescriptor(ConfigurationService));
services.set(IRequestService, new SyncDescriptor(RequestService));
services.set(IUpdateService, new SyncDescriptor(UpdateService));
services.set(IURLService, new SyncDescriptor(URLService, args['open-url']));
const instantiationService = new InstantiationService(services);
return new InstantiationService(services);
}
function start(): void {
let args: ParsedArgs;
try {
args = parseMainProcessArgv(process.argv);
args = validatePaths(args);
} catch (err) {
console.error(err.message);
process.exit(1);
return;
}
const instantiationService = createServices(args);
// On some platforms we need to manually read from the global environment variables
// and assign them to the process environment (e.g. when doubleclick app on Mac)
......
......@@ -18,20 +18,10 @@ import { Win32AutoUpdaterImpl } from './auto-updater.win32';
import { LinuxAutoUpdaterImpl } from './auto-updater.linux';
import { ILifecycleService } from 'vs/code/electron-main/lifecycle';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IRequestService } from 'vs/platform/request/common/request';
import product from 'vs/platform/product';
import { TPromise } from 'vs/base/common/winjs.base';
import { IUpdateService, State, IAutoUpdater, IUpdate, IRawUpdate } from 'vs/platform/update/common/update';
// TODO@Joao: add telemetry
//
// this.updateService.onUpdateReady(update => {
// this.sendToFocused('vscode:telemetry', { eventName: 'update:downloaded', data: { version: update.version } });
// });
// this.updateService.onUpdateNotAvailable(explicit => {
// this.sendToFocused('vscode:telemetry', { eventName: 'update:notAvailable', data: { explicit } });
// });
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
export class UpdateService implements IUpdateService {
......@@ -97,7 +87,7 @@ export class UpdateService implements IUpdateService {
@IInstantiationService instantiationService: IInstantiationService,
@ILifecycleService private lifecycleService: ILifecycleService,
@IConfigurationService private configurationService: IConfigurationService,
@IRequestService requestService: IRequestService
@ITelemetryService private telemetryService: ITelemetryService
) {
if (process.platform === 'win32') {
this.raw = instantiationService.createInstance(Win32AutoUpdaterImpl);
......@@ -109,6 +99,8 @@ export class UpdateService implements IUpdateService {
return;
}
telemetryService.publicLog('whattt', { yeah: 123 });
const channel = this.getUpdateChannel();
const feedUrl = this.getUpdateFeedUrl(channel);
......@@ -167,6 +159,7 @@ export class UpdateService implements IUpdateService {
if (!update) {
this._onUpdateNotAvailable.fire(explicit);
this.state = State.Idle;
this.telemetryService.publicLog('update:notAvailable', { explicit });
} else if (update.url) {
const data: IUpdate = {
......@@ -190,6 +183,7 @@ export class UpdateService implements IUpdateService {
this._availableUpdate = data;
this._onUpdateReady.fire(data);
this.state = State.UpdateDownloaded;
this.telemetryService.publicLog('update:downloaded', { version: update.version });
}
return update;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册