lib/runbox/runtime/stage/state_generator.ex

defmodule Runbox.Runtime.Stage.StateGenerator do
  @moduledoc """
  Module generates state of run components running on slave node.
  """

  alias Runbox.Runtime.Stage.UnitRegistry
  alias Toolbox.Runtime.Stage.Unit
  alias Toolbox.Scenario.Template.StageBased, as: Template
  require Logger

  @doc """
  Generates state for component template.
  """
  @spec generate_for_component({:template, atom}, String.t()) :: {String.t(), UnitRegistry.t()}
  def generate_for_component({:template, template}, run_id) do
    id = Atom.to_string(template)

    unit_registry =
      template
      |> Template.instances()
      |> Enum.map(fn
        {:unit, id, attributes} ->
          %{id: id, attributes: attributes}

        unknown_unit_def ->
          Logger.warn(
            "Ignored unknown instance definition of #{template} in run #{run_id} - #{inspect(unknown_unit_def)}"
          )

          []
      end)
      |> List.flatten()
      |> Enum.map(fn %{id: id, attributes: attrs} -> Unit.new(id, %{}, attrs) end)
      |> create_unit_registry(template)

    {id, unit_registry}
  end

  defp create_unit_registry(units, template) do
    unit_routings =
      template
      |> Template.subscriptions()
      |> Enum.map(fn {_, _, unit_routing} -> unit_routing end)
      |> List.flatten()

    empty_unit_registry = UnitRegistry.new(unit_routings)

    Enum.reduce(units, empty_unit_registry, fn unit, unit_registry ->
      unit_registry = UnitRegistry.register(unit_registry, unit)
      unit_registry
    end)
  end
end