接入NoFlo的Runtime

林一二2023年08月14日 20:00

待解决的问题

noflo-nodejs命令行的执行流程

  1. 从命令行参数读取文件路径,并用 fbp-graph 库加载为 Graph 对象
  2. 启动一个本地socket服务器,供本地自己连,或flowhub连
  3. 通过 runtime.graph.registerGraph 监听这个图的变化并广播,并设为当前的 mainGraph 在未来 getRuntime 时返回
    1. 谁会操作本地的图,它为何会变化?应该都是远端操作的吧,可能是为了某个远端操作后本地变了后同步给其它所有远端
    2. 看起来一个 runtime 只能有一个图?所以如果要在后台执行多个图就需要启动多个 runtime?不过或许这只是开发环境,生产环境可以直接用 noflo 包运行多个图
    3. 暂时不准备用 runtime,而是自己用 asCallback 处理运行

应该可以不用它这里的逻辑,因为主要是为远程连接 flowhub 开发用的,并支持广播给多端协作。我们自己嵌入了图编辑器且单用户的话,自己保存图和执行图就好了。

等需要做多人协作了再把 runtime 和 fbp protocol 这套东西加回来。

  1. 通过 ./node_modules/.bin/noflo-nodejs --host localhost --auto-save --graph ./scripts/MyGraph.json 启动后打开的 flowhub 页面里可以搜到本地安装的各种 noflo-strings 之类的包提供的组件
    1. 通过 devtool 看到是通过 "protocol":"component","command":"list" 触发返回一系列 "protocol":"component","command":"component","payload":{"name":"core/Callback" 协议在 socket 里,在页面加载时一个组件一个组件地读取的
    2. 实际上转发给了 runtimeClient.protocol.component.list 然后是 noflo 包里调 fbp-manifest 包的 manifest.list.list(loader.baseDir, opts)
  2. noflo-component-loader 并没有让 import { ComponentLoader } from 'noflo'; 取得的 loader 能列出组件列表,直接用 fbpManifest.load.load 却能看到 node_modules 里的组件
    1. 需要在 manifest 的设置里开启 recursive: true, 才会递归搜素 nodemodules 里的内容,不然默认搜素当前项目文件夹里的 conponents 文件夹和 graph 文件夹
  3. 没加载图标
    1. 首先得装 @fortawesome/fontawesome-free 包,用里面的 @fortawesome/fontawesome-free/js/all.js /css/all.css /css/v4-font-face.css 加载 fbp 那个年代用的 v4 版
    2. TheGraph.library.libraryFromGraph 只是通过图中节点反推伪造了一个组件库,都是假的,自然没有 icon 属性,可以通过 component.icon = sample(Object.keys(TheGraph.FONT_AWESOME)); 手动放上去来测试效果
    3. 还是得正常拼装组件库 library 并传给 TheGraph.App 才是正途
  4. 有没有办法把依赖的组件打成一个包动态加载,还是说必须在运行时通过fs寻找和加载。前者对electric环境更友好
    1. 通过 noflo-component-loader coffee-loader fbp-loader 相关的 webpack rules 来加载,然后会覆盖 ComponentLoader 里的一个 require 从而取到 node_modules 里所有 noflo 相关包打包出的结果
  5. 如何在图里加载自己这个图或者其它子图

the-graph 界面的使用方式

  1. flowhub是如何列出可用组件的列表的
    1. 后来自己用 material ui 让 GPT 实现了一个自己的
  2. react 版本过旧,无法使用其中的 method
    1. 见仓库相关 issue,我通过 pnpm patch 加了个方法接收 ref,从而让我的代码能接触到里面的函数
  3. 自动布局用的 klayjs 涉及 webworker
    1. 用 CopyPlugin 将它复制到构建产物文件夹里,在使用时 Electron 就可以从这个 .webpack/renderer/webWorkers 文件夹里加载创建 webWorker 了

点击运行按钮后执行的操作

  1. 将当前 fbp-graph 的 Graph 对象转换为 noflo Graph 对象
    1. 本来在前端是只会有 fbp-graph 的,就算在前端运行流程,也是通过一个 browser-runtime 去构建 noflo Graph 对象
    2. 仿照 noflo-browser 看看是如何做这个转换的
      1. 它里面没写,noflo-ui 里又层层转发消息,找不到点了执行按钮后具体做了什么
    3. 调用链 noflo-ui / noflo-nodejs - noflo-runtime-websocket - noflo-runtime-base - src/protocol/Network.js - noflo.createNetwork 这里没有类型,但通过自己的 TS 项目可以看到这个函数入参就是 fbp-graph 的 Graph 对象
      1. 所以可以直接用 noflo 库里的 createNetwork (实际上创建的是 Graph,但这里不知为何称为 Network)
      2. 实际创建的不是 Noflo 的 Graph,而是 Network,这个可以直接调 start 来执行
        1. 需要先调 Network.connect(),才会让里面的 connection 有内容,那个才是运行时使用的信息,运行时不会直接去读 Graph 里的内容。
        2. 可以通过 fbpGraph.addInitial('aaa', fbpGraph.nodes[1].id, 'in'); 程序化地添加初始值,这个值也会反应在界面上
      3. 这与 asCallback 有什么不同?
        1. 一样的,实际上都是走上面的流程,Network 类就是最底层的运行时实现了
  2. 点击调试运行按钮时执行图,并在页面退出时用 AbortController 之类的来中止运行

基于状态机的插件化的AI流程工具Memeloop 动态数据付费创意工坊线上线下分类项目

Undefined widget 'supertag-form'

Code
!! 待解决的问题

!! noflo-nodejs命令行的执行流程

# 从命令行参数读取文件路径,并用 `fbp-graph` 库加载为 Graph 对象
# 启动一个本地socket服务器,供本地自己连,或flowhub连
# 通过 `runtime.graph.registerGraph` 监听这个图的变化并广播,并设为当前的 `mainGraph` 在未来 `getRuntime` 时返回
## 谁会操作本地的图,它为何会变化?应该都是远端操作的吧,可能是为了某个远端操作后本地变了后同步给其它所有远端
## 看起来一个 runtime 只能有一个图?所以如果要在后台执行多个图就需要启动多个 runtime?不过或许这只是开发环境,生产环境可以直接用 noflo 包运行多个图
## 暂时不准备用 runtime,而是自己用 `asCallback` 处理运行


应该可以不用它这里的逻辑,因为主要是为远程连接 flowhub 开发用的,并支持广播给多端协作。我们自己嵌入了图编辑器且单用户的话,自己保存图和执行图就好了。

等需要做多人协作了再把 runtime 和 fbp protocol 这套东西加回来。 

# 通过 `./node_modules/.bin/noflo-nodejs --host localhost --auto-save --graph ./scripts/MyGraph.json` 启动后打开的 flowhub 页面里可以搜到本地安装的各种 `noflo-strings` 之类的包提供的组件
## 通过 devtool 看到是通过 `"protocol":"component","command":"list"` 触发返回一系列 `"protocol":"component","command":"component","payload":{"name":"core/Callback"` 协议在 socket 里,在页面加载时一个组件一个组件地读取的
## 实际上转发给了 `runtimeClient.protocol.component.list` 然后是 `noflo` 包里调 `fbp-manifest` 包的 `manifest.list.list(loader.baseDir, opts)` 
# noflo-component-loader 并没有让 `import { ComponentLoader } from 'noflo';` 取得的 loader 能列出组件列表,直接用 `fbpManifest.load.load` 却能看到 node_modules 里的组件
## 需要在 manifest 的设置里开启 `recursive: true,` 才会递归搜素 nodemodules 里的内容,不然默认搜素当前项目文件夹里的 conponents 文件夹和 graph 文件夹
# 没加载图标
## 首先得装 `@fortawesome/fontawesome-free` 包,用里面的 `@fortawesome/fontawesome-free/js/all.js` `/css/all.css` `/css/v4-font-face.css` 加载 fbp 那个年代用的 v4 版
## `TheGraph.library.libraryFromGraph` 只是通过图中节点反推伪造了一个组件库,都是假的,自然没有 icon 属性,可以通过 `component.icon = sample(Object.keys(TheGraph.FONT_AWESOME));` 手动放上去来测试效果
## 还是得正常拼装组件库 library 并传给 `TheGraph.App` 才是正途
# 有没有办法把依赖的组件打成一个包动态加载,还是说必须在运行时通过fs寻找和加载。前者对electric环境更友好
## 通过 `noflo-component-loader` `coffee-loader` `fbp-loader` 相关的 webpack rules 来加载,然后会覆盖 `ComponentLoader` 里的一个 require 从而取到 node_modules 里所有 noflo 相关包打包出的结果
# 如何在图里加载自己这个图或者其它子图

!! the-graph 界面的使用方式

# flowhub是如何列出可用组件的列表的
## 后来自己用 material ui 让 GPT 实现了一个自己的
# react 版本过旧,无法使用其中的 method
## 见仓库相关 issue,我通过 pnpm patch 加了个方法接收 ref,从而让我的代码能接触到里面的函数
# 自动布局用的 klayjs 涉及 webworker
## 用 CopyPlugin 将它复制到构建产物文件夹里,在使用时 Electron 就可以从这个 `.webpack/renderer/webWorkers` 文件夹里加载创建 webWorker 了


!!! 点击运行按钮后执行的操作

# 将当前 fbp-graph 的 Graph 对象转换为 noflo Graph 对象
## 本来在前端是只会有 fbp-graph 的,就算在前端运行流程,也是通过一个 browser-runtime 去构建 noflo Graph 对象
## 仿照 [ext[noflo-browser|https://github.com/noflo/noflo-browser]] 看看是如何做这个转换的
### 它里面没写,noflo-ui 里又层层转发消息,找不到点了执行按钮后具体做了什么
## 调用链 `noflo-ui` / `noflo-nodejs` - `noflo-runtime-websocket` - `noflo-runtime-base` - `src/protocol/Network.js` - `noflo.createNetwork` 这里没有类型,但通过自己的 TS 项目可以看到这个函数入参就是 fbp-graph 的 Graph 对象
### 所以可以直接用 noflo 库里的 createNetwork (实际上创建的是 Graph,但这里不知为何称为 Network)
### 实际创建的不是 Noflo 的 Graph,而是 Network,这个可以直接调 `start` 来执行
#### 需要先调 `Network.connect()`,才会让里面的 connection 有内容,那个才是运行时使用的信息,运行时不会直接去读 Graph 里的内容。
#### 可以通过 `fbpGraph.addInitial('aaa', fbpGraph.nodes[1].id, 'in');` 程序化地添加初始值,这个值也会反应在界面上
### 这与 `asCallback` 有什么不同?
#### 一样的,实际上都是走上面的流程,Network 类就是最底层的运行时实现了
# 点击调试运行按钮时执行图,并在页面退出时用 `AbortController` 之类的来中止运行