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

原文地址:https://www.cnblogs.com/liulun/p/11050725.html

时间: 2024-11-08 21:40:10

vscode源码分析【七】主进程启动消息通信服务的相关文章

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

第一篇: vscode源码分析[一]从源码运行vscode 第二篇:vscode源码分析[二]程序的启动逻辑,第一个窗口是如何创建的 第三篇:vscode源码分析[三]程序的启动逻辑,性能问题的追踪 第四篇:vscode源码分析[四]程序启动的逻辑,最初创建的服务 第五篇:vscode源码分析[五]事件分发机制 第六篇:vscode源码分析[六]服务实例化和单例的实现 第七篇:vscode源码分析[七]主进程启动消息通信服务 先复习一下! 在第一节中,我们提到: app.ts(src\vs\co

vscode源码分析【九】窗口里的主要元素

第一篇: vscode源码分析[一]从源码运行vscode 第二篇:vscode源码分析[二]程序的启动逻辑,第一个窗口是如何创建的 第三篇:vscode源码分析[三]程序的启动逻辑,性能问题的追踪 第四篇:vscode源码分析[四]程序启动的逻辑,最初创建的服务 第五篇:vscode源码分析[五]事件分发机制 第六篇:vscode源码分析[六]服务实例化和单例的实现 第七篇:vscode源码分析[七]主进程启动消息通信服务 第八篇:vscode源码分析[八]加载第一个画面 在上一节中,我们讲到

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

第一篇: vscode源码分析[一]从源码运行vscode 第二篇:vscode源码分析[二]程序的启动逻辑,第一个窗口是如何创建的 启动追踪 代码文件:src\main.js 如果指定了特定的启动参数:trace vscode会在启动之初,执行下面的代码: const contentTracing = require('electron').contentTracing; const traceOptions = { categoryFilter: args['trace-category-f

Nouveau源码分析(七): 各SUBDEV/ENGINE初始化 (1)

Nouveau源码分析(七) 虽然各个SUBDEV/EGINE的初始化实际还是在nouveau_drm_load里,但还是换个标题吧. 等把各个SUBDEV/ENGINE之类的说完再换回去. 上次已经按着初始化的顺序介绍了一下各个subdev的用途,现在按顺序,首先来看VBIOS的ctor函数: // /drivers/gpu/drm/nouveau/core/subdev/bios/base.c 537 struct nouveau_oclass 538 nouveau_bios_oclass

vscode源码分析【二】程序的启动逻辑

上一篇文章:https://www.cnblogs.com/liulun/ (小广告:我做的开源免费的,个人知识管理及自媒体营销工具“想学吗”:https://github.com/xland/xiangxuema) 我们在package.json里能找到他的入口文件: "main": "./out/main", electron是分主进程和渲染进程的: 渲染进程是主进程启动的: ./out/main.js显然这就是主进程的入口程序: 确实不假 但别着急去分析这个文

源码分析_Shinken-2.4.0001.启动脚本/etc/init.d/shinken源码分析?

简单介绍:说明: Shinken是一个网络监控平台,可以通过一系列直观的方式监控网络内的各种健康状况.Shinken脱胎于Nagios,其实Shinken这个项目本身就是一帮Nagios项目的人无法忍受Nagios,自己跳出来重新用纯Python重构了一下,甚至完全兼容Nagios的配置文件. 相关地址: 官网地址: http://www.shinken-monitoring.org/ 官网文档: http://shinken.readthedocs.io/en/latest/ 论坛地址: ht

Solr初始化源码分析-Solr初始化与启动

用solr做项目已经有一年有余,但都是使用层面,只是利用solr现有机制,修改参数,然后监控调优,从没有对solr进行源码级别的研究.但是,最近手头的一个项目,让我感觉必须把solrn内部原理和扩展机制弄熟,才能把这个项目做好.今天分享的就是:Solr是如何启动并且初始化的.大家知道,部署solr时,分两部分:一.solr的配置文件.二.solr相关的程序.插件.依赖lucene相关的jar包.日志方面的jar.因此,在研究solr也可以顺着这个思路:加载配置文件.初始化各个core.初始化各个

Spring Core Container 源码分析七:注册 Bean Definitions

前言 原本以为,Spring 通过解析 bean 的配置,生成并注册 bean defintions 的过程不太复杂,比较简单,不用单独开辟一篇博文来讲述:但是当在分析前面两个章节有关 @Autowired.@Component.@Service 注解的注入机制的时候,发现,如果没有对有关 bean defintions 的解析和注册机制彻底弄明白,则很难弄清楚 annotation 在 Spring 容器中的底层运行机制:所以,本篇博文作者将试图去弄清楚 Spring 容器内部是如何去解析 b

7.Sentinel源码分析—Sentinel是怎么和控制台通信的?

这里会介绍: Sentinel会使用多线程的方式实现一个类Reactor的IO模型 Sentinel会使用心跳检测来观察控制台是否正常 Sentinel源码解析系列: 1.Sentinel源码分析-FlowRuleManager加载规则做了什么? 2. Sentinel源码分析-Sentinel是如何进行流量统计的? 3. Sentinel源码分析- QPS流量控制是如何实现的? 4.Sentinel源码分析- Sentinel是如何做到降级的? 5.Sentinel源码分析-Sentinel如