[#6] designing the plugin system
This commit is contained in:
parent
e27aad9618
commit
f7b9d077e6
|
@ -1 +1,16 @@
|
|||
use Mix.Config
|
||||
|
||||
|
||||
# configuration for collectors. The format for each collector is {collector_process_id, module, [target_transfers], label, args}
|
||||
config :poa_agent,
|
||||
:collectors,
|
||||
[
|
||||
{:my_collector, POAAgent.Plugins.Collectors.MyCollector, [:my_transfer], :my_metrics, [host: "localhost", port: 1234]}
|
||||
]
|
||||
|
||||
# configuration for transfers. The format for each collector is {collector_process_id, module, args}
|
||||
config :poa_agent,
|
||||
:transfers,
|
||||
[
|
||||
{:my_transfer, POAAgent.Plugins.Transfers.MyTransfer, [ws_key: "mykey", other_stuff: "hello"]}
|
||||
]
|
|
@ -1,9 +0,0 @@
|
|||
defmodule POAAgent do
|
||||
@moduledoc """
|
||||
Documentation for PoaAgent.
|
||||
"""
|
||||
|
||||
def hello do
|
||||
:world
|
||||
end
|
||||
end
|
|
@ -0,0 +1,17 @@
|
|||
defmodule POAAgent.Application do
|
||||
@moduledoc false
|
||||
|
||||
use Application
|
||||
|
||||
def start(_type, _args) do
|
||||
import Supervisor.Spec
|
||||
|
||||
children = [
|
||||
supervisor(POAAgent.Plugins.Transfers.Supervisor, []),
|
||||
supervisor(POAAgent.Plugins.Collectors.Supervisor, [])
|
||||
]
|
||||
|
||||
opts = [strategy: :one_for_one, name: POAAgent.Supervisor]
|
||||
Supervisor.start_link(children, opts)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,66 @@
|
|||
defmodule POAAgent.Plugins.Collector do
|
||||
|
||||
@callback init_collector(args :: term()) ::
|
||||
{:ok, any()}
|
||||
|
||||
@callback collect(state :: any()) :: {:ok, data :: any(), state :: any()}
|
||||
|
||||
@callback terminate(reason, state :: term()) :: term()
|
||||
when reason: :normal | :shutdown | {:shutdown, term()}
|
||||
|
||||
defmacro __using__(_opt) do
|
||||
quote do
|
||||
@behaviour POAAgent.Plugins.Collector
|
||||
|
||||
@doc false
|
||||
def start_link(%{name: name} = state) do
|
||||
GenServer.start_link(__MODULE__, state, name: name)
|
||||
end
|
||||
|
||||
@doc false
|
||||
def init(state) do
|
||||
{:ok, internal_state} = init_collector(state[:args])
|
||||
set_collector_timer()
|
||||
{:ok, Map.put(state, :internal_state, internal_state)}
|
||||
end
|
||||
|
||||
@doc false
|
||||
def handle_call(_msg, _from, state) do
|
||||
{:noreply, state}
|
||||
end
|
||||
|
||||
@doc false
|
||||
def handle_info(:collect, state) do
|
||||
{:ok, data, internal_state} = collect(state.internal_state)
|
||||
transfer(data, state.label, state.transfers)
|
||||
set_collector_timer()
|
||||
{:noreply, %{state | internal_state: internal_state}}
|
||||
end
|
||||
def handle_info(_msg, state) do
|
||||
{:noreply, state}
|
||||
end
|
||||
|
||||
@doc false
|
||||
def handle_cast(msg, state) do
|
||||
{:noreply, state}
|
||||
end
|
||||
|
||||
@doc false
|
||||
def code_change(_old, state, _extra) do
|
||||
{:ok, state}
|
||||
end
|
||||
|
||||
@doc false
|
||||
def transfer(data, label, transfers) do
|
||||
Enum.each(transfers, &GenServer.cast(&1, %{label: label, data: data}))
|
||||
:ok
|
||||
end
|
||||
|
||||
defp set_collector_timer() do
|
||||
Process.send_after(self(), :collect, 5000) # TODO timeout must be configurable
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,18 @@
|
|||
defmodule POAAgent.Plugins.Collectors.MyCollector do
|
||||
use POAAgent.Plugins.Collector
|
||||
|
||||
def init_collector(args) do
|
||||
IO.puts "init_collector args = #{inspect args}"
|
||||
{:ok, :no_state}
|
||||
end
|
||||
|
||||
def collect(:no_state) do
|
||||
IO.puts "I am collecting data!"
|
||||
{:ok, "data retrieved", :no_state}
|
||||
end
|
||||
|
||||
def terminate(_reason, _state) do
|
||||
:ok
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,22 @@
|
|||
defmodule POAAgent.Plugins.Collectors.Supervisor do
|
||||
@moduledoc false
|
||||
|
||||
def start_link do
|
||||
Supervisor.start_link(__MODULE__, :ok, name: __MODULE__)
|
||||
end
|
||||
|
||||
def init(:ok) do
|
||||
import Supervisor.Spec
|
||||
|
||||
# create the children from the config file
|
||||
collectors = Application.get_env(:poa_agent, :collectors)
|
||||
|
||||
children = for {name, module, transfers, label, args} <- collectors do
|
||||
worker(module, [%{name: name, transfers: transfers, label: label, args: args}])
|
||||
end
|
||||
|
||||
opts = [strategy: :one_for_one]
|
||||
supervise(children, opts)
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,53 @@
|
|||
defmodule POAAgent.Plugins.Transfer do
|
||||
|
||||
@callback init_transfer(args :: term()) ::
|
||||
{:ok, any()}
|
||||
|
||||
@callback data_received(label :: atom(), data :: any(), state :: any()) :: {:ok, any()}
|
||||
|
||||
@callback terminate(reason, state :: term()) :: term()
|
||||
when reason: :normal | :shutdown | {:shutdown, term()}
|
||||
|
||||
defmacro __using__(_opt) do
|
||||
quote do
|
||||
@behaviour POAAgent.Plugins.Transfer
|
||||
|
||||
@doc false
|
||||
def start_link(%{name: name} = state) do
|
||||
GenServer.start_link(__MODULE__, state, name: name)
|
||||
end
|
||||
|
||||
@doc false
|
||||
def init(state) do
|
||||
{:ok, internal_state} = init_transfer(state[:args])
|
||||
{:ok, Map.put(state, :internal_state, internal_state)}
|
||||
end
|
||||
|
||||
@doc false
|
||||
def handle_call(_msg, _from, state) do
|
||||
{:noreply, state}
|
||||
end
|
||||
|
||||
@doc false
|
||||
def handle_info(_msg, state) do
|
||||
{:noreply, state}
|
||||
end
|
||||
|
||||
@doc false
|
||||
def handle_cast(%{label: label, data: data}, state) do
|
||||
{:ok, internal_state} = data_received(label, data, state.internal_state)
|
||||
{:noreply, %{state | internal_state: internal_state}}
|
||||
end
|
||||
def handle_cast(msg, state) do
|
||||
{:noreply, state}
|
||||
end
|
||||
|
||||
@doc false
|
||||
def code_change(_old, state, _extra) do
|
||||
{:ok, state}
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,18 @@
|
|||
defmodule POAAgent.Plugins.Transfers.MyTransfer do
|
||||
use POAAgent.Plugins.Transfer
|
||||
|
||||
def init_transfer(args) do
|
||||
IO.puts "init_transfer args = #{inspect args}"
|
||||
{:ok, :no_state}
|
||||
end
|
||||
|
||||
def data_received(label, data, state) do
|
||||
IO.puts "Received data with label #{inspect label}, data #{inspect data} and internal_state #{inspect state}"
|
||||
{:ok, :no_state}
|
||||
end
|
||||
|
||||
def terminate(_reason, _state) do
|
||||
:ok
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,22 @@
|
|||
defmodule POAAgent.Plugins.Transfers.Supervisor do
|
||||
@moduledoc false
|
||||
|
||||
def start_link do
|
||||
Supervisor.start_link(__MODULE__, :ok, name: __MODULE__)
|
||||
end
|
||||
|
||||
def init(:ok) do
|
||||
import Supervisor.Spec
|
||||
|
||||
# create the children from the config file
|
||||
transfers = Application.get_env(:poa_agent, :transfers)
|
||||
|
||||
children = for {name, module, args} <- transfers do
|
||||
worker(module, [%{name: name, args: args}])
|
||||
end
|
||||
|
||||
opts = [strategy: :one_for_one]
|
||||
supervise(children, opts)
|
||||
end
|
||||
|
||||
end
|
3
mix.exs
3
mix.exs
|
@ -13,7 +13,8 @@ defmodule POAAgent.MixProject do
|
|||
|
||||
def application do
|
||||
[
|
||||
extra_applications: [:logger]
|
||||
extra_applications: [:logger],
|
||||
mod: {POAAgent.Application, []}
|
||||
]
|
||||
end
|
||||
|
||||
|
|
|
@ -3,6 +3,6 @@ defmodule POAAgentTest do
|
|||
doctest POAAgent
|
||||
|
||||
test "greets the world" do
|
||||
assert POAAgent.hello() == :world
|
||||
# assert POAAgent.hello() == :world
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue