Refactor handler registration scoped to event modules - #151
Conversation
e5139de to
79978bc
Compare
d4b55f1 to
615eda0
Compare
79978bc to
04dccd4
Compare
615eda0 to
dfa9fe1
Compare
|
|
||
| let getContractRegisterArgs = (contextEnv, ~inMemoryStore) => { | ||
| RegisteredEvents.event: contextEnv.event, | ||
| Types.Handlers.event: contextEnv.event, |
There was a problem hiding this comment.
RegesteredEvents module is removed and it's types are moved into Types.Handlers
| ? executeSetEntityWithHistory | ||
| : executeDbFunctionsEntity | ||
| let entityDbExecutionComposer = | ||
| RegisterHandlers.getConfig()->Config.shouldRollbackOnReorg |
There was a problem hiding this comment.
Config.getGenerated is removed, it now needs to be accessed from RegisterHandlers.getConfig() to ensure handlers are all registered (with event options) before instantiating the workers
| {{/with}} | ||
| } | ||
| {{/if}} | ||
| let makeGeneratedConfig = () => { |
There was a problem hiding this comment.
I would suggest reviewing this with hide whitespace setting
There was a problem hiding this comment.
Thanks, I didn't know about the option
| let eventModLookup = | ||
| contracts | ||
| ->Belt.Array.flatMap(contract => contract.events) | ||
| ->EventModLookup.fromArrayOrThrow(~chain) |
There was a problem hiding this comment.
evenModLookup is now instantiated when this makeGeneratedConfig is run and passed to the chain worker
| @genType | ||
| module Handlers = { | ||
| type args<'eventArgs, 'context> = { | ||
| event: eventLog<'eventArgs>, | ||
| context: 'context, | ||
| } | ||
|
|
||
| type contractRegisterArgs<'eventArgs> = args<'eventArgs, contractRegistrations> | ||
| type contractRegister<'eventArgs> = contractRegisterArgs<'eventArgs> => unit | ||
|
|
||
| type loaderArgs<'eventArgs> = args<'eventArgs, loaderContext> | ||
| type loader<'eventArgs, 'loaderReturn> = loaderArgs<'eventArgs> => promise<'loaderReturn> | ||
|
|
||
| type handlerArgs<'eventArgs, 'loaderReturn> = { | ||
| event: eventLog<'eventArgs>, | ||
| context: handlerContext, | ||
| loaderReturn: 'loaderReturn, | ||
| } | ||
|
|
||
| type handler<'eventArgs, 'loaderReturn> = handlerArgs<'eventArgs, 'loaderReturn> => promise<unit> | ||
|
|
||
| type loaderHandler<'eventArgs, 'loaderReturn> = { | ||
| loader: loader<'eventArgs, 'loaderReturn>, | ||
| handler: handler<'eventArgs, 'loaderReturn>, | ||
| } | ||
|
|
||
| type eventOptions = { | ||
| wildcard: bool, | ||
| topicSelections: array<LogSelection.topicSelection>, | ||
| } | ||
|
|
||
| let getDefaultEventOptions = (~topic0) => { | ||
| wildcard: false, | ||
| topicSelections: [LogSelection.makeTopicSelection(~topic0=[topic0])->Utils.unwrapResultExn], | ||
| } | ||
|
|
||
| type registeredEvent<'eventArgs, 'loaderReturn> = { | ||
| loaderHandler?: loaderHandler<'eventArgs, 'loaderReturn>, | ||
| contractRegister?: contractRegister<'eventArgs>, | ||
| eventOptions: eventOptions, | ||
| } |
There was a problem hiding this comment.
This chunk is basically just moved from RegisteredEvents.res
| module Register: { | ||
| type t<'eventArgs> | ||
| let make: (~topic0: string, ~contractName: string, ~eventName: string) => t<'eventArgs> | ||
| let setLoaderHandler: ( | ||
| t<'eventArgs>, | ||
| loaderHandler<'eventArgs, 'loaderReturn>, | ||
| ~eventOptions: option<eventOptions>, | ||
| ~logger: Pino.t=?, | ||
| ) => unit | ||
| let setContractRegister: ( | ||
| t<'eventArgs>, | ||
| contractRegister<'eventArgs>, | ||
| ~eventOptions: option<eventOptions>, | ||
| ~logger: Pino.t=?, | ||
| ) => unit | ||
| let getLoaderHandler: t<'eventArgs> => option<loaderHandler<'eventArgs, 'loaderReturn>> | ||
| let getContractRegister: t<'eventArgs> => option<contractRegister<'eventArgs>> | ||
| let getEventOptions: t<'eventArgs> => eventOptions | ||
| let hasRegistration: t<'eventArgs> => bool | ||
| } = { | ||
| type loaderReturn | ||
|
|
||
| type t<'eventArgs> = { | ||
| contractName: string, | ||
| eventName: string, | ||
| topic0: string, | ||
| mutable loaderHandler: option<loaderHandler<'eventArgs, loaderReturn>>, | ||
| mutable contractRegister: option<contractRegister<'eventArgs>>, | ||
| mutable eventOptions: option<eventOptions>, | ||
| } | ||
|
|
||
| let getLoaderHandler = (t: t<'eventArgs>): option<loaderHandler<'eventArgs, 'loaderReturn>> => | ||
| t.loaderHandler->( | ||
| Utils.magic: option<loaderHandler<'eventArgs, loaderReturn>> => option< | ||
| loaderHandler<'eventArgs, 'loaderReturn>, | ||
| > | ||
| ) | ||
|
|
||
| let getContractRegister = (t: t<'eventArgs>): option<contractRegister<'eventArgs>> => | ||
| t.contractRegister | ||
|
|
||
| let getEventOptions = ({eventOptions, topic0}: t<'eventArgs>): eventOptions => | ||
| switch eventOptions { | ||
| | Some(eventOptions) => eventOptions | ||
| | None => getDefaultEventOptions(~topic0) | ||
| } | ||
|
|
||
| let hasRegistration = ({loaderHandler, contractRegister}) => | ||
| loaderHandler->Belt.Option.isSome || contractRegister->Belt.Option.isSome | ||
|
|
||
| let make = (~topic0, ~contractName, ~eventName) => { | ||
| contractName, | ||
| eventName, | ||
| topic0, | ||
| loaderHandler: None, | ||
| contractRegister: None, | ||
| eventOptions: None, | ||
| } | ||
|
|
||
| type eventNamespace = {contractName: string, eventName: string} | ||
| exception DuplicateEventRegistration(eventNamespace) | ||
|
|
||
| let setEventOptions = (t: t<'eventArgs>, value: eventOptions, ~logger=Logging.logger) => { | ||
| switch t.eventOptions { | ||
| | None => t.eventOptions = Some(value) | ||
| | Some(_) => | ||
| let eventNamespace = {contractName: t.contractName, eventName: t.eventName} | ||
| DuplicateEventRegistration(eventNamespace)->ErrorHandling.mkLogAndRaise( | ||
| ~logger=Logging.createChildFrom(~logger, ~params=eventNamespace), | ||
| ~msg="Duplicate eventOptions in handlers not allowed", | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| let setLoaderHandler = ( | ||
| t: t<'eventArgs>, | ||
| value: loaderHandler<'eventArgs, 'loaderReturn>, | ||
| ~eventOptions, | ||
| ~logger=Logging.logger, | ||
| ) => { | ||
| switch t.loaderHandler { | ||
| | None => | ||
| t.loaderHandler = | ||
| value | ||
| ->(Utils.magic: loaderHandler<'eventArgs, 'loaderReturn> => loaderHandler< | ||
| 'eventArgs, | ||
| loaderReturn, | ||
| >) | ||
| ->Some | ||
| | Some(_) => | ||
| let eventNamespace = {contractName: t.contractName, eventName: t.eventName} | ||
| DuplicateEventRegistration(eventNamespace)->ErrorHandling.mkLogAndRaise( | ||
| ~logger=Logging.createChildFrom(~logger, ~params=eventNamespace), | ||
| ~msg="Duplicate registration of event handlers not allowed", | ||
| ) | ||
| } | ||
|
|
||
| switch eventOptions { | ||
| | Some(eventOptions) => t->setEventOptions(eventOptions, ~logger) | ||
| | None => () | ||
| } | ||
| } |
There was a problem hiding this comment.
This is a new abstraction for registering handlers with with options on an event module
| open Belt | ||
| type eventMod = module(Types.InternalEvent) | ||
|
|
||
| type errorKind = WildcardSighashCollision | Duplicate | ||
| type eventError = {eventMod: eventMod, errorKind: errorKind} | ||
| module ContractEventMods = { | ||
| type t = { | ||
| all: array<eventMod>, | ||
| byContractName: dict<eventMod>, | ||
| } | ||
|
|
There was a problem hiding this comment.
Strange this wasn't tracked as a move... but there are quite a lot of changes here as well.
67e050f to
c7acf83
Compare
| let set = ( | ||
| inMemTable: t<'entity>, | ||
| entityUpdate: Types.entityUpdate<'entity>, | ||
| ~shouldRollbackOnReorg, |
There was a problem hiding this comment.
Passing shouldRollbackOnReorg in here because using RegisterHandlers causes dependency cycle
There was a problem hiding this comment.
Nice, we had to get rid of Config.getGenerated() anyways
| let findWildcard = ({all}) => { | ||
| all->Js.Array2.find(event => event->isWildcard) | ||
| } |
There was a problem hiding this comment.
With the new design you can add wildcard: option<eventMod> field to the ContractEventMods.t type, which will simplify the hasWildcardCollision and allow getting rid of the findWildcard function
|
|
||
| let set = ({all, byContractName}: t, eventMod: eventMod) => { | ||
| let module(Event) = eventMod | ||
| switch byContractName->Js.Dict.get(Event.contractName) { |
There was a problem hiding this comment.
A tiny thing, but there's Utils.Dict.dangerouslyGetNonOption, which doesn't have an unnecessary runtime overhead.
There was a problem hiding this comment.
Ok cool, I think it makes sense to improve for the get function but these values will only be set at startup
DZakh
left a comment
There was a problem hiding this comment.
Amazing 👍 The only comment is about improving the wildcard eventMod lookup 👌
04dccd4 to
a1e2351
Compare
c7acf83 to
53d74dc
Compare
Refactors: