背景

最近总有读者来向我询问如何定制开发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);
如下图
定义路由入口

Node-RED editor-api 部分源码解析插图1

定义处理函数

Node-RED editor-api 部分源码解析插图3

这就是路由/flows对应的处理函数flows.get

注入此类,你在浏览器中看到的每一个请求都可以在editor-api中找到对应的路由配置。
当然有些是使用的通配符。走的静态资源加载。

总结

要想改造NODE-RED 就必须懂得,如何根据看到的页面,接口来找到对应的代码。
有时候代码只需要修改一行,但找到这行代码的位置却需要半天。

相关新闻

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

邮箱

cloud@modbus.cn

QQ
QQ
微信
微信
SHARE
TOP