[#9] Defining the abstract custom protocol

This commit is contained in:
Felipe Ripoll 2018-06-05 15:14:04 -06:00
parent 167bc2f353
commit 824704b65f
11 changed files with 316 additions and 27 deletions

View File

@ -5,6 +5,17 @@
Storage and data-processing companion for the [poa-netstats-agent](https://github.com/poanetwork/poa-netstats-agent)
## Documentation
In order to build the documentation run
```
mix deps.get
mix docs
```
That command will create a `doc/` folder with the actual Documentation.
## Run Tests
In order to run the tests we have to run the command

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

View File

@ -1,18 +1,31 @@
defmodule POABackend do
@moduledoc """
Documentation for PoaBackend.
Storage and data-processing companion for the [poa-netstats-agent](https://github.com/poanetwork/poa-netstats-agent)
## Documentation
In order to build the documentation run
```
mix deps.get
mix docs
```
That command will create a `doc/` folder with the actual Documentation.
## Run Tests
In order to run the tests we have to run the command
```
mix test
```
`POABackend` comes also with a code analysis tool [Credo](https://github.com/rrrene/credo) and a types checker tool [Dialyxir](https://github.com/jeremyjh/dialyxir). In order to run them we have to run
```
mix credo
mix dialyzer
```
"""
@doc """
Hello world.
## Examples
iex> POABackend.hello
:world
"""
def hello do
:world
end
end

View File

@ -14,4 +14,4 @@ defmodule POABackend.Application do
opts = [strategy: :one_for_one, name: POABackend.Supervisor]
Supervisor.start_link(children, opts)
end
end
end

130
lib/poa_backend/protocol.ex Normal file
View File

@ -0,0 +1,130 @@
defmodule POABackend.Protocol do
@moduledoc """
## POA Protocol
This protocol defines the communication between the Agents and the POA Backend.
![POA Backend Architecture](./backend_architecture.png)
### Basic calls
Only those calls are allowed:
* session (*not implemented*) - In future in order to add authentication / authorization
* hello - Message sent when starting a communication with the backend
* ping - Ping message
* latency - The Agent will calculate the latency and send it to the Backend
* data - Specific message for a given receiver. It can be a metric itself or something else
* bye - Message sent when the Agent wants to close the communication explicitly
#### hello call
abstract request:
```json
{
id: String() # agent id
secret: String() # secret string for authentication/authorisation
data: Object() # optional data for receivers (i.e. Dashboard needs specific data here)
}
```
response:
```json
{
result: String() # “success” or “error”
payload: any() # optional payload
}
```
#### ping call
abstract request:
```json
{
id: String() # agent id
secret: String() # secret string for authentication/authorisation
}
```
response:
```json
{
result: String() # “success” or “error”
payload: String() # optional payload
}
```
#### latency call
abstract request:
```json
{
id: String() # agent id
secret: String() # secret string for authentication/authorisation
latency: Float() # latency in milliseconds
}
```
response:
```json
{
result: String() # “success” or “error”
payload: String() # optional payload
}
```
#### data call
abstract request:
```json
{
id: String() # agent id
secret: String() # secret string for authentication/authorisation
type: String() # data type (for now only ethereum_metrics)
data: Object() # metric data itself
}
```
response:
```json
{
result: String() # “success” or “error”
payload: String() # optional payload
}
```
#### bye call
abstract request:
```json
{
id: String() # agent id
secret: String() # secret string for authentication/authorisation
}
```
response:
```json
{
result: String() # “success” or “error”
payload: String() # optional payload
}
```
"""
end

View File

@ -0,0 +1,14 @@
defmodule POABackend.Protocol.DataType do
@moduledoc """
The protocol messages Data type.
Only one Data type is supported now in the backend and it is the ethereum metric
"""
@typedoc """
The Message Data Type. For now only ethereum metrics allowed
"""
@type t :: :ethereum_metric
end

View File

@ -0,0 +1,72 @@
defmodule POABackend.Protocol.Message do
alias __MODULE__
@moduledoc """
The message received from the Agent (inspired in [`Plug.Conn`](https://hexdocs.pm/plug/Plug.Conn.html)).
This module defines the Message received from the Agent and the main functions in order
to work with it.
## Message Fields
* `agent_id` - The Agent Id which sent the message to the backend.
* `receivers` - The list of the receivers which are going to receive this message. This list is retrieved from the config file and is mapped to the `data_type`
* `data_type` - The kind of data the message is carring. For now only `ethereum_metric` type is defined.
* `message_type` - This is the message type according to the custom protocol. Only `hello`, `data` and `latency` are defined
* `assigns` - Shared user data as a map
* `peer` - The actual TCP peer that connected, example: `{{127, 0, 0, 1}, 12345}`.
* `data` - The message payloda. It is a map
"""
defstruct [
agent_id: nil,
receivers: [],
data_type: nil,
message_type: nil,
assigns: %{},
peer: nil,
data: nil
]
@typedoc """
The Message struct.
That keeps all the message data and metadata
"""
@type t :: %__MODULE__{
agent_id: String.t(),
receivers: [atom()],
data_type: POABackend.CustomProtocol.DataType.t(),
message_type: POABackend.CustomProtocol.MessageType.t(),
assigns: %{atom() => any()},
peer: {:inet.ip_address(), :inet.port_number()},
data: Map.t()
}
@doc """
Returns a new Message Struct
"""
@spec new() :: t
def new() do
%Message{}
end
@doc """
Assigns a value to a key in the connection.
## Examples
iex> alias POABackend.Protocol.Message
iex> message = Message.new()
iex> message.assigns[:hello]
nil
iex> message = Message.assign(message, :hello, :world)
iex> message.assigns[:hello]
:world
"""
@spec assign(t, atom, term) :: t
def assign(%Message{assigns: assigns} = message, key, value) when is_atom(key) do
%{message | assigns: Map.put(assigns, key, value)}
end
end

View File

@ -0,0 +1,19 @@
defmodule POABackend.Protocol.MessageType do
@moduledoc """
Regarding the POA Protocol only 3 types of message can be processed in the backend.
Those message types are
* `hello` - When the communication starts
* `data` - When data is sent to the backend. Data is also called "metric data"
* `latency` - When the agent sent the latency value
"""
@typedoc """
The message type. Only `hello`, `data` and `latency` are allowed
"""
@type t :: :hello | :data | :latency
end

42
mix.exs
View File

@ -1,13 +1,17 @@
defmodule PoaBackend.MixProject do
defmodule POABackend.MixProject do
use Mix.Project
@version "0.1.0"
def project do
[
app: :poa_backend,
version: "0.1.0",
version: @version,
elixir: "~> 1.6",
start_permanent: Mix.env() == :prod,
deps: deps(),
aliases: aliases(),
docs: docs(),
test_coverage: [tool: ExCoveralls]
]
end
@ -15,7 +19,7 @@ defmodule PoaBackend.MixProject do
# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger],
extra_applications: [:logger, :cowboy, :plug],
mod: {POABackend.Application, []}
]
end
@ -23,10 +27,40 @@ defmodule PoaBackend.MixProject do
# Run "mix help deps" to learn about dependencies.
defp deps do
[
{:cowboy, "~> 1.0.0"},
{:plug, "~> 1.0"},
# Tests
{:credo, "~> 0.9", only: [:dev, :test], runtime: false},
{:dialyxir, "~> 0.5", only: [:dev], runtime: false},
{:excoveralls, "~> 0.8", only: [:test, :dev], runtime: false}
{:excoveralls, "~> 0.8", only: [:test, :dev], runtime: false},
# Docs
{:ex_doc, "~> 0.18", only: :dev, runtime: false}
]
end
defp docs do
[
source_ref: "v#{@version}",
main: "POABackend",
source_url: "https://github.com/poanetwork/poa-netstats-wharehouse",
groups_for_modules: [
"POA Protocol": [
POABackend.Protocol,
POABackend.Protocol.Message,
POABackend.Protocol.MessageType,
POABackend.Protocol.DataType
]
]
]
end
defp aliases do
[docs: ["docs", &picture/1]]
end
defp picture(_) do
File.cp("./assets/backend_architecture.png", "./doc/backend_architecture.png")
end
end

View File

@ -1,8 +0,0 @@
defmodule POABackendTest do
use ExUnit.Case
doctest POABackend
test "greets the world" do
assert POABackend.hello() == :world
end
end

View File

@ -0,0 +1,4 @@
defmodule Protocol.MessageTest do
use ExUnit.Case
doctest POABackend.Protocol.Message
end