2022-03-11-带着问题看源码5-NodeRed系统数据存储
NodeRed 系统相关的配置文件会以 JONS 格式存储在本地,同时也提供了插件机制实现系统数据的自定义存储,本文从 Storage 模块出发,从源码分析下如何以插件形式实现自定义存储,也对这种方式的可能的用途进行分析。
1. NodeRed 系统数据有哪些#
文件名称 | 说明 |
---|---|
package.json | nodered npm 信息 |
.sessions.json | 维护会话信息,每一个建立的会话都会记录 |
flows_[hostname].json | NodeRed 流程文件 |
flows_[hostname]_cred.json | 用以保存节点中以.credentials 保存的信息,加密与否可使用配置文件中 credentialSecret 参数配置 |
.config.runtime.json | 运行时配置 |
.config.users.json | 用户配置 |
.config.nodes.json | 节点配置 |
.config.projects.json | Git 配置 |
2. NodeRed 中系统数据存储机制#
NodeRed 提供 storage 模块支持上述文件的读写。
2.1. 源码分析#
以接口形式封装模块,模块的使用者只依赖接口,不依赖接口的实现,符合面向对象的依赖倒置原则(依赖倒置原则可以减少类间的耦合性,提高系统的稳定,降低并行开发引起的风险,提高代码的可读性和可维护性。)
- 以接口形式封装,具体的实现由动态加载的插件实现
1 | getFlows: async function() { //====>此处为接口 |
- 在初始化时按配置文件选择要使用的存储模块
1 | init: async function(_runtime) { |
- 在可能有越权行为的接口处增加检验,保证文件访问不会越权
1 | ... |
- 在有可能同时写文件(共同资源)时,做互斥操作
1 | saveSettings: async function(settings) { |
2.2. API#
storage API 使用插件式配置 Node-RED 运行时存储数据
Function | Description |
---|---|
Storage.init(settings) | initialise the storage system |
Storage.getFlows() | get the flow configuration |
Storage.saveFlows(flows) | save the flow configuration |
Storage.getCredentials() | get the flow credentials |
Storage.saveCredentials(credentials) | save the flow credentials |
Storage.getSettings() | get the user settings |
Storage.saveSettings(settings) | save the user settings |
Storage.getSessions() | get the user sessions |
Storage.saveSessions(sessions) | save the user sessions |
Storage.getLibraryEntry(type,name) | get a type-specific library entry |
Storage.saveLibraryEntry(type,name,meta,body) | save a type-specific library entry |
3. NodeRed 中系统数据存储机制有哪些参与者#
4. NodeRed 为什么这么设计,这种设计的优劣有哪些#
以接口形式封装模块,模块的使用者只依赖接口,不依赖接口的实现,符合面向对象的依赖倒置原则(依赖倒置原则可以减少类间的耦合性,提高系统的稳定,降低并行开发引起的风险,提高代码的可读性和可维护性。)
6. 相关知识#
- async-mutex:异步互斥
支持使用互斥量和信号量两种方式
mutex(互斥体)
术语“互斥体”通常是指一种用于同步不同线程上运行的并发进程的数据结构。例如,在访问非线程安全资源之前,线程会锁定互斥体。这保证阻塞线程,直到没有其他线程持有互斥锁,从而强制对资源的独占访问。一旦操作完成,线程释放锁,允许其他线程获取锁并访问资源。
虽然 Javascript 是严格的单线程,但其执行模型的异步特性允许需要类似同步原语的竞争条件。例如,考虑一个与 web worker 通信的库,为了完成一项任务,它需要与 worker 交换几个后续消息。因为这些消息是以异步方式交换的,所以在这个过程中很有可能再次调用这个库。根据异步过程中处理状态的方式,这将导致难以修复甚至更难跟踪的竞争情况。
这个库通过将互斥的概念应用于 Javascript 解决了这个问题。锁定互斥体将返回一个承诺,一旦互斥体变得可用,该承诺就会解决。一旦异步进程完成(通常需要事件循环的多次旋转),调用提供给调用者的回调以释放互斥体,允许下一个调度的工作线程执行。
semaphore(信号量)
想象一下,您需要控制对共享资源的几个实例的访问。例如,您可能希望在执行转换的几个工作进程之间分发图像,或者您可能希望创建一个 web crawler 来并行执行定义数量的请求。信号量是一种数据结构,它被初始化为一个正整数值,并且可以被多次锁定。只要信号量值为正,锁定它将返回当前值,锁定进程将立即继续执行;信号量将在锁定时递减。释放锁将再次增加信号量。
一旦信号量达到零,下一个试图获取锁的进程将被挂起,直到另一个进程释放它的锁,这将再次增加信号量。
这个库为 Javascript 提供了一个信号量实现,类似于上面描述的互斥体实现。
- 面向对象 6 大原则:依赖倒置
高层模块不应该依赖底层模块,两者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。
依赖倒置原则是指模块间的依赖是通过抽象来发生的,实现类之间不发生直接的依赖关系,其依赖关系是通过接口是来实现的,这就是俗称的面向接口编程。
7. 应用场景分析#
- 换一种存储格式(YAML)
有些库已经实现此功能 node-red-contrib-yaml-storage
Node-RED 将流文件存储为 JSON 文档。虽然 JSON 是轻量级和通用的,但它不是最容易阅读的格式。Node-RED 在函数、注释和模板节点中存储各种形式的代码,如 JavaScript、HTML、CSS、Markdown 等。这些代码块被表示为 JSON 结构中的一行,这使得在读取流文件时很难进行调试,并且会产生差异 - 按指定的接口将文件存储在服务端
有些库已经实现(@flowforge/nr-storage) - 做数据加密
可以将数据加密后存储到本地或远端,防止拷贝数据 - 远端存储并做授权认证
通过将数据存放在远端,可对用户访问进行授权,限定用户可操作的时间。
2022-03-11-带着问题看源码5-NodeRed系统数据存储
https://blog.buqia.fun/2022/03/11/2022-03-11-带着问题看源码5-NodeRed系统数据存储/