背景
最近总有读者来向我询问如何定制开发Node-RED,他们想基于自己的项目做一些定制开发。
比如调整Node-RED的布局,主题色,增加一些按钮。或者将一些其他功能集成进去。
接下来的几篇文章我们就来分析一下NODE-RED的源码。
NODE-RED的核心代码主要在packages/node_modules/@node-red
该目录下。
根据最新版,该目录下有6个子目录,分别是:
- editor-api 编辑器后端代码
- editor-client 编辑器前端代码
- nodes 默认安装的节点
- registry 插件,库,节点的注册管理
- runtime 运行时入口,也是node-red的入口
- util 辅助工具
本篇首先讲解一下editor-api该目录的作用 及重要源码。方便开发人员开发时能够快速理解,并找到对应的文件。
editor-api
该目录存放的是用于支撑editor-client功能的后端api服务。
它是使用express启动的一个应用。依赖@node-red/util和@node-red/editor-client。
该模块的入口是./lib/index.js
应用初始化代码
function init(settings,_server,storage,runtimeAPI) {
server = _server;
if (settings.httpAdminRoot !== false) {
adminApp = express();
var cors = require('cors');
var corsHandler = cors({
origin: "*",
methods: "GET,PUT,POST,DELETE"
});
adminApp.use(corsHandler);
if (settings.httpAdminMiddleware) {
if (typeof settings.httpAdminMiddleware === "function" || Array.isArray(settings.httpAdminMiddleware)) {
adminApp.use(settings.httpAdminMiddleware);
}
}
var defaultServerSettings = {
"x-powered-by": false
}
var serverSettings = Object.assign({},defaultServerSettings,settings.httpServerOptions||{});
for (var eOption in serverSettings) {
adminApp.set(eOption, serverSettings[eOption]);
}
auth.init(settings,storage);
var maxApiRequestSize = settings.apiMaxLength || '5mb';
adminApp.use(bodyParser.json({limit:maxApiRequestSize}));
adminApp.use(bodyParser.urlencoded({limit:maxApiRequestSize,extended:true}));
adminApp.get("/auth/login",auth.login,apiUtil.errorHandler);
if (settings.adminAuth) {
if (settings.adminAuth.type === "strategy") {
auth.genericStrategy(adminApp,settings.adminAuth.strategy);
} else if (settings.adminAuth.type === "credentials") {
adminApp.use(passport.initialize());
adminApp.post("/auth/token",
auth.ensureClientSecret,
auth.authenticateClient,
auth.getToken,
auth.errorHandler
);
} else if (settings.adminAuth.tokens) {
adminApp.use(passport.initialize());
}
adminApp.post("/auth/revoke",auth.needsPermission(""),auth.revoke,apiUtil.errorHandler);
}
// Editor
if (!settings.disableEditor) {
editor = require("./editor");
var editorApp = editor.init(server, settings, runtimeAPI);
adminApp.use(editorApp);
}
if (settings.httpAdminCors) {
var corsHandler = cors(settings.httpAdminCors);
adminApp.use(corsHandler);
}
var adminApiApp = require("./admin").init(settings, runtimeAPI);
adminApp.use(adminApiApp);
} else {
adminApp = null;
}
}
在lib下,存在三个目录,分别是admin,auth,editor。
三个目录下都有一个index.js 文件,该文件定义接口路由,接口所需要的权限,以及对应的处理函数。
编辑器的登录逻辑,鉴权等都是在该模块处理。
登录鉴权在editor-api/lib/auth/index.js
该模块下提供的编辑器相关接口存放在editor-api/lib/editor
目录下。
比如国际化,证书,主题,设置,
editor-api中的接口底层是要调用运行时的接口。比如admin/context中的删除函数。
就是调用了 runtimeAPI
runtimeAPI.context.delete(opts).then(function(result) {
res.status(204).end();
}).catch(function(err) {
apiUtils.rejectHandler(req,res,err);
})
看到这里相信大家都已经明白,用户点击编辑器中的某个按钮,请求接口,
用户的请求首先到底editor-api该模块中,有些逻辑是在该模块下直接处理,返回给客户端。
而有些是又调用了runtime中的函数,经过运行时的处理。最终返回给用户的客户端。
比如
打开node-red的编辑器会请求一个flows的接口,http://127.0.0.1:1880/flows?_=1676345536746
在admin/index.js中可以找到adminApp.get("/flows",needsPermission("flows.read"),flows.get,apiUtil.errorHandler);
如下图
定义路由入口
定义处理函数
这就是路由/flows
对应的处理函数flows.get
。
注入此类,你在浏览器中看到的每一个请求都可以在editor-api中找到对应的路由配置。
当然有些是使用的通配符。走的静态资源加载。
总结
要想改造NODE-RED 就必须懂得,如何根据看到的页面,接口来找到对应的代码。
有时候代码只需要修改一行,但找到这行代码的位置却需要半天。