专栏首页liulunvscode源码分析【七】主进程启动消息通信服务

vscode源码分析【七】主进程启动消息通信服务

在mian.ts中的doStartup方法里,创建了一个命名管道服务 (src\vs\code\electron-main\main.ts)

server = await serve(environmentService.mainIPCHandle);
once(lifecycleService.onWillShutdown)(() => server.dispose());

传入的environmentService.mainIPCHandle是命名管道的识别路径, 一个有规则的字符串,规则如下:

function getWin32IPCHandle(userDataPath: string, type: string): string {
	const scope = crypto.createHash('md5').update(userDataPath).digest('hex');
	return `\\\\.\\pipe\\${scope}-${pkg.version}-${type}-sock`;
}

注意:每次启动程序,取这个字符串的时候,都会获得同样的值(而且这个值是会被缓存起来的); 以后监听消息、发送消息,都根据这个字符串来; 创建服务的代码(serve):

export function serve(hook: any): Promise<Server> {
	return new Promise<Server>((c, e) => {
		const server = createServer();
		server.on('error', e);
		server.listen(hook, () => {
			server.removeListener('error', e);
			c(new Server(server));
		});
	});
}

这个方法返回了一个Promise的对象, c和e是Promise的参数,c代表成功时的回调,e代表失败时的回调(有点类似es6的Promise) 匿名函数内createServer就是nodejs里的原生接口, Server类绑定了连接和断开的事件,暂时不细说; 回头看看main.ts startup方法里有这么一句:

instantiationService.createInstance(CodeApplication, mainIpcServer, instanceEnvironment).startup();

这句显然是创建了CodeApplication的实例,然后执行了实例的startup方法 注意:创建这个实例的时候,把我们前面创建的mainIpcServer传递进去了; CodeApplication(src\vs\code\electron-main\app.ts)的startup方法,还启动了Electron的IPCServer

const electronIpcServer = new ElectronIPCServer();

vscode把electron默认的通信机制也接入到了自己的事件体系内,有消息过来,会触发事件; 具体先不细说,后面再讲. 接着就跳转到同类型里的openFirstWindow方法(是不是很熟悉,我们在第一篇文章中讲到过这里) 在这里,给这两个服务(mainIpcServer和electronIpcServer ),创建了一堆信道:

const launchService = accessor.get(ILaunchService);
		const launchChannel = new LaunchChannel(launchService);
		this.mainIpcServer.registerChannel('launch', launchChannel);

		const updateService = accessor.get(IUpdateService);
		const updateChannel = new UpdateChannel(updateService);
		electronIpcServer.registerChannel('update', updateChannel);

		const issueService = accessor.get(IIssueService);
		const issueChannel = new IssueChannel(issueService);
		electronIpcServer.registerChannel('issue', issueChannel);

		const workspacesService = accessor.get(IWorkspacesMainService);
		const workspacesChannel = new WorkspacesChannel(workspacesService);
		electronIpcServer.registerChannel('workspaces', workspacesChannel);

		const windowsService = accessor.get(IWindowsService);
		const windowsChannel = new WindowsChannel(windowsService);
		electronIpcServer.registerChannel('windows', windowsChannel);
		sharedProcessClient.then(client => client.registerChannel('windows', windowsChannel));

		const menubarService = accessor.get(IMenubarService);
		const menubarChannel = new MenubarChannel(menubarService);
		electronIpcServer.registerChannel('menubar', menubarChannel);

		const urlService = accessor.get(IURLService);
		const urlChannel = new URLServiceChannel(urlService);
		electronIpcServer.registerChannel('url', urlChannel);

		const storageMainService = accessor.get(IStorageMainService);
		const storageChannel = this._register(new GlobalStorageDatabaseChannel(this.logService, storageMainService as StorageMainService));
		electronIpcServer.registerChannel('storage', storageChannel);


		const logLevelChannel = new LogLevelSetterChannel(accessor.get(ILogService));
		electronIpcServer.registerChannel('loglevel', logLevelChannel);

