Comparing version 2.0.0 to 3.0.0
@@ -1,2 +0,2 @@ | ||
import { Block, Effect, IndexState, Updater } from "./interfaces"; | ||
import { Action, Block, HandlerVersion, IndexState } from "./interfaces"; | ||
/** | ||
@@ -9,7 +9,7 @@ * Takes `block`s output from implementations of `AbstractActionReader` and processes their actions through | ||
export declare abstract class AbstractActionHandler { | ||
protected updaters: Updater[]; | ||
protected effects: Effect[]; | ||
protected lastProcessedBlockNumber: number; | ||
protected lastProcessedBlockHash: string; | ||
constructor(updaters: Updater[], effects: Effect[]); | ||
protected handlerVersionName: string; | ||
private handlerVersionMap; | ||
constructor(handlerVersions: HandlerVersion[]); | ||
/** | ||
@@ -23,3 +23,3 @@ * Receive block, validate, and handle actions with updaters and effects | ||
*/ | ||
protected abstract updateIndexState(state: any, block: Block, isReplay: boolean, context?: any): Promise<void>; | ||
protected abstract updateIndexState(state: any, block: Block, isReplay: boolean, handlerVersionName: string, context?: any): Promise<void>; | ||
/** | ||
@@ -40,7 +40,7 @@ * Returns a promise for the `lastProcessedBlockNumber` and `lastProcessedBlockHash` meta state, | ||
*/ | ||
protected runUpdaters(state: any, block: Block, context: any): Promise<void>; | ||
protected applyUpdaters(state: any, block: Block, isReplay: boolean, context: any): Promise<Array<[Action, string]>>; | ||
/** | ||
* Process actions against asynchronous side effects. | ||
*/ | ||
protected runEffects(state: any, block: Block, context: any): void; | ||
protected runEffects(versionedActions: Array<[Action, string]>, block: Block, context: any): void; | ||
/** | ||
@@ -53,6 +53,9 @@ * Will run when a rollback block number is passed to handleActions. Implement this method to | ||
/** | ||
* Calls `runUpdaters` and `runEffects` on the given actions | ||
* Calls `applyUpdaters` and `runEffects` on the given actions | ||
*/ | ||
protected handleActions(state: any, block: Block, context: any, isReplay: boolean): Promise<void>; | ||
private initHandlerVersions; | ||
private warnHandlerVersionNonexistent; | ||
private warnSkippingUpdaters; | ||
private refreshIndexState; | ||
} |
@@ -18,7 +18,8 @@ "use strict"; | ||
class AbstractActionHandler { | ||
constructor(updaters, effects) { | ||
this.updaters = updaters; | ||
this.effects = effects; | ||
constructor(handlerVersions) { | ||
this.lastProcessedBlockNumber = 0; | ||
this.lastProcessedBlockHash = ""; | ||
this.handlerVersionName = "v1"; | ||
this.handlerVersionMap = {}; | ||
this.initHandlerVersions(handlerVersions); | ||
} | ||
@@ -38,3 +39,3 @@ /** | ||
} | ||
else if (!this.lastProcessedBlockHash && this.lastProcessedBlockNumber === 0) { | ||
else if (this.lastProcessedBlockNumber === 0 && this.lastProcessedBlockHash === "") { | ||
yield this.refreshIndexState(); | ||
@@ -72,13 +73,28 @@ } | ||
*/ | ||
runUpdaters(state, block, context) { | ||
applyUpdaters(state, block, isReplay, context) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const versionedActions = []; | ||
const { actions, blockInfo } = block; | ||
for (const action of actions) { | ||
for (const updater of this.updaters) { | ||
let updaterIndex = -1; | ||
for (const updater of this.handlerVersionMap[this.handlerVersionName].updaters) { | ||
updaterIndex += 1; | ||
if (action.type === updater.actionType) { | ||
const { payload } = action; | ||
yield updater.updater(state, payload, blockInfo, context); | ||
const newVersion = yield updater.apply(state, payload, blockInfo, context); | ||
versionedActions.push([action, this.handlerVersionName]); | ||
if (newVersion && !this.handlerVersionMap.hasOwnProperty(newVersion)) { | ||
this.warnHandlerVersionNonexistent(newVersion); | ||
} | ||
else if (newVersion) { | ||
console.info(`BLOCK ${blockInfo.blockNumber}: Updating Handler Version to '${newVersion}'`); | ||
this.warnSkippingUpdaters(updaterIndex, action.type); | ||
yield this.updateIndexState(state, block, isReplay, newVersion, context); | ||
this.handlerVersionName = newVersion; | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
return versionedActions; | ||
}); | ||
@@ -89,9 +105,8 @@ } | ||
*/ | ||
runEffects(state, block, context) { | ||
const { actions, blockInfo } = block; | ||
for (const action of actions) { | ||
for (const effect of this.effects) { | ||
runEffects(versionedActions, block, context) { | ||
for (const [action, handlerVersionName] of versionedActions) { | ||
for (const effect of this.handlerVersionMap[handlerVersionName].effects) { | ||
if (action.type === effect.actionType) { | ||
const { payload } = action; | ||
effect.effect(state, payload, blockInfo, context); | ||
effect.run(payload, block, context); | ||
} | ||
@@ -102,3 +117,3 @@ } | ||
/** | ||
* Calls `runUpdaters` and `runEffects` on the given actions | ||
* Calls `applyUpdaters` and `runEffects` on the given actions | ||
*/ | ||
@@ -108,7 +123,7 @@ handleActions(state, block, context, isReplay) { | ||
const { blockInfo } = block; | ||
yield this.runUpdaters(state, block, context); | ||
const versionedActions = yield this.applyUpdaters(state, block, isReplay, context); | ||
if (!isReplay) { | ||
this.runEffects(state, block, context); | ||
this.runEffects(versionedActions, block, context); | ||
} | ||
yield this.updateIndexState(state, block, isReplay, context); | ||
yield this.updateIndexState(state, block, isReplay, this.handlerVersionName, context); | ||
this.lastProcessedBlockNumber = blockInfo.blockNumber; | ||
@@ -118,7 +133,42 @@ this.lastProcessedBlockHash = blockInfo.blockHash; | ||
} | ||
initHandlerVersions(handlerVersions) { | ||
if (handlerVersions.length === 0) { | ||
throw new Error("Must have at least one handler version."); | ||
} | ||
for (const handlerVersion of handlerVersions) { | ||
if (this.handlerVersionMap.hasOwnProperty(handlerVersion.versionName)) { | ||
throw new Error(`Handler version name '${handlerVersion.versionName}' already exists. ` + | ||
"Handler versions must have unique names."); | ||
} | ||
this.handlerVersionMap[handlerVersion.versionName] = handlerVersion; | ||
} | ||
if (!this.handlerVersionMap.hasOwnProperty(this.handlerVersionName)) { | ||
console.warn(`No Handler Version found with name '${this.handlerVersionName}': starting with ` + | ||
`'${handlerVersions[0].versionName}' instead.`); | ||
this.handlerVersionName = handlerVersions[0].versionName; | ||
} | ||
else if (handlerVersions[0].versionName !== "v1") { | ||
console.warn(`First Handler Version '${handlerVersions[0].versionName}' is not '${this.handlerVersionName}', ` + | ||
`and there is also '${this.handlerVersionName}' present. Handler Version ` + | ||
`'${this.handlerVersionName}' will be used, even though it is not first.`); | ||
} | ||
} | ||
warnHandlerVersionNonexistent(newVersion) { | ||
console.warn(`Attempted to switch to handler version '${newVersion}', however this version ` + | ||
`does not exist. Handler will continue as version '${this.handlerVersionName}'`); | ||
} | ||
warnSkippingUpdaters(updaterIndex, actionType) { | ||
const remainingUpdaters = this.handlerVersionMap[this.handlerVersionName].updaters.length - updaterIndex - 1; | ||
if (remainingUpdaters) { | ||
console.warn(`Handler Version was updated to version '${this.handlerVersionName}' while there ` + | ||
`were still ${remainingUpdaters} updaters left! These updaters will be skipped for the ` + | ||
`current action '${actionType}'.`); | ||
} | ||
} | ||
refreshIndexState() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { blockNumber, blockHash } = yield this.loadIndexState(); | ||
const { blockNumber, blockHash, handlerVersionName } = yield this.loadIndexState(); | ||
this.lastProcessedBlockNumber = blockNumber; | ||
this.lastProcessedBlockHash = blockHash; | ||
this.handlerVersionName = handlerVersionName; | ||
}); | ||
@@ -125,0 +175,0 @@ } |
@@ -1,4 +0,4 @@ | ||
export { Action, Block, BlockInfo, Effect, IndexState, Updater } from "./interfaces"; | ||
export { Action, Block, BlockInfo, Effect, HandlerVersion, IndexState, Updater } from "./interfaces"; | ||
export { AbstractActionHandler } from "./AbstractActionHandler"; | ||
export { AbstractActionReader } from "./AbstractActionReader"; | ||
export { BaseActionWatcher } from "./BaseActionWatcher"; |
@@ -8,2 +8,4 @@ export interface Block { | ||
blockHash: string; | ||
handlerVersionName: string; | ||
isReplay: boolean; | ||
} | ||
@@ -20,9 +22,19 @@ export interface BlockInfo { | ||
} | ||
export interface Updater { | ||
export interface ActionListener { | ||
actionType: string; | ||
updater: (state: any, payload: any, blockInfo: BlockInfo, context: any) => void; | ||
} | ||
export interface Effect { | ||
actionType: string; | ||
effect: (state: any, payload: any, blockInfo: BlockInfo, context: any) => void; | ||
export declare type ActionCallback = (state: any, payload: any, blockInfo: BlockInfo, context: any) => void | string | Promise<void> | Promise<string>; | ||
export declare type StatelessActionCallback = (payload: any, block: Block, context: any) => void | Promise<void>; | ||
export interface Updater extends ActionListener { | ||
apply: ActionCallback; | ||
revert?: ActionCallback; | ||
} | ||
export interface Effect extends ActionListener { | ||
run: StatelessActionCallback; | ||
onRollback?: StatelessActionCallback; | ||
} | ||
export interface HandlerVersion { | ||
versionName: string; | ||
updaters: Updater[]; | ||
effects: Effect[]; | ||
} |
{ | ||
"name": "demux", | ||
"version": "2.0.0", | ||
"version": "3.0.0", | ||
"author": { | ||
@@ -5,0 +5,0 @@ "name": "Julien Heller", |
@@ -78,2 +78,3 @@ # demux-js [![Build Status](https://travis-ci.org/EOSIO/demux-js.svg?branch=develop)](https://travis-ci.org/EOSIO/demux-js) | ||
[EOSIO / demux-js-postgres](https://github.com/EOSIO/demux-js-postgres) * | Action Handler implementation for Postgres databases | ||
[Zapata / demux-js-bitshares](https://github.com/Zapata/demux-js-bitshares) | Action Reader implementations for BitShares blockchain | ||
@@ -80,0 +81,0 @@ *\* Officially supported by Block.one* |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
288590
593
122