Created
January 18, 2009 20:46
-
-
Save ngerakines/48763 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%% @doc Pulls wowinsider.com feeds and caches appropiately. Note that inets | |
%% must be running for this to work. See http://www.wowinsider.com/feeds for | |
%% all their supported feeds. | |
%% @type article() = {string(), string()}. | |
-module(ipwfbfe_wowinsider). | |
-export([recent/0, feed_articles/1, priest/0]). | |
-export([ensure_server_started/0, start_server_loop/0, server_loop/1]). | |
-include_lib("xmerl/include/xmerl.hrl"). | |
%% @spec recent() -> [article()] | |
%% @doc Returns a list of the most recent articles. | |
recent() -> | |
ensure_server_started(), | |
refresh_articles("http://www.wowinsider.com/rss.xml"). | |
%% @spec feed_articles() -> [article()] | |
%% @doc Returns a list articles based on a url. Note that this does not | |
%% validate the contents of the url. The only checking performed is a match | |
%% on the base url. | |
feed_articles(Url = "http://www.wowinsider.com/" ++ _) -> | |
ensure_server_started(), | |
refresh_articles(Url). | |
%% @spec priest() -> [article()] | |
%% @doc Returns a list of the most recently articles for priests. | |
priest() -> | |
ensure_server_started(), | |
refresh_articles("http://www.wowinsider.com/category/priest/rss.xml"). | |
%% @private | |
refresh_articles(Url) -> | |
case should_refresh(Url) of | |
true -> | |
case fetch(Url) of | |
{ok, Body} -> | |
case parse_items(Body) of | |
{error, _} -> []; | |
Articles -> store_articles(Url, Articles), Articles | |
end; | |
_ -> {error, fetch} | |
end; | |
false -> thaw_articles(Url) | |
end. | |
%% @private | |
should_refresh(X) -> | |
wowinsider_cache ! {self(), should_update, X}, | |
receive Y -> Y after 1000 -> true end. | |
%% @private | |
thaw_articles(X) -> | |
wowinsider_cache ! {self(), get, X}, | |
receive Y -> Y after 1000 -> true end. | |
%% @private | |
store_articles(X, Y) -> | |
wowinsider_cache ! {self(), store, X, Y}. | |
%% @private | |
fetch(Url) -> | |
case http:request(get, {Url, []}, [], []) of | |
{ok, {_, _, Body}} -> {ok, Body}; | |
X -> {error, X} | |
end. | |
%% @private | |
parse_items(Body) -> | |
try xmerl_scan:string(Body) of | |
{XmlElem, _} -> | |
[begin | |
[#xmlText{ value = Title }] = xmerl_xpath:string("/item/title/text()", Elem), | |
[#xmlText{ value = Link }] = xmerl_xpath:string("/item/link/text()", Elem), | |
{Title, Link} | |
end || Elem <- xmerl_xpath:string("/rss/channel/item", XmlElem)]; | |
_ -> {error, unknown} | |
catch | |
_:_ -> {error, throw} | |
end. | |
%% @private | |
ensure_server_started() -> | |
case whereis(wowinsider_cache) of | |
undefined -> proc_lib:start(?MODULE, start_server_loop,[]); | |
_ -> ok | |
end. | |
%% @private | |
start_server_loop() -> | |
catch register(wowinsider_cache, self()), | |
proc_lib:init_ack(ok), | |
?MODULE:server_loop(dict:new()). | |
%% @private | |
server_loop(State) -> | |
NewState = receive | |
{_From, store, Url, Articles} -> | |
Now = calendar:datetime_to_gregorian_seconds({date(), time()}), | |
dict:store(Url, {Now, Articles}, State); | |
{From, get, Url} -> | |
case dict:find(Url, State) of | |
{ok, {_, Articles}} -> From ! Articles; | |
_ -> From ! [] | |
end, | |
State; | |
{From, exists, Url} -> | |
Resp = case dict:find(Url, State) of | |
{ok, _} -> true; | |
_ -> false | |
end, | |
From ! Resp, | |
State; | |
{From, should_update, Url} -> | |
Now = calendar:datetime_to_gregorian_seconds({date(), time()}) - (60 * 5), | |
Resp = case dict:find(Url, State) of | |
{ok, {Last, _}} when Last > Now-> false; | |
_ -> true | |
end, | |
From ! Resp, | |
State; | |
_ -> State | |
end, | |
?MODULE:server_loop(NewState). |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment