84 lines
2.4 KiB
Elixir
84 lines
2.4 KiB
Elixir
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, Download.PubSub}
|
|
|
|
@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("asset:queued")
|
|
: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({"asset:queued", _}, state)
|
|
when state.connected? and state.outstanding_demand > 0 do
|
|
produce(0, state)
|
|
end
|
|
|
|
def handle_info({"asset:queued", _}, state),
|
|
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
|