Current section

Files

Jump to
honeylixir lib response_queue.ex
Raw

lib/response_queue.ex

defmodule Honeylixir.ResponseQueue do
@moduledoc """
Available for tracking responses for each event sent via `Honeylixir.Transmission`.
Currently does not block when the queue is full.
"""
use Agent
@doc false
def start_link(%{max_response_queue_size: max_response_queue_size}, opts \\ []) do
name = Access.get(opts, :name, __MODULE__)
Agent.start_link(
fn -> %{max_size: max_response_queue_size, size: 0, responses: :queue.new()} end,
name: name
)
end
@doc """
Adds a `Honeylixir.Response` to the queue unless max size has been reached at
which point the value is dropped.
"""
@spec add(Honeylixir.Response.t(), atom()) :: :ok
def add(%Honeylixir.Response{} = resp, name \\ __MODULE__) do
Agent.update(name, Honeylixir.ResponseQueue, :do_update, [resp])
end
@doc """
Takes the oldest `Honeylixir.Response` from the queue and returns it unless
the queue is empty in which case `nil` is returned.
"""
@spec pop(atom()) :: nil | Honeylixir.Response.t()
def pop(name \\ __MODULE__) do
Agent.get_and_update(name, Honeylixir.ResponseQueue, :do_pop, [])
end
@doc false
def do_update(state, %Honeylixir.Response{} = resp) do
cond do
state[:size] == state[:max_size] ->
state
true ->
%{state | size: state[:size] + 1, responses: :queue.in(resp, state[:responses])}
end
end
@doc false
def do_pop(state) do
case :queue.out(state[:responses]) do
{:empty, _} ->
{nil, state}
{{:value, item}, remaining_queue} ->
new_state = %{state | size: state[:size] - 1, responses: remaining_queue}
{item, new_state}
end
end
end