Skip to content

Commit

Permalink
Modified etorrent_ctl:start, adding the optional Options parameter.
Browse files Browse the repository at this point in the history
  • Loading branch information
arcusfelis committed Mar 7, 2013
1 parent c1243f2 commit 617385e
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 44 deletions.
12 changes: 6 additions & 6 deletions src/etorrent.erl
Expand Up @@ -50,13 +50,13 @@ start(Filename) when is_list(Filename) ->
%% @end
start(Filename, {Ref, Pid})
when is_list(Filename), is_reference(Ref), is_pid(Pid) ->
start(Filename,
fun() ->
lager:info("Completing torrent callback: ~s", [Filename]),
Pid ! {Ref, done}
end);
Callback = fun() ->
lager:info("Completing torrent callback: ~s", [Filename]),
Pid ! {Ref, done}
end,
start(Filename, {callback, Callback});
start(Filename, CallBack) when is_list(Filename), is_function(CallBack, 0) ->
etorrent_ctl:start(Filename, CallBack).
etorrent_ctl:start(Filename, {callback, CallBack}).

%% @doc List currently active torrents.
%% <p>This function will list the torrent files which are currently in
Expand Down
37 changes: 22 additions & 15 deletions src/etorrent_ctl.erl
Expand Up @@ -40,15 +40,18 @@ start_link(PeerId) when is_binary(PeerId) ->
% @end
-spec start(string()) -> ok | {error, term()}.
start(File) ->
start(File, none).
start(File, []).

%% @doc Ask the manager to start a new torrent, given in File
%% Upon completion the given CallBack function is executed in a separate
%% process.
%% @end
-spec start(string(), none | fun (() -> any())) -> ok | {error, term()}.
start(File, CallBack) ->
gen_server:call(?SERVER, {start, File, CallBack}, infinity).
-spec start(string(), [Option]) -> {ok, TorrentID} | {error, term()} when
Option :: {callback, Callback} | paused,
Callback :: fun (() -> any()),
TorrentID :: non_neg_integer().
start(File, Options) ->
gen_server:call(?SERVER, {start, File, Options}, infinity).

% @doc Check a torrents contents
% @end
Expand Down Expand Up @@ -113,19 +116,25 @@ handle_cast({stop, F}, S) ->
{noreply, S}.

%% @private
handle_call({start, F, CallBack}, _From, S) ->
lager:info("Starting torrent from file ~s", [F]),
case load_torrent(F) of
handle_call({start, FileName, Options}, _From, S) ->
lager:info("Starting torrent from file ~s", [FileName]),
case load_torrent(FileName) of
duplicate -> {reply, duplicate, S};
{ok, Torrent} ->
TorrentIH = etorrent_metainfo:get_infohash(Torrent),
TorrentID = etorrent_counters:next(torrent),
case etorrent_torrent_pool:start_child(
{Torrent, F, TorrentIH},
{Torrent, FileName, TorrentIH},
S#state.local_peer_id,
etorrent_counters:next(torrent)) of
TorrentID,
Options) of
{ok, TorrentPid} ->
install_callback(TorrentPid, TorrentIH, CallBack),
{reply, ok, S};
case proplists:get_value(callback, Options) of
undefined -> ok;
Callback ->
install_callback(TorrentPid, TorrentIH, Callback)
end,
{reply, {ok, TorrentID}, S};
{error, {already_started, _Pid}} = Err ->
lager:error("Cannot load the torrent ~p twice.", [TorrentIH]),
{reply, Err, S};
Expand All @@ -134,8 +143,8 @@ handle_call({start, F, CallBack}, _From, S) ->
{reply, Err, S}
end;
{error, Reason} ->
lager:info("Malformed torrent file ~s, error: ~p", [F, Reason]),
etorrent_event:notify({malformed_torrent_file, F}),
lager:info("Malformed torrent file ~s, error: ~p", [FileName, Reason]),
etorrent_event:notify({malformed_torrent_file, FileName}),
{reply, {error, Reason}, S}
end;
handle_call(stop_all, _From, S) ->
Expand Down Expand Up @@ -194,7 +203,5 @@ load_torrent_internal(F) ->
P = filename:join([Workdir, F]),
etorrent_bcoding:parse_file(P).

install_callback(_TorrentPid, _InfoHash, none) ->
ok;
install_callback(TorrentPid, InfoHash, Fun) ->
ok = etorrent_callback_handler:install_callback(TorrentPid, InfoHash, Fun).
16 changes: 13 additions & 3 deletions src/etorrent_magnet.erl
Expand Up @@ -34,7 +34,7 @@

%% @doc Parse a magnet link into a tuple "{Infohash, Description, Trackers}".
-spec parse_url(Url) -> {XT, DN, [TR]} when
Url :: string() | binary(),
Url :: string(),
XT :: non_neg_integer(),
DN :: string() | undefined,
TR :: string().
Expand Down Expand Up @@ -78,13 +78,22 @@ xt_to_integer(<<"urn:btih:", Base32:32/binary>>) ->
-type portnum() :: etorrent_types:portnum().
-type bcode() :: etorrent_types:bcode().

download({infohash, Hash}) ->
download({address, Address}) ->
case iolist_to_binary(Address) of
<<"magnet:", _/binary>> = Bin ->
download({magnet_link, binary_to_list(Bin)});
<<Base16:40/binary>> ->
download({infohash, list_to_integer(binary_to_list(Base16), 16)});
<<Base32:32/binary>> ->
download({infohash, etorrent_utils:base32_binary_to_integer(Base32)})
end;
download({infohash, Hash}) when is_integer(Hash) ->
LocalPeerId = etorrent_ctl:local_peer_id(),
{ok, Info} = download_meta_info(LocalPeerId, Hash),
{ok, DecodedInfo} = etorrent_bcoding:decode(Info),
{ok, Torrent} = build_torrent(DecodedInfo, []),
write_torrent(Torrent);
download({magnet_link, Link}) ->
download({magnet_link, Link}) when is_list(Link) ->
LocalPeerId = etorrent_ctl:local_peer_id(),
{Hash, _, Trackers} = parse_url(Link),
{ok, Info} = download_meta_info(LocalPeerId, Hash),
Expand Down Expand Up @@ -250,6 +259,7 @@ download_metadata(Socket, MetadataExtId, LeftSize, MetadataSize, PieceNum, Data)
{RespondMsg, Piece} = etorrent_bcoding2:decode(RespondMsgBin),
case decode_metadata_respond(RespondMsg) of
{data, PieceNum, TotalSize} ->
lager:debug("Metadata piece #~p was downloaded.", [PieceNum]),
PieceSize = byte_size(Piece),
assert_total_size(MetadataSize, TotalSize),
assert_piece_size(LeftSize, PieceSize),
Expand Down
2 changes: 2 additions & 0 deletions src/etorrent_peer_control.erl
Expand Up @@ -182,6 +182,8 @@ has_incoming_requests(Pid) ->
%% @private
init([TrackerUrl, LocalPeerID, RemotePeerID,
InfoHash, TorrentID, {IP, Port}, Caps, Socket]) ->
lager:info("New peer ~p:~p is known as ~p for #~p.",
[IP, Port, RemotePeerID, TorrentID]),
random:seed(now()),
%% Use socket handle as remote peer-id.
register_server(TorrentID, Socket),
Expand Down
28 changes: 20 additions & 8 deletions src/etorrent_torrent_ctl.erl
Expand Up @@ -15,7 +15,7 @@


