Skip to content

Commit fe33ef7

Browse files
committed
wip: url service
1 parent dccf029 commit fe33ef7

8 files changed

Lines changed: 118 additions & 61 deletions

File tree

src/vs/base/parts/ipc/common/ipc.electron.ts

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,33 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import { IDisposable, toDisposable, dispose } from 'vs/base/common/lifecycle';
7-
import { TPromise } from 'vs/base/common/winjs.base';
87
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
98
import { Server as IPCServer, Client as IPCClient, IServer, IClient, IChannel } from 'vs/base/parts/ipc/common/ipc';
109

1110
const Hello = 'ipc:hello';
1211
const Goodbye = 'ipc:goodbye';
1312
const Message = 'ipc:message';
1413

15-
export interface IPC extends NodeJS.EventEmitter {
14+
export interface Sender {
1615
send(channel: string, ...args: any[]): void;
1716
}
1817

18+
export interface IPC extends Sender, NodeJS.EventEmitter {}
19+
1920
class Protocol implements IMessagePassingProtocol {
2021

2122
private listener: IDisposable;
2223

23-
constructor(private ipc: IPC) {}
24+
constructor(private sender: Sender, private receiver: NodeJS.EventEmitter) {}
2425

2526
send(message: any): void {
26-
this.ipc.send(Message, message);
27+
this.sender.send(Message, message);
2728
}
2829

2930
onMessage(callback: (message: any) => void): void {
3031
const cb = (_, m) => callback(m);
31-
this.ipc.on(Message, cb);
32-
this.listener = toDisposable(() => this.ipc.removeListener(Message, cb));
32+
this.receiver.on(Message, cb);
33+
this.listener = toDisposable(() => this.receiver.removeListener(Message, cb));
3334
}
3435

3536
dispose(): void {
@@ -41,11 +42,11 @@ export class Server implements IServer, IDisposable {
4142

4243
private channels: { [name: string]: IChannel };
4344

44-
constructor(ipc: IPC) {
45+
constructor(ipc: NodeJS.EventEmitter) {
4546
this.channels = Object.create(null);
4647

4748
ipc.on(Hello, ({ sender }) => {
48-
const protocol = new Protocol(sender);
49+
const protocol = new Protocol(sender, ipc);
4950
const ipcServer = new IPCServer(protocol);
5051

5152
Object.keys(this.channels)
@@ -55,8 +56,6 @@ export class Server implements IServer, IDisposable {
5556
ipcServer.dispose();
5657
protocol.dispose();
5758
});
58-
59-
sender.send(Hello);
6059
});
6160
}
6261

@@ -75,7 +74,8 @@ export class Client implements IClient, IDisposable {
7574
private ipcClient: IPCClient;
7675

7776
constructor(private ipc: IPC) {
78-
this.protocol = new Protocol(ipc);
77+
ipc.send(Hello);
78+
this.protocol = new Protocol(ipc, ipc);
7979
this.ipcClient = new IPCClient(this.protocol);
8080
}
8181

@@ -87,16 +87,4 @@ export class Client implements IClient, IDisposable {
8787
this.ipc.send(Goodbye);
8888
this.protocol = dispose(this.protocol);
8989
}
90-
}
91-
92-
export function connect(ipc: IPC): TPromise<Client> {
93-
return new TPromise<Client>((c, e) => {
94-
ipc.once(Hello, () => {
95-
ipc.removeListener('error', e);
96-
c(new Client(ipc));
97-
});
98-
99-
ipc.once('error', e);
100-
ipc.send(Hello);
101-
});
10290
}

src/vs/code/electron-main/main.ts

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { ILifecycleService, LifecycleService } from 'vs/code/electron-main/lifec
1616
import { VSCodeMenu } from 'vs/code/electron-main/menus';
1717
import { ISettingsService, SettingsManager } from 'vs/code/electron-main/settings';
1818
import { IUpdateService, UpdateManager } from 'vs/code/electron-main/update-manager';
19+
import { Server as ElectronIPCServer } from 'vs/base/parts/ipc/common/ipc.electron';
1920
import { Server, serve, connect } from 'vs/base/parts/ipc/node/ipc.net';
2021
import { TPromise } from 'vs/base/common/winjs.base';
2122
import { AskpassChannel } from 'vs/workbench/parts/git/common/gitIpc';
@@ -31,6 +32,8 @@ import { ILogService, MainLogService } from 'vs/code/electron-main/log';
3132
import { IStorageService, StorageService } from 'vs/code/electron-main/storage';
3233
import * as cp from 'child_process';
3334
import { generateUuid } from 'vs/base/common/uuid';
35+
import { URLChannel } from 'vs/platform/url/common/urlIpc';
36+
import { URLService } from 'vs/platform/url/electron-main/urlService';
3437

3538
function quit(accessor: ServicesAccessor, error?: Error);
3639
function quit(accessor: ServicesAccessor, message?: string);
@@ -52,7 +55,7 @@ function quit(accessor: ServicesAccessor, arg?: any) {
5255
process.exit(exitCode); // in main, process.exit === app.exit
5356
}
5457

55-
function main(accessor: ServicesAccessor, ipcServer: Server, userEnv: IProcessEnvironment): void {
58+
function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: IProcessEnvironment): void {
5659
const instantiationService = accessor.get(IInstantiationService);
5760
const logService = accessor.get(ILogService);
5861
const envService = accessor.get(IEnvironmentService);
@@ -93,14 +96,22 @@ function main(accessor: ServicesAccessor, ipcServer: Server, userEnv: IProcessEn
9396
// noop
9497
}
9598

96-
// Register IPC services
99+
// Register Main IPC services
97100
const launchService = instantiationService.createInstance(LaunchService);
98101
const launchChannel = new LaunchChannel(launchService);
99-
ipcServer.registerChannel('launch', launchChannel);
102+
mainIpcServer.registerChannel('launch', launchChannel);
100103

101104
const askpassService = new GitAskpassService();
102105
const askpassChannel = new AskpassChannel(askpassService);
103-
ipcServer.registerChannel('askpass', askpassChannel);
106+
mainIpcServer.registerChannel('askpass', askpassChannel);
107+
108+
// Create Electron IPC Server
109+
const electronIpcServer = new ElectronIPCServer(ipc);
110+
111+
// Register Electron IPC services
112+
const urlService = instantiationService.createInstance(URLService);
113+
const urlChannel = new URLChannel(urlService);
114+
electronIpcServer.registerChannel('url', urlChannel);
104115

105116
// Used by sub processes to communicate back to the main instance
106117
process.env['VSCODE_PID'] = '' + process.pid;
@@ -125,9 +136,9 @@ function main(accessor: ServicesAccessor, ipcServer: Server, userEnv: IProcessEn
125136
global.programStart = envService.cliArgs.programStart;
126137

127138
function dispose() {
128-
if (ipcServer) {
129-
ipcServer.dispose();
130-
ipcServer = null;
139+
if (mainIpcServer) {
140+
mainIpcServer.dispose();
141+
mainIpcServer = null;
131142
}
132143

133144
sharedProcess.dispose();
@@ -144,12 +155,6 @@ function main(accessor: ServicesAccessor, ipcServer: Server, userEnv: IProcessEn
144155
dispose();
145156
});
146157

147-
app.setAsDefaultProtocolClient('vscode');
148-
149-
app.on('open-url', url => {
150-
console.log(url);
151-
});
152-
153158
// Dispose on vscode:exit
154159
ipc.on('vscode:exit', (event, code: number) => {
155160
logService.log('IPC#vscode:exit', code);
@@ -356,6 +361,6 @@ getUserEnvironment()
356361

357362
return instantiationService.invokeFunction(a => a.get(IEnvironmentService).createPaths())
358363
.then(() => instantiationService.invokeFunction(setupIPC))
359-
.then(ipcServer => instantiationService.invokeFunction(main, ipcServer, userEnv));
364+
.then(mainIpcServer => instantiationService.invokeFunction(main, mainIpcServer, userEnv));
360365
})
361366
.done(null, err => instantiationService.invokeFunction(quit, err));

src/vs/platform/url/common/url.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@ export const ID = 'urlService';
1212
export const IURLService = createDecorator<IURLService>(ID);
1313

1414
export interface IURLService {
15-
onOpenUrl: Event<string>;
15+
_serviceBrand: any;
16+
onOpenURL: Event<string>;
1617
}

src/vs/platform/url/common/urlIpc.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,35 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
'use strict';
6+
'use strict';
7+
8+
import { TPromise } from 'vs/base/common/winjs.base';
9+
import { IChannel, eventToCall, eventFromCall } from 'vs/base/parts/ipc/common/ipc';
10+
import { IURLService } from './url';
11+
import Event from 'vs/base/common/event';
12+
13+
export interface IURLChannel extends IChannel {
14+
call(command: 'event:onOpenURL'): TPromise<void>;
15+
call(command: string, arg: any): TPromise<any>;
16+
}
17+
18+
export class URLChannel implements IURLChannel {
19+
20+
constructor(private service: IURLService) { }
21+
22+
call(command: string, arg: any): TPromise<any> {
23+
switch (command) {
24+
case 'event:onOpenURL': return eventToCall(this.service.onOpenURL);
25+
}
26+
}
27+
}
28+
29+
export class URLChannelClient implements IURLService {
30+
31+
_serviceBrand: any;
32+
33+
constructor(private channel: IChannel) { }
34+
35+
private _onOpenURL = eventFromCall<string>(this.channel, 'event:onOpenURL');
36+
get onOpenURL(): Event<string> { return this._onOpenURL; }
37+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
'use strict';
7+
8+
import Event, {Emitter} from 'vs/base/common/event';
9+
import {IDisposable, dispose, toDisposable} from 'vs/base/common/lifecycle';
10+
import {IURLService} from 'vs/platform/url/common/url';
11+
import {app} from 'electron';
12+
13+
export class URLService implements IURLService, IDisposable {
14+
15+
_serviceBrand: any;
16+
17+
private _onOpenURL = new Emitter<string>();
18+
onOpenURL: Event<string> = this._onOpenURL.event;
19+
private disposables: IDisposable[] = [];
20+
21+
constructor() {
22+
const handler = (e: Electron.Event, url: string) => {
23+
e.preventDefault();
24+
this._onOpenURL.fire(url);
25+
};
26+
27+
app.on('open-url', handler);
28+
this.disposables.push(toDisposable(() => app.removeListener('open-url', handler)));
29+
30+
// app.setAsDefaultProtocolClient('vscode');
31+
}
32+
33+
dispose(): void {
34+
this.disposables = dispose(this.disposables);
35+
}
36+
}

src/vs/platform/url/node/urlService.ts

Lines changed: 0 additions & 19 deletions
This file was deleted.

src/vs/workbench/electron-browser/shell.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,13 @@ import {CrashReporter} from 'vs/workbench/electron-browser/crashReporter';
7070
import {IThemeService} from 'vs/workbench/services/themes/common/themeService';
7171
import {ThemeService} from 'vs/workbench/services/themes/electron-browser/themeService';
7272
import {getDelayedChannel} from 'vs/base/parts/ipc/common/ipc';
73-
import {connect} from 'vs/base/parts/ipc/node/ipc.net';
73+
import {connect as connectNet} from 'vs/base/parts/ipc/node/ipc.net';
74+
import {Client as ElectronIPCClient} from 'vs/base/parts/ipc/common/ipc.electron';
75+
import {ipcRenderer} from 'electron';
7476
import {IExtensionManagementChannel, ExtensionManagementChannelClient} from 'vs/platform/extensionManagement/common/extensionManagementIpc';
7577
import {IExtensionManagementService} from 'vs/platform/extensionManagement/common/extensionManagement';
78+
import {URLChannelClient} from 'vs/platform/url/common/urlIpc';
79+
import {IURLService} from 'vs/platform/url/common/url';
7680
import {ReloadWindowAction} from 'vs/workbench/electron-browser/actions';
7781

7882
// self registering services
@@ -202,7 +206,7 @@ export class WorkbenchShell {
202206
}
203207

204208
private initServiceCollection(): [InstantiationService, ServiceCollection] {
205-
const sharedProcess = connect(process.env['VSCODE_SHARED_IPC_HOOK']);
209+
const sharedProcess = connectNet(process.env['VSCODE_SHARED_IPC_HOOK']);
206210
sharedProcess.done(service => {
207211
service.onClose(() => {
208212
this.messageService.show(Severity.Error, {
@@ -212,6 +216,8 @@ export class WorkbenchShell {
212216
});
213217
}, errors.onUnexpectedError);
214218

219+
const mainProcessClient = new ElectronIPCClient(ipcRenderer);
220+
215221
const serviceCollection = new ServiceCollection();
216222
serviceCollection.set(IEventService, this.eventService);
217223
serviceCollection.set(IWorkspaceContextService, this.contextService);
@@ -314,6 +320,10 @@ export class WorkbenchShell {
314320
const extensionManagementChannelClient = instantiationService.createInstance(ExtensionManagementChannelClient, extensionManagementChannel);
315321
serviceCollection.set(IExtensionManagementService, extensionManagementChannelClient);
316322

323+
const urlChannel = mainProcessClient.getChannel('url');
324+
const urlChannelClient = instantiationService.createInstance(URLChannelClient, urlChannel);
325+
serviceCollection.set(IURLService, urlChannelClient);
326+
317327
return [instantiationService, serviceCollection];
318328
}
319329

src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchExtension.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { IWorkspaceContextService } from 'vs/workbench/services/workspace/common
1717
import { IActivityService, ProgressBadge, NumberBadge } from 'vs/workbench/services/activity/common/activityService';
1818
import { ReloadWindowAction } from 'vs/workbench/electron-browser/actions';
1919
import { ipcRenderer as ipc } from 'electron';
20+
import { IURLService } from 'vs/platform/url/common/url';
2021

2122
interface IInstallExtensionsRequest {
2223
extensionsToInstall: string[];
@@ -31,7 +32,8 @@ export class ExtensionsWorkbenchExtension implements IWorkbenchContribution {
3132
@IMessageService private messageService: IMessageService,
3233
@IWorkspaceContextService contextService: IWorkspaceContextService,
3334
@IExtensionTipsService extenstionTips: IExtensionTipsService, // this is to eagerly start the service
34-
@IExtensionGalleryService galleryService: IExtensionGalleryService
35+
@IExtensionGalleryService galleryService: IExtensionGalleryService,
36+
@IURLService urlService: IURLService
3537
) {
3638
this.registerListeners();
3739

@@ -40,6 +42,9 @@ export class ExtensionsWorkbenchExtension implements IWorkbenchContribution {
4042
if (options.extensionsToInstall && options.extensionsToInstall.length) {
4143
this.install(options.extensionsToInstall).done(null, onUnexpectedError);
4244
}
45+
46+
urlService.onOpenURL(url => console.log(url));
47+
4348
//actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(InstallExtensionAction, InstallExtensionAction.ID, InstallExtensionAction.LABEL), 'Extensions: Install Extension', ExtensionsLabel);
4449
}
4550

0 commit comments

Comments
 (0)