有存储、日志、菜单栏、工作台、升级.....等等 主要的通信还是用electronIpcServer 来干的,mainIpcServer只有一个launch信道; 下面我们看看消息是怎么传递的 我们随便打开一个信道的类型(src\vs\platform\windows\node\windowsIpc.ts) 它有两个主要的函数,listen和call,

	listen(_: unknown, event: string): Event<any> {
		switch (event) {
			case 'onWindowOpen': return this.onWindowOpen;
			case 'onWindowFocus': return this.onWindowFocus;
			case 'onWindowBlur': return this.onWindowBlur;
			case 'onWindowMaximize': return this.onWindowMaximize;
			case 'onWindowUnmaximize': return this.onWindowUnmaximize;
			case 'onRecentlyOpenedChange': return this.onRecentlyOpenedChange;
		}
		throw new Error(`Event not found: ${event}`);
	}
	call(_: unknown, command: string, arg?: any): Promise<any> {
		switch (command) {
			case 'pickFileFolderAndOpen': return this.service.pickFileFolderAndOpen(arg);
			case 'pickFileAndOpen': return this.service.pickFileAndOpen(arg);
			case 'pickFolderAndOpen': return this.service.pickFolderAndOpen(arg);
			case 'pickWorkspaceAndOpen': return this.service.pickWorkspaceAndOpen(arg);
			case 'showMessageBox': return this.service.showMessageBox(arg[0], arg[1]);
			case 'showSaveDialog': return this.service.showSaveDialog(arg[0], arg[1]);
			case 'showOpenDialog': return this.service.showOpenDialog(arg[0], arg[1]);
//......

消息来了,进入listen函数,发送消息,进入call函数; 注意,消息来了,触发的也不是他自己的方法,我们看看它的构造函数:

	constructor(private service: IWindowsService) {
		this.onWindowOpen = Event.buffer(service.onWindowOpen, true);
		this.onWindowFocus = Event.buffer(service.onWindowFocus, true);
		this.onWindowBlur = Event.buffer(service.onWindowBlur, true);
		this.onWindowMaximize = Event.buffer(service.onWindowMaximize, true);
		this.onWindowUnmaximize = Event.buffer(service.onWindowUnmaximize, true);
		this.onRecentlyOpenedChange = Event.buffer(service.onRecentlyOpenedChange, true);
	}

看到没,触发的其实是一个事件,事件是关联到service实例的; 这个实例是这样创建的:

const windowsService = accessor.get(IWindowsService);

具体的代码在:src\vs\platform\windows\electron-browser\windowsService.ts

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • vscode源码分析【三】程序的启动逻辑,性能问题的追踪

    代码文件:src\main.js 如果指定了特定的启动参数:trace vscode会在启动之初,执行下面的代码:

    liulun
  • riot.js教程【四】Mixins、HTML内嵌表达式

    前文回顾 riot.js教程【三】访问DOM元素、使用jquery、mount输入参数、riotjs标签的生命周期; riot.js教程【二】组件撰写准则...

    liulun
  • vscode源码分析【八】加载第一个画面

    先复习一下! 在第一节中,我们提到: app.ts(src\vs\code\electron-main\app.ts)的openFirstWindow方法...

    liulun
  • 网络中立:互联网的未来

    腾讯研究院司晓 蔡雄山 廖怀学 卢依联合撰稿       导语:奥巴马在一封给网络中立支持者们的公开信中谈到,“FCC今天的决定将保护创新,并为新一代的...

    腾讯研究院
  • NFV在运营商网络三大用武之地

    尽管NFV是一个非常理想的模式,但是如何将NFV逐渐在运营网中引入进来,才是最重要、最需要思考的问题。其实很多运营商都已经开始实践在运营商网络中引用NFV架构。...

    SDNLAB
  • ES6——常量( const )

    const声明一个只读的常量。一旦声明,常量必须进行初始化且初始化的值就不能改变。

    羊羽shine
  • Android调用手机中的应用市场,去评分的功能实现

    在我们常常使用的软件当中,我们经常可以看到在软件的设置界面,有一个功能那就是去评分的功能,只要我们一点击“去评分”就会调用手机中的应用市场软件。一开始我以为这个...

    非著名程序员
  • Android 必知必会 - 使用 Intent 打开第三方应用及验证可用性

    一个普通的应用默认会有一个入口 Activity,它在 AndroidManifest.xml 中一般这样写:

    他叫自己MR.张
  • 最近的 vim 配置

    前段时间调整了vim配置,尝试了下python-mode这个集成的配置。最终还是以体验太差告终,主要在性能方面,可能是我的Air配置太Low了。经常出现噼里啪啦...

    the5fire
  • 2018中国运营增长大会:2大城市,30+实战派大咖和你一起“引爆”增长引擎

    ? 一日一变的互联网世界,今年竞争异常激烈 从直播答题,人工智能,区块链, 短视频,P2P 无数产品诞生、火爆、变革和死亡 多变的一年,流量红利期已过,微信...

    腾讯大讲堂

扫码关注云+社区

领取腾讯云代金券