Closed yantze closed 2 years ago
这个可能要过几天再确认是谁,因为现在不止一个同学申请这个题目。
评价标准其实是看之前有给 OpenSumi 贡献过一些代码或者有一些研发能力的的同学(因为这个项目可能涉及到的东西还是有一些的)。
没问题~
一个可能行得通的思路:
将“可能行得通”划掉是因为Electron端的事情没想象中简单。
Hi, OpenSumi community! 这两天我在探索学习中,主要是想确定捕获通信消息的可行方案。标题中所谓的“外挂式通信消息捕获”指的就是诸如:
因为宿主应用对它们是没有感知的,所以是“外挂式”的。就我目前的认知看来,这种比较理想的方式似乎不大可行。
DevTron是 @Yantze 老师推荐看看的,于是我首先学习了它的原理。与IPC消息捕获相关的代码在这儿,可以用移花接木或偷梁换柱形容。具体是怎么做的呢?Electron的Main进程和renderer进程之间以IPC的方式进行通信,具体到代码就是用ipcMain和ipcRenderer这两个API通信。DevTron对ipcRenderer做了手脚,在其中加入捕获通信消息的逻辑,使得宿主应用执行ipcRenderer的方法时实际上调用的是改造过后的ipcRenderer,于是就达到了“外挂式通信消息捕获”的目的。
我一度认为DevTron所采用的方法就是本课题的方案了,直到意识到此课题要求捕获的消息是前端进程和后端进程之间的消息,而不是Electron的Main进程和renderer进程之间的消息。前者在Electron端(isRemote为false时)是靠Nodejs的Socket来通信的,这意味着跟ipcRenderer没什么关系。这也解释了为什么当我在ide-electron中运行DevTron后,IPC消息列表几乎没什么消息——因为这个列表中的消息只包含ipcRenderer收发的消息。
我不想轻易放弃:既然Chrome能捕获websocket的消息,那有没有方法可以直接捕获socket消息呢?这样的话宿主应用照样是对此无感的。遗憾的是,目前我还没找到。
以上只是我目前的认知,如果有错误的地方请 @yantze 和其他maintainers一定要纠正我。
通过修改 OpenSumi 的前端代码其实是很容易做到这件事的,Chrome 插件向 window 上注入一个 __OPENSUMI_DEVTOOL_EVENT_SOURCE_TOKEN__
,然后在 core 的代码中检测这个变量是否存在,比如说:
const __OPENSUMI_DEVTOOL_EVENT_SOURCE_TOKEN__ = { traffic: { send(xxx){}, recieve(xxx){} } }
然后代码中这么用,最后在前端收发的过程中将自己发出去或者接收到的内容发给 Chrome 插件。
let trafficInspector;
if (typeof __OPENSUMI_DEVTOOL_EVENT_SOURCE_TOKEN__ !== "undefined") {
trafficInspector = __OPENSUMI_DEVTOOL_EVENT_SOURCE_TOKEN__.traffic;
}
class WSChannel {
sendMessage(xxx) {
trafficInspector?.send(xxx)
this.connection.send(xxxx)
}
onMessage(xxx) {
trafficInspector?.recieve(xxx)
}
}
以上都是随手写的代码,仅供参考。
谢谢 @bytemain ,你提供的snippet非常具有启发性!
之前和 @yantze 老师交流过,如果“外挂式”方案行不通的话,就改动connection模块的代码。WSChannel是针对websocket的,我刚刚发现RPCProtocol._protocol看起来是个更好的切入点: https://github.com/opensumi/core/blob/4df3b875d71f46e58c4684ec1eb25b09a4ed053f/packages/connection/src/common/rpcProtocol.ts#L201
因为this._protocol是一个connection,而connection是统一了websocekt和socket的,所以这个send和onMessage对websocket和socket的msg都适用。大家怎么看?
HELP WANTED:
以connection这个模块为例,我发现common/的一些模块只在web端用到;node/的一些模块是针对Electron的前端进程的,还有一些是针对OpenSumi的后端进程的。好吧,我也说不大清我的感受,也许我想问node/connect.ts为什么不放在common/里,因为我目前认为node/只放后端代码。
大家如果愿意分享一下“如何读懂connection”相关的经验的话,那就太好了!急需这方面的建议。
有关这几个为什么..只能说 connection 这部分写的太耦合,以至于后面想改已经改不动了。
有关 connection 的一些 pr: 改造开始的起点:
然后发现 electron 下有问题:
然后发现 web 端又有问题:
至此,connection 改造失败
之前的一些尝试:
sumi-ipc-main_threadyw-q6BbDmwr6WVDMb6Uh_.sock
文件,通过 unix socket 捕获到对应的信息,但感觉这条路太底层,有点吃力不讨好的感觉另外:
这两种都可以作为插件查看通讯的方式。可以针对 ide-connection 的传送信息,优化显示,比如能通过 connection 模块,查看 请求的信息和返回的信息。而 ipc 的方式可以作为一个通用的面板展示即可,后期有必要再进行优化。
非常感谢 @bytemain 和 @yantze 的回复!前几天仔细阅读了回复内容后,我明确了一下目标,并进行了实验。
(这里想确认一下:@yantze 老师说的ipc特指socket通信吗?)
因为this._protocol是一个connection,而connection是统一了websocekt和socket的,所以这个send和onMessage对websocket和socket的msg都适用。大家怎么看?
首先,我放弃了将_protocol作为消息拦截对象,因为在查看了class RPCProtocol
的所有引用后,我发现只有extension模块使用了它。但前后端的通信不只发生在extension模块。
通过阅读源码、调试后,我发现MessageConnection才是合适的消息拦截对象。下图是我在寻找websocket和socket的统一层的时候画的“connection建立过程”流程图:
目前的改动部分我已经提了一个PR到自己仓库里,大家可以直接前往看changes。代码改动的地方不多,一看就能明白(虽然我花了很久)。我在这里稍微描述一下我的改造旅程。
首先,我非常希望能改造得松耦合一点,尽量能不影响原来的代码逻辑,所以一开始我还是希望能像DevTron那样“偷梁换柱”,于是我计划用Proxy
代理createMessageConnection()
得到的messageConnection
,并在handler中对get
做手脚,使得messageConnection
实例调用sendRequest
、sendNotification
、onRequest
、onNotification
这4个方法的时候会被拦截到,这样我就可以插入捕获消息的逻辑了。
这里有个细节,那就是createWebSocketConnection
和createSocketConnection
不仅在前端被调用,还会在后端进程启动的时候被调用,这是个公共的函数,所以要考虑window
对象是否存在——使用window
对象是因为我根据 @bytemain 提供的思路在“opensumi-devtools”插件(暂且这么称呼它)启动的时候利用chrome.devtools.inspectedWindow.eval(xxx)
向前端的window
对象插入了一个TOKEN。
上面4个被拦截的方法中,sendRequest
和sendNotification
看上去成功了,但onRequest
、onNotification
似乎没有被拦截到。后来我意识到,拦截代码得放到调用这两个方法时注册的handler里面去——onXXX
只是一开始的时候被调用一次,不像sendXXX
每次发送消息都会调用。
这么一来,理想中的松耦合改造落空了,我又去handler里加了捕获逻辑。此外,sendRequest
是有返回值的,我还得在requestResult
这个Promise的then中加捕获逻辑。于是,就有了目前PR里的内容。
现在只做到了插件向window注入东西,还没做到前端发信息给插件,截图中console里的内容是利用window.eval
打印的。
经过自己的测试和体验,像方向键移动、获取文件buffer、terminal“画面”的原始字符串、插件列表信息等都能在捕获的信息里看到。但是,onRequest的handler从来没有被触发到,即我试了很久也没有试出来后端向前端sendRequest的情况,这是正常的吗?
码的字有点多,希望大家看看目前的改造思路可以吗?如果思路可以,有没有方法能更加的松耦合、优雅一点?
后端向前端发送消息的场景我知道的有一个:
把 "terminal.type"这个配置项 设置为一个随便的字符串,然后启动一下终端,因为这个终端是不存在的,后端就会通知前端这个 terminal 启动失败了。
我猜这个 onRequest 和 onNotification 的区别貌似是只有文字上的区别。它们的实现和底层的东西貌似是一样的
Hi, @bytemain, 请问“terminal.type”是去一个文件里设置吗?我在界面上设置只能选择,不能输入。
我猜这个 onRequest 和 onNotification 的区别貌似是只有文字上的区别。它们的实现和底层的东西貌似是一样的
我目前的理解是,对前端来说,onRequest是来响应后端的sendRequest,onNotification是接受后端的单向通知,后者在消息中很高频的,前者目前我还没遇到过。
「ipc特指socket通信」这里的 ipc 特指 ipcMain 和 ipcRenderer 之间的通信
点击这个图标可以编辑 json
触发到了!谢谢你!
Hi,大家好!
我已经准备好了一个仓库:https://github.com/tyn1998/opensumi-devtools
~计划下一步是先把捕获到的消息传给devtools page,相关issue:https://github.com/tyn1998/opensumi-devtools/issues/4~
https://github.com/tyn1998/opensumi-devtools/issues/4 中的方案对electron不适用,故放弃。不过,做都做了,我还是在web端跑通了,大家可以在 https://github.com/tyn1998/opensumi-devtools/issues/6 看效果~
启用Plan B,即模仿DevTron的方式,请见:https://github.com/tyn1998/opensumi-devtools/issues/7
敬请期待~
Hi,大家好!
已经有一个(非常朴素的)原型了:https://github.com/tyn1998/opensumi-devtools/pull/10
一个升级版demo,支持:
相关PR:
大家好!之前已经确认用data grid的形式来呈现通信消息,但是具体的columns没有明确过。这次构想了一下需要的列:
(突然发现自己一直没考虑onRequest后再return给后端data的消息,如果考虑进来,那么可能会用↓↑表示onRequest+return data,于是上面的columns还要改进)
有了最基本的功能,录了个视频大概演示了一下:
sendRequest+requestResult, onRequest+return 看起来是某个一侧的内容?只要加上是哪一侧发起的就好了吧。
大家好,与上次比变化如下:
下一步计划:
视频演示:
相关PR:
下一步计划:
更新内容:
视频演示(网络延迟功能):
相关PR:
计划安排:
Implement a Chrome DevTools for viewing OpenSumi communication messages
Background
This is an advance subject of ASoC 2022 and #1103 .
The current architecture of OpenSumi is a front-end and back-end separation, where the front-end of the desktop has to communicate with multiple processes, or the web-end has to communicate with the back-end services. The current communication methods are ipc, rpc, etc., but it is difficult to see or debug the communication problems visually.
Hope to provide a visual display of communication data Chrome plug-in, easy to see the communication traffic.
Target
Difficulty
Advance
Mentor
@yantze yutian.yz#alibaba-inc#com
Output Requirements
实现一个用于查看 OpenSumi 通信消息的 Chrome 插件
背景
这是一个阿里巴巴编程之夏 2022 的基础课题 https://github.com/opensumi/core/issues/1098 .
目前 OpenSumi 的架构是前后端分离的,桌面端前端要和有多个进程进行通信,或者 Web 端要和后端服务通信。目前通信的方式有 ipc、rpc 等,但通信的问题会比较难以直观的看到或者调试。
希望提供一个可视化的显示通信数据的 Chrome 插件,方便的查看通信流量。
目标
为了在 Web 和 桌面端都可以通用,期望实现的最终产物是一个 Chrome Extension,通信数据展示在 Devtools 上,具有可视化显示每一条通信数据。
难度
进阶
导师
@yantze yutian.yz#alibaba-inc#com
需要的技能