Current section

Files

Jump to
rasstaggregator lib rasstaggregator.ex
Raw

lib/rasstaggregator.ex

defmodule RaSStaggregator do
@moduledoc """
The RSS aggregator for Elixir.
The RaSStaggregator will read the list of feeds from the configuration value:
config :rasstaggregator, feeds: [
%RaSStaggregator.Feed{id: :example_feed, url: "http://example.com/feed"},
%RaSStaggregator.Feed{id: :another_feed, url: "http://example.com/another_feed"},
%RaSStaggregator.Feed{id: :yet_another_feed, url: "http://example.com/yet_another_feed"},
]
It is also possible to add a feed programatically:
RaSStaggregator.add_feed(id, url)
RaSStaggregator will start a parser for each feed and periodically check them
and store them into ETS. It is easy to get the list of feed entries from it:
feed = %RaSStaggregator.Feed{:id :example_feed, url: "http://example.com/feed"}
entries = RaSStaggregator.Cache.find(feed.id)
or to get the post timeline consisting out of multiple feeds:
timeline = RaSStaggregator.get_timeline([:feed_id_1, :feed_id_2, ...])
"""
use Application
@doc """
RaSStaggregator application start function.
"""
def start(_type, _args) do
import Supervisor.Spec, warn: false
# See if any feeds are defined in configuration and start their parsers.
children = Application.get_env(:rasstaggregator, :feeds, [])
|> Enum.map(&(worker(RaSStaggregator.Feed, [&1], [id: &1.id])))
children = [worker(RaSStaggregator.Cache, [], [id: "cache"]) | children]
opts = [strategy: :one_for_one, name: RaSStaggregator.Supervisor]
Supervisor.start_link(children, opts)
end
@doc """
Adds a feed to the RaSStaggregator app.
## Parameters
- `id` - Feed identifier.
- `url` - Feed url.
## Examples
iex> {:ok, pid} = RaSStaggregator.add_feed :example_feed, "http://example.com/feed"
iex> is_pid(pid)
true
"""
@spec add_feed(atom, String.t) :: Supervisor.on_start_child
def add_feed(id, url) do
feed = %RaSStaggregator.Feed{id: id, url: url}
Supervisor.start_child(RaSStaggregator.Supervisor, Supervisor.Spec.worker(RaSStaggregator.Feed, [feed], [id: feed.id]))
end
@doc """
Returns the aggregator timeline consisting of the given feeds in a descending
order.
## Parameters
- `feeds` - List feed IDs to be includded in the timeline.
## Examples
iex> RaSStaggregator.Cache.save(:first, [%FeederEx.Entry{title: "Example post 1", updated: "Thu, 27 Apr 2017 10:00:00 +0200"}])
iex> RaSStaggregator.Cache.save(:second, [%FeederEx.Entry{title: "Example post 2", updated: "Thu, 27 Apr 2017 12:00:00 +0200"}])
iex> RaSStaggregator.get_timeline [:first, :second]
[%FeederEx.Entry{author: nil, duration: nil, enclosure: nil, id: nil,
image: nil, link: nil, subtitle: nil, summary: nil, title: "Example post 2",
updated: "Thu, 27 Apr 2017 12:00:00 +0200"},
%FeederEx.Entry{author: nil, duration: nil, enclosure: nil, id: nil,
image: nil, link: nil, subtitle: nil, summary: nil, title: "Example post 1",
updated: "Thu, 27 Apr 2017 10:00:00 +0200"}]
iex> RaSStaggregator.get_timeline [:second]
[%FeederEx.Entry{author: nil, duration: nil, enclosure: nil, id: nil,
image: nil, link: nil, subtitle: nil, summary: nil, title: "Example post 2",
updated: "Thu, 27 Apr 2017 12:00:00 +0200"}]
iex> RaSStaggregator.get_timeline [:first]
[%FeederEx.Entry{author: nil, duration: nil, enclosure: nil, id: nil,
image: nil, link: nil, subtitle: nil, summary: nil, title: "Example post 1",
updated: "Thu, 27 Apr 2017 10:00:00 +0200"}]
"""
@spec get_timeline([atom]) :: [%FeederEx.Entry{}]
def get_timeline(feeds) do
timeline = do_get_timeline(feeds, [])
|> Enum.sort(&RaSStaggregator.Feed.compare_datetimes/2)
timeline
end
defp do_get_timeline([], entries) do
entries
end
@spec do_get_timeline([atom], [%FeederEx.Entry{}]) :: [%FeederEx.Entry{}]
defp do_get_timeline([feed | rest], entries) do
entries = entries ++ RaSStaggregator.Cache.find feed
do_get_timeline rest, entries
end
end