%% API
-export([start_link/3,
-export([start_link/4,
completed/1,
pause_torrent/1,
continue_torrent/1,
Expand Down Expand Up @@ -106,7 +106,10 @@
progress :: pid(),
wishes = [] :: [#wish{}],
interval :: timer:interval(),
mode = progress :: 'progress' | 'endgame' | atom()
mode = progress :: 'progress' | 'endgame' | atom(),
%% This field is for passing `paused' flag beetween
%% the `init' and `initializing' functions.
state :: unknown | paused
}).


Expand All @@ -127,10 +130,11 @@ server_name(TorrentID) ->
{etorrent, TorrentID, control}.

%% @doc Start the server process
-spec start_link(integer(), {bcode(), string(), binary()}, binary()) ->
-spec start_link(integer(), {bcode(), string(), binary()}, binary(), list()) ->
{ok, pid()} | ignore | {error, term()}.
start_link(Id, {Torrent, TorrentFile, TorrentIH}, PeerId) ->
gen_fsm:start_link(?MODULE, [self(), Id, {Torrent, TorrentFile, TorrentIH}, PeerId], []).
start_link(Id, {Torrent, TorrentFile, TorrentIH}, PeerId, Options) ->
Params = [self(), Id, {Torrent, TorrentFile, TorrentIH}, PeerId, Options],
gen_fsm:start_link(?MODULE, Params, []).

%% @doc Request that the given torrent is checked (eventually again)
%% @end
Expand Down Expand Up @@ -445,19 +449,25 @@ search_wish(_El, []) ->
%% ====================================================================

%% @private
init([Parent, Id, {Torrent, TorrentFile, TorrentIH}, PeerId]) ->
init([Parent, Id, {Torrent, TorrentFile, TorrentIH}, PeerId, Options]) ->
register_server(Id),
etorrent_table:new_torrent(TorrentFile, TorrentIH, Parent, Id),
HashList = etorrent_metainfo:get_pieces(Torrent),
Hashes = hashes_to_binary(HashList),
%% Initial (non in fast resume) state of the torrent:
TState = case proplists:get_bool(paused, Options) of
true -> paused;
false -> unknown
end,
InitState = #state{
id=Id,
torrent=Torrent,
info_hash=TorrentIH,
peer_id=PeerId,
default_peer_id=PeerId,
parent_pid=Parent,
hashes=Hashes},
hashes=Hashes,
state=TState},
{ok, initializing, InitState, 0}.

%% @private
Expand All @@ -470,7 +480,9 @@ initializing(timeout, #state{id=Id, parent_pid=Sup} = S) ->

%% Read the torrent, check its contents for what we are missing
FastResumePL = etorrent_fast_resume:query_state(Id),
TState = proplists:get_value(state, FastResumePL, unknown),
[lager:debug("Fast resume entry for #~p is empty.", [Id])
|| FastResumePL =:= []],
TState = proplists:get_value(state, FastResumePL, S#state.state),
case TState of
paused ->
%% Reset a parent supervisor to a default state.
Expand Down
8 changes: 4 additions & 4 deletions src/etorrent_torrent_pool.erl
Expand Up @@ -5,7 +5,7 @@
-behaviour(supervisor).

%% API
-export([start_link/0, start_child/3, terminate_child/1]).
-export([start_link/0, start_child/4, terminate_child/1]).

%% Supervisor callbacks
-export([init/1]).
Expand All @@ -23,12 +23,12 @@ start_link() -> supervisor:start_link({local, ?SERVER}, ?MODULE, []).
% and info hash. Our PeerId is also given, as well as
% the Id we wish to use for that torrent.</p>
% @end
-spec start_child({bcode(), string(), binary()}, binary(), integer()) ->
-spec start_child({bcode(), string(), binary()}, binary(), integer(), list()) ->
{ok, pid()} | {ok, pid(), term()} | {error, term()}.
start_child({Torrent, TorrentFile, TorrentIH}, Local_PeerId, Id) ->
start_child({Torrent, TorrentFile, TorrentIH}, Local_PeerId, Id, Options) ->
ChildSpec = {TorrentIH,
{etorrent_torrent_sup, start_link,
[{Torrent, TorrentFile, TorrentIH}, Local_PeerId, Id]},
[{Torrent, TorrentFile, TorrentIH}, Local_PeerId, Id, Options]},
transient, infinity, supervisor, [etorrent_torrent_sup]},
supervisor:start_child(?SERVER, ChildSpec).

Expand Down
16 changes: 8 additions & 8 deletions src/etorrent_torrent_sup.erl
Expand Up @@ -7,7 +7,7 @@
-behaviour(supervisor).

%% API
-export([start_link/3,
-export([start_link/4,

start_child_tracker/5,
start_progress/6,
Expand All @@ -31,10 +31,10 @@

%% @doc Start up the supervisor
%% @end
-spec start_link({bcode(), string(), binary()}, binary(), integer()) ->
-spec start_link({bcode(), string(), binary()}, binary(), integer(), list()) ->
{ok, pid()} | ignore | {error, term()}.
start_link({Torrent, TorrentFile, TorrentIH}, Local_PeerId, Id) ->
supervisor:start_link(?MODULE, [{Torrent, TorrentFile, TorrentIH}, Local_PeerId, Id]).
start_link({Torrent, TorrentFile, TorrentIH}, Local_PeerId, Id, Options) ->
supervisor:start_link(?MODULE, [{Torrent, TorrentFile, TorrentIH}, Local_PeerId, Id, Options]).

%% @doc start a child process of a tracker type.
%% <p>We do this after-the-fact as we like to make sure how complete the torrent
Expand Down Expand Up @@ -123,11 +123,11 @@ stop_assignor(Pid) ->
%% ====================================================================

%% @private
init([{Torrent, TorrentPath, TorrentIH}, PeerID, TorrentID]) ->
init([{Torrent, TorrentPath, TorrentIH}, PeerID, TorrentID, Options]) ->
lager:debug("Init torrent supervisor #~p.", [TorrentID]),
Children = [
info_spec(TorrentID, Torrent),
torrent_control_spec(TorrentID, Torrent, TorrentPath, TorrentIH, PeerID)],
torrent_control_spec(TorrentID, Torrent, TorrentPath, TorrentIH, PeerID, Options)],
{ok, {{one_for_all, 1, 60}, Children}}.

pending_spec(TorrentID) ->
Expand Down Expand Up @@ -155,10 +155,10 @@ endgame_spec(TorrentID) ->
{etorrent_endgame, start_link, [TorrentID]},
transient, 5000, worker, [etorrent_endgame]}.

torrent_control_spec(TorrentID, Torrent, TorrentFile, TorrentIH, PeerID) ->
torrent_control_spec(TorrentID, Torrent, TorrentFile, TorrentIH, PeerID, Options) ->
{control,
{etorrent_torrent_ctl, start_link,
[TorrentID, {Torrent, TorrentFile, TorrentIH}, PeerID]},
[TorrentID, {Torrent, TorrentFile, TorrentIH}, PeerID, Options]},
permanent, 5000, worker, [etorrent_torrent_ctl]}.

io_sup_spec(TorrentID, Torrent) ->
Expand Down

0 comments on commit 617385e

Please sign in to comment.