lab05 written, not tested (awaiting online)
This commit is contained in:
parent
bac73b1a85
commit
eebaa34291
|
@ -0,0 +1,15 @@
|
|||
% Helper functions for logging to the error-logger, or printing trace messages
|
||||
% to the console.
|
||||
|
||||
-define(TRACE(Format, Data),
|
||||
io:format("[TRACE] ~p ~p: " ++ Format, [?MODULE, self()] ++ Data)).
|
||||
|
||||
-define(INFO(Format, Data),
|
||||
error_logger:info_msg("~p ~p: " ++ Format, [?MODULE, self()] ++ Data)).
|
||||
|
||||
-define(WARN(Format, Data),
|
||||
error_logger:warning_msg("~p ~p: " ++ Format, [?MODULE, self()] ++ Data)).
|
||||
|
||||
-define(ERROR(Format, Data),
|
||||
error_logger:error_msg("~p ~p: " ++ Format, [?MODULE, self()] ++ Data)).
|
||||
|
|
@ -2,10 +2,51 @@
|
|||
|
||||
-compile(export_all).
|
||||
|
||||
% 4 Создайте и экспортируйте вспомогательные функции для запуска нового серверного процесса, обслуживающего очередь
|
||||
%% @doc init([]), init([Url])
|
||||
%% нужно написать функцию init, и в обоих версиях функции start которые запускают процессы добавить вызовы init. После этого, init может вызвать вашу функцию server с необходимым набором аргументов.
|
||||
init([]) ->
|
||||
start();
|
||||
|
||||
init([Url]) ->
|
||||
start(Url).
|
||||
|
||||
%% @doc start()
|
||||
%% Для того чтобы сделать подписчику, вам надо добавить к состоянию очереди новое поле Subscribers, которое будет использоваться для хранения PID'ов очередей.
|
||||
start() ->
|
||||
Queue = [],
|
||||
spawn(?MODULE, server, [Queue]).
|
||||
Queue = [],
|
||||
Subscribers = sets:new(),
|
||||
spawn(?MODULE, server, [Queue, Subscribers]).
|
||||
|
||||
%% @doc start(Url)
|
||||
%% Добавьте новую функцию start/1, которая имеет один аргумент URL, и запускает процесс rss_queue, который привязывается к процессу чтения, получая от него элементы ленты RSS, как это обсуждалось выше.
|
||||
start(Url) ->
|
||||
QPid = start(),
|
||||
rss_reader:start(Url,QPid),
|
||||
QPid.
|
||||
|
||||
%% @doc Основный цикл программы, который слушает события
|
||||
%% {add_item, RSSItem} и {get_all, RegPid}.
|
||||
server(Queue, Subscribers) ->
|
||||
receive
|
||||
% Измените код обработки этого сообщения так, чтобы входящие элементы RSS ленты, новые или обновленные версии старых, дополнительно транслировались каждому подписчику очереди
|
||||
{add_item, RSSItem} ->
|
||||
UpdatedQueue = push_item(RSSItem, Queue, Subscribers),
|
||||
server(UpdatedQueue, Subscribers);
|
||||
{get_all, RegPid} ->
|
||||
RegPid ! {self(), Queue},
|
||||
server(Queue, Subscribers);
|
||||
% Добавьте обработку нового сообщения {unsubscribe, QPid}, которое удаляет заданный PID из множества подписчиков
|
||||
{unsubscribe, QPid} ->
|
||||
server(Queue, sets:del_element(QPid,Subscribers));
|
||||
%Обработайте новое сообщение {subscribe, QPid}, которое позволяет очереди подписаться на получение элементов ленты другой очереди
|
||||
{subscribe, QPid} ->
|
||||
[add_item(QPid,Item) || Item <- Queue],
|
||||
server(Queue, sets:add_element(QPid,Subscribers));
|
||||
% Измените очередь так, чтобы она могла получать сообщения 'EXIT' или 'DOWN' от очередей подписчиков, в зависимости от того выбрали вы способ с установкой связи между процессами, или мониторинг очереди подписчика.
|
||||
{'DOWN',_ , _, QPid, _} ->
|
||||
server(Queue, sets:del_element(QPid,Subscribers))
|
||||
end.
|
||||
|
||||
|
||||
%% @doc Функция для сравнения дат
|
||||
date_comporator(A, B) ->
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
-module(rss_reader).
|
||||
-include("logging.hrl").
|
||||
-compile(export_all).
|
||||
-define(RETRIEVE,3000).
|
||||
|
||||
%% @doc start(Url, QPid)
|
||||
%% Запуск сервера
|
||||
start(Url,QPid)->
|
||||
ssl:start(),
|
||||
spawn(?MODULE,server,[Url,QPid]).
|
||||
|
||||
%% @doc реализация чтения
|
||||
%% Загружаем ленту с указанного URL, с помощью функции httpc:request/1.
|
||||
%% Если код ответа равен 200, извлекаем тело ответа и разбирает его XML содержимое с помощью функции xmerl_scan:string/1.
|
||||
%% Когда информация извлечена из тела запроса, проверяем, что получена лента в формате RSS 2.0. Для этого есть написанная в задании 3 функция rss_parse:is_rss2_feed/1.
|
||||
%% Если все вышеперечисленные шаги завершились без ошибок, с помощью написанной в прошлом задании вспомогательной функции rss_queue:add_feed/2 отправляем все элементы ленты в очередь, которая стоит в паре с этим процессом чтения.
|
||||
%% Ждем заданное время, затем возвращаемся к началу и продолжаем все заново.
|
||||
|
||||
%% Обычно, процессы чтения RSS новостей обновляют свои ленты через большие интервалы времени, начиная с 15 минут до часа. Однако, так вам будет сложно тестировать свою программу, поэтому на время разработки этот интервал можно уменьшить до 60 секунд или около того. Объявите с помощью макроса константу, например, RETRIEVE_INTERVAL, с тем чтобы в последствии вы могли бы легко изменить значение таймаута не отыскивая место в коде, где он используется.
|
||||
|
||||
server(Url, QPid)->
|
||||
?INFO("URL ~s~n", [Url]),
|
||||
{ok,{{_,Code,_},_,Load}}=httpc:request(Url),
|
||||
case Code of
|
||||
200 ->
|
||||
?INFO("HTTPCode ~s~n", [Code]),
|
||||
|
||||
{RSS,_} = xmerl_scan:string(Load),
|
||||
case rss_parse:is_rss2_feed(RSS) of
|
||||
ok ->
|
||||
rss_queue:add_feed(QPid,RSS),
|
||||
receive
|
||||
after ?RETRIEVE ->
|
||||
server(Url, QPid)
|
||||
end;
|
||||
_ ->
|
||||
{error,not_rss2_feed}
|
||||
end;
|
||||
_ -> {error,Code}
|
||||
end.
|
Loading…
Reference in New Issue