EOS [EOS DAPP 开发] 14 - 详解 Demux (原理和使用)

pendingauth · 2019年05月24日 · 70 次阅读

本文转载自币乎,作者松果,原文链接:https://bihu.com/article/1412247022

Demux数据流

Demux借鉴了Facebook的Flux架构和Redux,它的数据流如下图所示:

  • 1、 客户端发送交易到区块链;

  • 2、 ActionWatcher调用ActionReader,检查新区块;

  • 3、 ActionReader发现新区块中的交易, 开始解析Action;

  • 4、 ActionWatcher把Action发送给ActionHandler处理;

  • 5、 ActionHandler通过Updaters和Effects处理Action;

  • 6、 ActionHandler执行相应的Updaters,更新数据库中的数据;

  • 7、 ActionHandler执行相应的Effects, 触发外部事件(推送消息给客户端等)和更新区块链;

  • 8、客户端通过查询API获取更新后的数据。

启动Demux服务

启动Demux服务的代码很简单,实例化一个BaseActionWatcher类,调用它的watch()方法。

const actionWatcher = new BaseActionWatcher(
  actionReader,
  actionHandler,
  250
);
actionWatcher.watch();

BaseActionWatcher的构造函数需要传入三个参数:actionReader、actionHandler,和一个时间(毫秒数)。

  • actionReader:一个AbstractActionReader对象,用来读取新区块交易中的Action;

  • actionHandler:一个AbstractActionHandler对象,用来处理actionReader读取的Action;

  • 250(毫秒数):BaseActionWatcher会开启一个轮询,250毫秒指每次轮询的间隔时间。

这里设置轮询间隔时间为0.25秒,是因为EOS的出块时间是0.5秒,这样在一个区块时间内可以处理两次Action,减少延迟。

注意,最新的Demux v4.0新增了一个BaseActionWatcher的子类:ExpressActionWatcher,更适合集成到Express。

详解Demux

这张图表示了Demux的组成:

从名字可以看出,AbstractActionReader、AbstractActionHandler都是抽象类,我们需要实例化出它们的实现类。

AbstractActionReader

EOSIO/demux-js库目前不提供AbstractActionReader的实现类,由EOSIO/demux-js-eos库提供。

# 安装demux-js
npm install demux --save
# 安装demux-js-eos
npm install demux-eos --save

demux-js-eos目前提供3个AbstractActionReader的实现类:

  • NodeosActionReader

直接从区块链中读取Action

  • MongoActionReader

从nodeos关联的MongoDB数据库中读取Action(需要启动eosio::mongo_db_plugin插件)

  • StateHistoryPostgresActionReader

从nodeos关联的Postgres数据库中读取Action(需要启动eosio::state_history_plugin插件)


AbstractActionHandler

EOSIO/demux-js-postgres库提供了一个AbstractActionHandler的实现类:

# 安装 demux-js-postgres
npm install demux-postgres --save
npm install massive --save
  • MassiveActionHandler:处理使用Postgres数据库时的Action

注:PostgreSQL已经连续两年蝉联DB-Engine年度数据库(2017、2018),PostgreSQL是关系型数据库,同时支持JSON,有取代mongoDB的趋势。

如果使用的数据库是mongoDB,需要自己写一个类继承AbstractActionHandler。

实例化AbstractActionHandler,需要实现这些方法:

# 加载区块链索引状态
protected abstract loadIndexState(): Promise<IndexState>;

# 更新区块链索引状态
protected abstract updateIndexState(state: any, block: Block, isReplay: boolean, context?: any): Promise<void>;

# 处理数据状态
protected abstract handleWithState(handle: (state: any, context?: any) => void): Promise<void>;

AbstractActionHandler的构造函数需要传递两个数组:updaters和effects

constructor(updaters: Updater[], effects: Effect[]);

注意,最新的Demux v4.0中,updaters和effects已经被封装进了HandlerVersion接口中,构造函数只需传递HandlerVersion数组。

Updater & Effect

Updater和Effect都是接口:

Updater接口需要实现updater函数,来更新数据库;

Effect接口需要实现effect函数,来通知区块链和外部事件数据已改变。

一个updater函数的实现例子:

一个effect函数的实现例子:

注意,这里的blockInfo是一个Block对象的一部分,Block接口在ts中的数据定义如下:

总结

到这里,Demux就介绍的差不多了,更多细节可以参考官方文档官方示例

Demux最新版已经更新到v4.0,Demo中使用的版本是v2.0,代码上有一些差别,在文章中指出了一部分,但大体使用方法相同。关于最新版本的变更细节查看:https://github.com/EOSIO/demux-js/releases

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册