Merge pull request #10 from poanetwork/ferigis.9.define_custom_protocol
[#9] Defining the abstract custom protocol
This commit is contained in:
commit
e2ff4a48c7
11
README.md
11
README.md
|
@ -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 |
|
@ -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
|
||||
|
|
|
@ -14,4 +14,4 @@ defmodule POABackend.Application do
|
|||
opts = [strategy: :one_for_one, name: POABackend.Supervisor]
|
||||
Supervisor.start_link(children, opts)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
42
mix.exs
|
@ -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
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
defmodule POABackendTest do
|
||||
use ExUnit.Case
|
||||
doctest POABackend
|
||||
|
||||
test "greets the world" do
|
||||
assert POABackend.hello() == :world
|
||||
end
|
||||
end
|
|
@ -0,0 +1,4 @@
|
|||
defmodule Protocol.MessageTest do
|
||||
use ExUnit.Case
|
||||
doctest POABackend.Protocol.Message
|
||||
end
|
Loading…
Reference in New Issue