Packages
forge_sdk
0.40.1
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.7
1.0.6
1.0.4
1.0.4-p1
1.0.4-p0
1.0.3
1.0.2
1.0.2-p1
1.0.1
1.0.1-p1
1.0.0
0.40.6
0.40.5
0.40.4
0.40.3
0.40.2
0.40.1
0.40.0
0.39.1
0.39.0
0.38.6
0.38.5
0.38.4
0.38.3
0.38.2
0.38.1
0.38.0
0.37.5
0.37.4
0.37.3
0.37.2
0.37.1
0.37.0
0.34.0
0.33.2
0.33.1
0.33.0
0.32.2
0.32.1
0.32.0
0.31.1
0.31.0
0.30.0
0.29.1
0.29.0
0.28.3
0.28.2
0.28.1
0.28.0
0.27.4
0.27.3
0.27.2
0.27.1
0.27.0
0.26.6
0.26.5
0.26.4
0.26.3
0.26.1
0.26.0
Elixir / Erlang version of the SDK for Forge framework.
Current section
Files
Jump to
Current section
Files
lib/forge_sdk/conn/rpc_conn.ex
defmodule ForgeSdk.Conn do
@moduledoc """
Wrapper for ForgeSdk gRPC connection
"""
use TypedStruct
typedstruct do
field :name, String.t()
field :endpoint, String.t()
field :chan, GRPC.Channel.t() | nil, default: nil
field :chain_id, String.t(), default: ""
field :decimal, non_neg_integer()
field :gas, map(), default: %{}
end
end
defmodule ForgeSdk.RpcConn do
@moduledoc """
Persistent gRPC connection to Forge GRPC server.
"""
use Connection
require Logger
alias ForgeSdk.Conn
alias GRPC.Stub, as: Client
# ------------------------------------------------------------------
# api
# ------------------------------------------------------------------
@doc """
The parameters for start_link/3 are:
* `endpoint` - the address of gRPC server in `host:port` format
* `opts` - the options for gRPC http2 client `gun`
* `callback` - the 0 arity function to be called when gRPC connection is established
"""
@spec start_link(atom(), String.t(), Keyword.t(), (() -> any) | nil) :: GenServer.on_start()
def start_link(name, endpoint, opts, callback) do
Connection.start_link(__MODULE__, {endpoint, name, opts, callback}, name: name)
end
@spec get_conn(atom()) :: ForgeSdk.Conn.t() | {:error, :closed}
def get_conn(name) do
Connection.call(name, :get_conn)
end
@spec get_config(atom()) :: String.t() | {:error, :closed}
def get_config(name) do
Connection.call(name, :get_config)
end
@spec update_config(atom(), String.t()) :: any()
def update_config(name, config) do
Connection.cast(name, {:update_config, config})
end
@spec update_gas(atom()) :: any()
def update_gas(name) do
Connection.cast(name, :update_gas)
end
@spec close(atom()) :: any()
def close(name), do: Connection.call(name, :close)
# ------------------------------------------------------------------
# callbacks
# ------------------------------------------------------------------
def init({"unix://" <> endpoint, name, opts, callback}),
do:
{:connect, :init,
%{opts: opts, callback: callback, config: %{}, conn: %Conn{name: name, endpoint: endpoint}}}
def init({"tcp://" <> endpoint, name, opts, callback}),
do:
{:connect, :init,
%{opts: opts, callback: callback, config: %{}, conn: %Conn{name: name, endpoint: endpoint}}}
def connect(
_,
%{conn: %{chan: nil, endpoint: endpoint} = conn, opts: opts, callback: callback} = state
) do
Logger.info("Forge ABI RPC: reconnect to #{endpoint}...")
case Client.connect(endpoint, opts) do
{:ok, chan} ->
Process.monitor(chan.adapter_payload.conn_pid)
# send(self(), :get_config)
callback && spawn(fn -> callback.(conn.name) end)
{:ok, %{state | conn: %{conn | chan: chan}}}
{:error, _} ->
{:backoff, 5000, state}
end
end
def disconnect(info, %{conn: %{chan: chan} = conn} = state) do
{:ok, _} = Client.disconnect(chan)
case info do
{:close, from} -> Connection.reply(from, :ok)
{:error, :closed} -> Logger.error("Forge SDK RPC connection closed")
{:error, reason} -> Logger.error("Forge SDK RPC connection error: #{inspect(reason)}")
end
{:connect, :reconnect, %{state | conn: %{conn | chan: nil}}}
end
# call
def handle_call(_, _, %{chan: nil} = state) do
{:reply, {:error, :closed}, state}
end
def handle_call(:get_conn, _from, %{conn: conn} = state) do
{:reply, conn, state}
end
def handle_call(:get_config, _from, %{config: config} = state) do
{:reply, config, state}
end
def handle_call(:close, from, state) do
{:disconnect, {:close, from}, state}
end
# cast
def handle_cast({:update_config, config}, %{conn: conn} = state) do
config = Jason.decode!(config)
chain_id = Map.get(config, "chain_id")
decimal = Map.get(config, "decimal")
{:noreply, %{state | conn: %{conn | chain_id: chain_id, decimal: decimal}, config: config}}
end
def handle_cast(:update_gas, %{conn: conn} = state) do
me = self()
spawn(fn ->
case ForgeSdk.get_forge_state(conn.name) do
nil -> Process.send_after(me, {:"$gen_cast", :update_gas}, 1000)
%{gas: gas} -> Connection.cast(me, {:update_gas, gas})
end
end)
{:noreply, state}
end
def handle_cast({:update_gas, gas}, %{conn: conn} = state) do
{:noreply, %{state | conn: %{conn | gas: gas}}}
end
# info
def handle_info(
{:DOWN, _ref, :process, pid, reason},
%{conn: %{chan: %{adapter_payload: %{conn_pid: pid}}} = conn} = state
) do
Logger.debug("Forge ABI RPC: connection down with reason #{inspect(reason)}...")
{:connect, :reconnect, %{state | conn: %{conn | chan: nil}}}
end
def handle_info(msg, state) do
Logger.debug("Got unexpected info message: #{inspect(msg)}")
{:noreply, state}
end
end