58 lines
1.7 KiB
Elixir
58 lines
1.7 KiB
Elixir
defmodule FeedReader.VerifiedParser do
|
|
@moduledoc "Validates a complete XML pass before returning a feed event session."
|
|
|
|
alias FeedReader.{Parser, Session}
|
|
|
|
@default_max_passes 5
|
|
|
|
@doc "Validates a local or library-owned file before exposing its events."
|
|
@spec stream_file(Path.t(), keyword()) :: {:ok, Session.t()} | {:error, term()}
|
|
def stream_file(path, opts) do
|
|
max_passes = positive_option(opts, :max_parse_passes, @default_max_passes)
|
|
|
|
with :ok <- validate(path, opts),
|
|
:ok <- require_delivery_pass(max_passes),
|
|
{:ok, %Session{} = session} <- Parser.stream_file(path, opts) do
|
|
resource = owned_resource(opts)
|
|
|
|
events =
|
|
Stream.transform(
|
|
session.events,
|
|
fn -> :ok end,
|
|
fn event, state -> {[event], state} end,
|
|
fn _state ->
|
|
if resource, do: FeedReader.close(%Session{resource: resource}), else: :ok
|
|
end
|
|
)
|
|
|
|
{:ok, %Session{session | events: events, resource: resource}}
|
|
end
|
|
end
|
|
|
|
defp validate(path, opts) do
|
|
with {:ok, %{events: events}} <- Parser.stream_file(path, opts) do
|
|
case Enum.find(events, &match?({:error, _}, &1)) do
|
|
{:error, reason} -> {:error, reason}
|
|
nil -> :ok
|
|
end
|
|
end
|
|
end
|
|
|
|
defp require_delivery_pass(limit) when limit >= 2, do: :ok
|
|
defp require_delivery_pass(limit), do: {:error, {:resource_limit, :max_parse_passes, limit}}
|
|
|
|
defp owned_resource(opts) do
|
|
case Keyword.get(opts, :owned_source_path) do
|
|
path when is_binary(path) -> %{path: path}
|
|
_ -> nil
|
|
end
|
|
end
|
|
|
|
defp positive_option(opts, key, default) do
|
|
case Keyword.get(opts, key, default) do
|
|
value when is_integer(value) and value > 0 -> value
|
|
_ -> default
|
|
end
|
|
end
|
|
end
|