podbox_ash/lib/podbox/download/producer.ex

85 lines
2.4 KiB
Elixir
Raw Normal View History

2024-05-22 13:17:21 +12:00
defmodule Podbox.Download.Producer do
@moduledoc """
A GenStage producer which only produces values when connected to the internet.
This only works when `VintageNet` is present (ie we're running on a target),
otherwise we just assume that we're always connected.
"""
use GenStage
alias Podbox.{Download, Download.Asset, Download.ConnectivityMonitor, PubSub}
2024-05-22 13:17:21 +12:00
@poll_interval :timer.seconds(30)
@type state :: %{
connected?: boolean,
outstanding_demand: non_neg_integer()
}
@doc false
@spec start_link(Keyword.t()) :: GenServer.on_start()
def start_link(opts), do: GenStage.start_link(__MODULE__, opts, name: __MODULE__)
@doc "Return the current status of the producer"
def status, do: GenServer.call(__MODULE__, :status)
@doc false
@impl true
@spec init(Keyword.t()) :: {:producer, state}
def init(_opts) do
PubSub.subscribe("internet:connected?")
PubSub.subscribe("download:asset:queued")
2024-05-22 13:17:21 +12:00
:timer.send_interval(@poll_interval, :poll)
{:producer, %{connected?: ConnectivityMonitor.connected?(), outstanding_demand: 0}}
end
@doc false
@impl true
@spec handle_info(any, state) :: {:noreply, [], state}
def handle_info({"internet:connected?", connect_status}, state),
do: {:noreply, [], %{state | connected?: connect_status}}
def handle_info({"download:asset:queued", _}, state)
2024-05-22 13:17:21 +12:00
when state.connected? and state.outstanding_demand > 0 do
produce(0, state)
end
def handle_info({"download:asset:queued", _}, state),
2024-05-22 13:17:21 +12:00
do: {:noreply, [], state}
def handle_info(:poll, state) when state.connected? do
produce(0, state)
end
def handle_info(:poll, state), do: {:noreply, [], state}
@doc false
@impl true
def handle_call(:status, _, state) do
{:reply, state, [], state}
end
@doc false
@impl true
@spec handle_demand(non_neg_integer, state) :: {:noreply, [Asset.t()], state}
def handle_demand(demand, state) when state.connected? do
produce(demand, state)
end
def handle_demand(demand, state),
do: {:noreply, [], %{state | outstanding_demand: state.outstanding_demand + demand}}
defp produce(demand, state) do
demand = state.outstanding_demand + demand
if demand == 0 do
{:noreply, [], state}
else
dequeued = Download.dequeue!(demand)
demand = demand - length(dequeued)
{:noreply, dequeued, %{state | outstanding_demand: demand}}
end
end
end