Last active
December 10, 2015 00:29
-
-
Save mokevnin/4351374 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| -module(grabber). | |
| -export([start/1]). | |
| -export([downloader/2, storage/1]). | |
| start(Host) -> | |
| inets:start(), | |
| StoragePid = spawn(grabber, storage, [Host]), | |
| StoragePid ! {links, [Host]}. | |
| storage(Host) -> | |
| receive | |
| {links, Links} -> | |
| %lists:map(fun(Link) -> io:format("~s~n", [Link]) end, Links), | |
| lists:map(fun(Url) -> spawn(grabber, downloader, [self(), Url]) end, get_internal_links(Links, Host)), | |
| storage(Host) | |
| end. | |
| get_internal_links(Links, Host) -> | |
| get_internal_links(Links, Host, []). | |
| get_internal_links([Head | Tail], Host, Lists) -> | |
| case string:str(Head, Host) of | |
| 0 -> | |
| get_internal_links(Tail, Host, [Host ++ Head | Lists]); | |
| 1 -> | |
| get_internal_links(Tail, Host, [Head | Lists]); | |
| _ -> | |
| get_internal_links(Tail, Host, Lists) | |
| end; | |
| get_internal_links([], _, Lists) -> | |
| Lists. | |
| downloader(StoragePid, Url) -> | |
| case get_links_by_url(Url) of | |
| {ok, Links} -> StoragePid ! {links, Links}; | |
| {error, Status} -> io:format("~s ~w~n", [Url, Status]) | |
| end. | |
| get_links_by_url(Url) -> | |
| case httpc:request(Url) of | |
| {ok, {_, _, Body}} -> | |
| io:format("~s~n", [Url]), | |
| {ok, get_links_by_body(Body)}; | |
| {Status, _} -> | |
| {error, Status} | |
| end. | |
| get_links_by_body(Body) -> | |
| case re:run(Body, "href=\"([^\"]+)\"", [global]) of | |
| {match, Matches} -> | |
| lists:map(fun([_, {Start, Length}]) -> string:substr(Body, Start + 1, Length) end, Matches); | |
| nomatch -> [] | |
| end. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
erl -man gen_server, чем spawn_link(), а spawn_link() лучше, чем spawn(). Например, storage() — это типичный gen_server, который принимает работу, диспетчеризует её и хранит новое состояние. Сейчас любой code reload убьёт граббер, а если оформить через gen_server, то появится возможность и код добавлять туда, и новые функции, получить интроспекцию (например, посмотреть на текущее состояние процесса, sys:get_status()).erl -man application, который с супервизором на несколько процессов. Как говорил Махоткин в своё время, «книжка у них была, но прочитали они её ровно до половины» ;) — в смысле, что надо не только примитивами языка пользоваться, но и OTP.lists:map(fun(Url) -> spawn(grabber, downloader, [self(), Url]) end, get_internal_links(Links, Host)),
=>
[ feed_grabber(Url) || Url <- get_internal_links(Links, Host) ]
Какие плюсы это даёт: увеличивается тестируемость: вместо запуска функции get_links_by_url() и ожидания самого-самого последнего результата цепочки функций, мы просто берём отдельные функции типа URL->Body; Body->Links и нанизываем их друг на друга. Обрати внимание, появляется возможность протестировать body_by_url независимо от links_by_body.