Skip to content

Commit

Permalink
Merge pull request #10 from wowica/send-query
Browse files Browse the repository at this point in the history
Expose send_query as top-level from StateQuery
  • Loading branch information
caike authored Jan 18, 2024
2 parents b868239 + 4814a17 commit a63dc5c
Show file tree
Hide file tree
Showing 9 changed files with 51 additions and 63 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ xogmios-*.tar
/tmp/
.DS_Store
.iex.exs
.elixir_ls
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

![CI Status](https://github.com/wowica/xogmios/actions/workflows/ci.yml/badge.svg)

An Elixir client for Cardano's [Ogmios](https://github.com/CardanoSolutions/ogmios).
An Elixir client for [Ogmios](https://github.com/CardanoSolutions/ogmios).

Currently supports the **Chain Synchronization** and **State Query** Ouroboros mini-protocol.
> Ogmios is a lightweight bridge interface for a Cardano node. It offers a WebSockets API that enables local clients to speak Ouroboros' mini-protocols via JSON/RPC. - https://ogmios.dev/
It currently only partially supports the **Chain Synchronization** and **State Query** mini-protocols. See [Examples](#examples) section below for information on how to use it.

## Installing

Expand All @@ -13,11 +15,13 @@ Add the dependency to `mix.exs`:
```elixir
defp deps do
[
{:xogmios, github: "wowica/xogmios", ref: "403384c"}
{:xogmios, github: "wowica/xogmios"}
]
end
```

Not yet available on Hex.

## Examples

See [ChainSyncClient](./examples/chain_sync_client.ex) and [StateQueryClient](./examples/state_query_client.ex)
Expand Down
25 changes: 8 additions & 17 deletions examples/state_query_client.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,29 +20,20 @@ defmodule StateQueryClient do
"""

use Xogmios, :state_query
alias Xogmios.StateQuery

@spec start_link(keyword()) :: {:ok, pid()} | {:error, any()}
def start_link(opts) do
Xogmios.start_state_link(__MODULE__, opts)
end

def get_current_epoch() do
case send_query(:get_current_epoch) do
{:ok, result} -> result
{:error, reason} -> "Something went wrong #{inspect(reason)}"
end
@spec get_current_epoch(pid() | atom()) :: {:ok, map()} | {:error, map()}
def get_current_epoch(pid \\ __MODULE__) do
StateQuery.send_query(pid, :get_current_epoch)
end

def get_era_start() do
case send_query(:get_era_start) do
{:ok, result} -> result
{:error, reason} -> "Something went wrong #{inspect(reason)}"
end
end

def get_bananas() do
case send_query(:get_bananas) do
{:ok, result} -> result
{:error, reason} -> "Something went wrong #{inspect(reason)}"
end
@spec get_era_start(pid() | atom()) :: {:ok, map()} | {:error, map()}
def get_era_start(pid \\ __MODULE__) do
StateQuery.send_query(pid, :get_era_start)
end
end
34 changes: 16 additions & 18 deletions lib/xogmios/state_query.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ defmodule Xogmios.StateQuery do
This module interfaces with the State Query protocol.
"""

alias Xogmios.StateQuery
alias Xogmios.StateQuery.Messages
alias Xogmios.StateQuery.Response
alias Xogmios.StateQuery.Server
Expand All @@ -19,13 +18,26 @@ defmodule Xogmios.StateQuery do

@allowed_queries Map.keys(@query_messages)

def fetch_query_message(query) when query in @allowed_queries,
@doc """
Sends a State Query call to the server and returns a response. This function is synchornous and takes two arguments:
1. (Optional) A process reference. If none given, it defaults to __MODULE__.
2. The query to run. It currently accepts the following values: `:get_current_epoch`, `:get_era_start`.
"""
@spec send_query(pid() | atom(), atom()) :: {:ok, any()} | {:error, any()}
def send_query(client \\ __MODULE__, query) do
with {:ok, message} <- fetch_query_message(query),
{:ok, %Response{} = response} <- call_query(client, message) do
{:ok, response.result}
end
end

defp fetch_query_message(query) when query in @allowed_queries,
do: Map.fetch(@query_messages, query)

def fetch_query_message(query),
defp fetch_query_message(query),
do: {:error, "Unsupported query #{inspect(query)}"}

def call_query(client, message) do
defp call_query(client, message) do
case GenServer.call(client, {:send_message, message}) do
{:ok, response} -> {:ok, response}
{:error, reason} -> {:error, reason}
Expand All @@ -36,20 +48,6 @@ defmodule Xogmios.StateQuery do
quote do
use GenServer

## Client API

@doc """
Sends a State Query call to the server and returns a response.
This function is synchornous.
"""
@spec send_query(term(), term()) :: {:ok, any()} | {:error, any()}
def send_query(client \\ __MODULE__, query) do
with {:ok, message} <- StateQuery.fetch_query_message(query),
{:ok, %Response{} = response} <- StateQuery.call_query(client, message) do
{:ok, response.result}
end
end

## Callbacks

@impl true
Expand Down
5 changes: 2 additions & 3 deletions lib/xogmios/state_query/messages.ex
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
defmodule Xogmios.StateQuery.Messages do
@moduledoc """
This module returns messages for the State Query protocol
"""
@moduledoc false
# This module returns messages for the State Query protocol

alias Jason.DecodeError

Expand Down
5 changes: 2 additions & 3 deletions lib/xogmios/state_query/response.ex
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
defmodule Xogmios.StateQuery.Response do
@moduledoc """
This module provides a common interface for responses from a State Queries
"""
@moduledoc false
# This module provides a common interface for responses from a State Queries

defstruct [:result]
end
9 changes: 4 additions & 5 deletions lib/xogmios/state_query/server.ex
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
defmodule Xogmios.StateQuery.Server do
@moduledoc """
This module implements the callbacks necessary for receiving asynchronous responses from
the WebSocket server. It acts as an synchronous interface for clients of Xogmios.StateQuery.
It uses GenServer.reply/2 to respond to GenServer.call/2 calls from Xogmios.StateQuery.send_query/2.
"""
@moduledoc false
# This module implements the callbacks necessary for receiving asynchronous responses from
# the WebSocket server. It acts as an synchronous interface for clients of Xogmios.StateQuery.
# It uses GenServer.reply/2 to respond to GenServer.call/2 calls from Xogmios.StateQuery.send_query/2.

@behaviour :websocket_client

Expand Down
4 changes: 2 additions & 2 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ defmodule Xogmios.MixProject do
~r/\.TestConnection/,
~r/\.TestHandler/,
~r/\.TestServer/,
Xogmios.ClientExampleA,
Xogmios.ClientExampleB
ChainSyncClient,
StateQueryClient
]
],
package: package(),
Expand Down
21 changes: 9 additions & 12 deletions test/state_query_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -15,31 +15,28 @@ defmodule Xogmios.StateQueryTest do

defmodule DummyClient do
use Xogmios, :state_query
alias Xogmios.StateQuery

def start_link(opts) do
Xogmios.start_state_link(__MODULE__, opts)
end

def get_current_epoch() do
case send_query(:get_current_epoch) do
{:ok, result} -> result
{:error, reason} -> "Something went wrong #{inspect(reason)}"
end
def get_current_epoch(pid \\ __MODULE__) do
StateQuery.send_query(pid, :get_current_epoch)
end

def get_bananas() do
case send_query(:get_bananas) do
{:ok, result} -> result
{:error, reason} -> "Something went wrong #{inspect(reason)}"
end
def unsupported_query(pid \\ __MODULE__) do
StateQuery.send_query(pid, :unsupported_query)
end
end

test "returns current epoch" do
pid = start_supervised!({DummyClient, url: @ws_url})
assert is_pid(pid)
Process.sleep(1_000)
assert DummyClient.get_current_epoch() == 333
assert DummyClient.get_bananas() =~ "Something went wrong"
expected_epoch = 333
assert {:ok, ^expected_epoch} = DummyClient.get_current_epoch()
assert {:error, error_message} = DummyClient.unsupported_query()
assert error_message == "Unsupported query :unsupported_query"
end
end

0 comments on commit a63dc5c

Please sign in to comment.