Packages

A Elixir library for interacting with Ethereum

Current section

Files

Jump to
web3ex lib web3 dispatcher.ex
Raw

lib/web3/dispatcher.ex

defmodule Web3.Dispatcher do
@moduledoc false
require Logger
alias Web3
alias Web3.Middleware.Pipeline
defmodule Payload do
@moduledoc false
defstruct [
:app_id,
:chain_id,
:method_name,
:request,
:args,
:return_fn,
:method,
:metadata,
:returning,
:json_rpc_arguments,
middleware: []
]
end
def dispatch(%Payload{method: _method} = payload) do
pipeline = to_pipeline(payload)
pipeline = before_dispatch(pipeline, payload)
unless Pipeline.halted?(pipeline) do
pipeline
|> execute(payload)
|> Pipeline.response()
else
pipeline
|> after_failure(payload)
|> Pipeline.response()
end
end
defp execute(%Pipeline{} = pipeline, %Payload{} = payload) do
%{request: request, json_rpc_arguments: json_rpc_arguments} = pipeline
result = Web3.json_rpc(request, json_rpc_arguments)
# TODO [] retry if result is error
case result do
{:ok, response} ->
pipeline
|> Pipeline.respond({:ok, response})
|> after_dispatch(payload)
{:error, error} ->
pipeline
|> Pipeline.respond({:error, error})
|> after_failure(payload)
{:error, error, reason} ->
pipeline
|> Pipeline.assign(:error_reason, reason)
|> Pipeline.respond({:error, error})
|> after_failure(payload)
end
end
defp to_pipeline(%Payload{} = payload) do
struct(Pipeline, Map.from_struct(payload))
end
defp before_dispatch(%Pipeline{} = pipeline, %Payload{middleware: middleware}) do
Pipeline.chain(pipeline, :before_dispatch, middleware)
end
defp after_dispatch(%Pipeline{} = pipeline, %Payload{middleware: middleware}) do
Pipeline.chain(pipeline, :after_dispatch, middleware)
end
defp after_failure(%Pipeline{response: {:error, error}} = pipeline, %Payload{} = payload) do
%Payload{middleware: middleware} = payload
pipeline
|> Pipeline.assign(:error, error)
|> Pipeline.chain(:after_failure, middleware)
end
defp after_failure(
%Pipeline{response: {:error, error, reason}} = pipeline,
%Payload{} = payload
) do
%Payload{middleware: middleware} = payload
pipeline
|> Pipeline.assign(:error, error)
|> Pipeline.assign(:error_reason, reason)
|> Pipeline.chain(:after_failure, middleware)
end
defp after_failure(%Pipeline{} = pipeline, %Payload{} = payload) do
%Payload{middleware: middleware} = payload
Pipeline.chain(pipeline, :after_failure, middleware)
end
end