forked from premiere/premiere-libtorrent
add stop-when-ready feature, to support checking torrents without starting the download afterwards
This commit is contained in:
parent
5c96a35a66
commit
51c6079c42
|
@ -1,3 +1,4 @@
|
||||||
|
* add feature to stop torrents immediately after checking files is done
|
||||||
* make all non-auto managed torrents exempt from queuing logic, including
|
* make all non-auto managed torrents exempt from queuing logic, including
|
||||||
checking torrents.
|
checking torrents.
|
||||||
* add option to not proxy tracker connections through proxy
|
* add option to not proxy tracker connections through proxy
|
||||||
|
|
|
@ -616,6 +616,7 @@ void bind_session()
|
||||||
.value("flag_sequential_download", add_torrent_params::flag_sequential_download)
|
.value("flag_sequential_download", add_torrent_params::flag_sequential_download)
|
||||||
.value("flag_use_resume_save_path", add_torrent_params::flag_use_resume_save_path)
|
.value("flag_use_resume_save_path", add_torrent_params::flag_use_resume_save_path)
|
||||||
.value("flag_merge_resume_http_seeds", add_torrent_params::flag_merge_resume_http_seeds)
|
.value("flag_merge_resume_http_seeds", add_torrent_params::flag_merge_resume_http_seeds)
|
||||||
|
.value("flag_stop_when_ready", add_torrent_params::flag_stop_when_ready)
|
||||||
;
|
;
|
||||||
class_<cache_status>("cache_status")
|
class_<cache_status>("cache_status")
|
||||||
#ifndef TORRENT_NO_DEPRECATE
|
#ifndef TORRENT_NO_DEPRECATE
|
||||||
|
|
|
@ -417,6 +417,7 @@ void bind_torrent_handle()
|
||||||
.def("is_valid", _(&torrent_handle::is_valid))
|
.def("is_valid", _(&torrent_handle::is_valid))
|
||||||
.def("pause", _(&torrent_handle::pause), arg("flags") = 0)
|
.def("pause", _(&torrent_handle::pause), arg("flags") = 0)
|
||||||
.def("resume", _(&torrent_handle::resume))
|
.def("resume", _(&torrent_handle::resume))
|
||||||
|
.def("stop_when_ready", _(&torrent_handle::stop_when_ready))
|
||||||
.def("clear_error", _(&torrent_handle::clear_error))
|
.def("clear_error", _(&torrent_handle::clear_error))
|
||||||
.def("set_priority", _(&torrent_handle::set_priority))
|
.def("set_priority", _(&torrent_handle::set_priority))
|
||||||
.def("super_seeding", super_seeding1)
|
.def("super_seeding", super_seeding1)
|
||||||
|
|
|
@ -28,6 +28,7 @@ void bind_torrent_status()
|
||||||
.def_readonly("info_hash", &torrent_status::info_hash)
|
.def_readonly("info_hash", &torrent_status::info_hash)
|
||||||
.def_readonly("state", &torrent_status::state)
|
.def_readonly("state", &torrent_status::state)
|
||||||
.def_readonly("paused", &torrent_status::paused)
|
.def_readonly("paused", &torrent_status::paused)
|
||||||
|
.def_readonly("stop_when_ready", &torrent_status::stop_when_ready)
|
||||||
.def_readonly("auto_managed", &torrent_status::auto_managed)
|
.def_readonly("auto_managed", &torrent_status::auto_managed)
|
||||||
.def_readonly("sequential_download", &torrent_status::sequential_download)
|
.def_readonly("sequential_download", &torrent_status::sequential_download)
|
||||||
.def_readonly("is_seeding", &torrent_status::is_seeding)
|
.def_readonly("is_seeding", &torrent_status::is_seeding)
|
||||||
|
|
|
@ -267,6 +267,11 @@ namespace libtorrent
|
||||||
// is passed in here as well as the .torrent file.
|
// is passed in here as well as the .torrent file.
|
||||||
flag_merge_resume_http_seeds = 0x2000,
|
flag_merge_resume_http_seeds = 0x2000,
|
||||||
|
|
||||||
|
// the stop when ready flag. Setting this flag is equivalent to calling
|
||||||
|
// torrent_handle::stop_when_ready() immediately after the torrent is
|
||||||
|
// added.
|
||||||
|
flag_stop_when_ready = 0x4000,
|
||||||
|
|
||||||
// internal
|
// internal
|
||||||
default_flags = flag_pinned | flag_update_subscribe
|
default_flags = flag_pinned | flag_update_subscribe
|
||||||
| flag_auto_managed | flag_paused | flag_apply_ip_filter
|
| flag_auto_managed | flag_paused | flag_apply_ip_filter
|
||||||
|
|
|
@ -478,6 +478,8 @@ namespace libtorrent
|
||||||
void set_announce_to_trackers(bool b) { m_announce_to_trackers = b; }
|
void set_announce_to_trackers(bool b) { m_announce_to_trackers = b; }
|
||||||
void set_announce_to_lsd(bool b) { m_announce_to_lsd = b; }
|
void set_announce_to_lsd(bool b) { m_announce_to_lsd = b; }
|
||||||
|
|
||||||
|
void stop_when_ready(bool b) { m_stop_when_ready = b; }
|
||||||
|
|
||||||
int started() const { return m_started; }
|
int started() const { return m_started; }
|
||||||
void step_session_time(int seconds);
|
void step_session_time(int seconds);
|
||||||
void do_pause();
|
void do_pause();
|
||||||
|
@ -521,7 +523,7 @@ namespace libtorrent
|
||||||
// ============ end deprecation =============
|
// ============ end deprecation =============
|
||||||
|
|
||||||
void piece_availability(std::vector<int>& avail) const;
|
void piece_availability(std::vector<int>& avail) const;
|
||||||
|
|
||||||
void set_piece_priority(int index, int priority);
|
void set_piece_priority(int index, int priority);
|
||||||
int piece_priority(int index) const;
|
int piece_priority(int index) const;
|
||||||
|
|
||||||
|
@ -1700,6 +1702,10 @@ namespace libtorrent
|
||||||
// file
|
// file
|
||||||
bool m_merge_resume_http_seeds:1;
|
bool m_merge_resume_http_seeds:1;
|
||||||
|
|
||||||
|
// if this is set, whenever transitioning into a downloading/seeding state
|
||||||
|
// from a non-downloading/seeding state, the torrent is paused.
|
||||||
|
bool m_stop_when_ready:1;
|
||||||
|
|
||||||
#if TORRENT_USE_ASSERTS
|
#if TORRENT_USE_ASSERTS
|
||||||
public:
|
public:
|
||||||
// set to false until we've loaded resume data
|
// set to false until we've loaded resume data
|
||||||
|
|
|
@ -554,6 +554,19 @@ namespace libtorrent
|
||||||
void pause(int flags = 0) const;
|
void pause(int flags = 0) const;
|
||||||
void resume() const;
|
void resume() const;
|
||||||
|
|
||||||
|
// set or clear the stop-when-ready flag. When this flag is set, the
|
||||||
|
// torrent will *force stop* whenever it transitions from a
|
||||||
|
// non-data-transferring state into a data-transferring state (referred to
|
||||||
|
// as being ready to download or seed). This is useful for torrents that
|
||||||
|
// should not start downloading or seeding yet, but what to be made ready
|
||||||
|
// to do so. A torrent may need to have its files checked for instance, so
|
||||||
|
// it needs to be started and possibly queued for checking (auto-managed
|
||||||
|
// and started) but as soon as it's done, it should be stopped.
|
||||||
|
//
|
||||||
|
// *Force stopped* means auto-managed is set to false and it's paused. As
|
||||||
|
// if auto_manage(false) and pause() were called on the torrent.
|
||||||
|
void stop_when_ready(bool b) const;
|
||||||
|
|
||||||
// Explicitly sets the upload mode of the torrent. In upload mode, the
|
// Explicitly sets the upload mode of the torrent. In upload mode, the
|
||||||
// torrent will not request any pieces. If the torrent is auto managed,
|
// torrent will not request any pieces. If the torrent is auto managed,
|
||||||
// it will automatically be taken out of upload mode periodically (see
|
// it will automatically be taken out of upload mode periodically (see
|
||||||
|
|
|
@ -485,6 +485,11 @@ namespace libtorrent
|
||||||
bool announcing_to_lsd;
|
bool announcing_to_lsd;
|
||||||
bool announcing_to_dht;
|
bool announcing_to_dht;
|
||||||
|
|
||||||
|
// this reflects whether the ``stop_when_ready`` flag is currently enabled
|
||||||
|
// on this torrent. For more information, see
|
||||||
|
// torrent_handle::stop_when_ready().
|
||||||
|
bool stop_when_ready;
|
||||||
|
|
||||||
// the info-hash for this torrent
|
// the info-hash for this torrent
|
||||||
sha1_hash info_hash;
|
sha1_hash info_hash;
|
||||||
};
|
};
|
||||||
|
|
|
@ -349,7 +349,6 @@ TORRENT_TEST(seed_limit)
|
||||||
},
|
},
|
||||||
|
|
||||||
[](lt::session& ses) {
|
[](lt::session& ses) {
|
||||||
// verify result (none should have been started)
|
|
||||||
// make sure only 3 got started
|
// make sure only 3 got started
|
||||||
std::vector<lt::alert*> alerts;
|
std::vector<lt::alert*> alerts;
|
||||||
ses.pop_alerts(&alerts);
|
ses.pop_alerts(&alerts);
|
||||||
|
@ -439,7 +438,6 @@ TORRENT_TEST(download_limit)
|
||||||
},
|
},
|
||||||
|
|
||||||
[](lt::session& ses) {
|
[](lt::session& ses) {
|
||||||
// verify result (none should have been started)
|
|
||||||
// make sure only 3 got started
|
// make sure only 3 got started
|
||||||
std::vector<lt::alert*> alerts;
|
std::vector<lt::alert*> alerts;
|
||||||
ses.pop_alerts(&alerts);
|
ses.pop_alerts(&alerts);
|
||||||
|
@ -538,7 +536,6 @@ TORRENT_TEST(checking_announce)
|
||||||
},
|
},
|
||||||
|
|
||||||
[](lt::session& ses) {
|
[](lt::session& ses) {
|
||||||
// verify result (none should have been started)
|
|
||||||
// make sure only 3 got started
|
// make sure only 3 got started
|
||||||
std::vector<lt::alert*> alerts;
|
std::vector<lt::alert*> alerts;
|
||||||
ses.pop_alerts(&alerts);
|
ses.pop_alerts(&alerts);
|
||||||
|
@ -590,7 +587,6 @@ TORRENT_TEST(paused_checking)
|
||||||
},
|
},
|
||||||
|
|
||||||
[](lt::session& ses) {
|
[](lt::session& ses) {
|
||||||
// verify result (none should have been started)
|
|
||||||
// make sure only 3 got started
|
// make sure only 3 got started
|
||||||
std::vector<lt::alert*> alerts;
|
std::vector<lt::alert*> alerts;
|
||||||
ses.pop_alerts(&alerts);
|
ses.pop_alerts(&alerts);
|
||||||
|
@ -619,6 +615,71 @@ TORRENT_TEST(paused_checking)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set the stop_when_ready flag and make sure we receive a paused alert *before*
|
||||||
|
// a state_changed_alert
|
||||||
|
TORRENT_TEST(stop_when_ready)
|
||||||
|
{
|
||||||
|
run_test(
|
||||||
|
[](settings_pack& sett) {},
|
||||||
|
|
||||||
|
[](lt::session& ses) {
|
||||||
|
// add torrents
|
||||||
|
lt::add_torrent_params params = create_torrent(0, true);
|
||||||
|
// torrents are started and auto-managed
|
||||||
|
params.flags |= add_torrent_params::flag_auto_managed;
|
||||||
|
params.flags |= add_torrent_params::flag_stop_when_ready;
|
||||||
|
// we need this to get the tracker_announce_alert
|
||||||
|
params.trackers.push_back("http://10.10.0.2/announce");
|
||||||
|
ses.async_add_torrent(params);
|
||||||
|
},
|
||||||
|
|
||||||
|
[](lt::session& ses) {
|
||||||
|
// verify result (none should have been started)
|
||||||
|
std::vector<lt::alert*> alerts;
|
||||||
|
ses.pop_alerts(&alerts);
|
||||||
|
|
||||||
|
lt::time_point start_time = alerts[0]->timestamp();
|
||||||
|
|
||||||
|
int num_paused = 0;
|
||||||
|
for (alert* a : alerts)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%-3d %s\n", int(duration_cast<lt::seconds>(a->timestamp()
|
||||||
|
- start_time).count()), a->message().c_str());
|
||||||
|
|
||||||
|
if (alert_cast<torrent_paused_alert>(a))
|
||||||
|
{
|
||||||
|
++num_paused;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state_changed_alert* sc = alert_cast<state_changed_alert>(a))
|
||||||
|
{
|
||||||
|
if (sc->state == torrent_status::seeding)
|
||||||
|
{
|
||||||
|
// once we turn into beeing a seed. we should have been paused
|
||||||
|
// already.
|
||||||
|
TEST_EQUAL(num_paused, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// there should not have been any announces. the torrent should have
|
||||||
|
// been stopped *before* announcing.
|
||||||
|
TEST_EQUAL(alert_cast<tracker_announce_alert>(a), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (torrent_handle const& h : ses.get_torrents())
|
||||||
|
{
|
||||||
|
// the torrent should have been force-stopped (after checking was
|
||||||
|
// donw, because we set the stop_when_ready flag). Force stopped
|
||||||
|
// means not auto-managed and paused.
|
||||||
|
torrent_status st = h.status();
|
||||||
|
TEST_CHECK(!st.auto_managed);
|
||||||
|
TEST_EQUAL(st.paused, true);
|
||||||
|
// it should be seeding. If it's not seeding it may not have had its
|
||||||
|
// files checked.
|
||||||
|
TEST_EQUAL(st.state, torrent_status::seeding);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
// TODO: assert that the torrent_paused_alert is posted when pausing
|
// TODO: assert that the torrent_paused_alert is posted when pausing
|
||||||
// downloading, seeding, checking torrents as well as the graceful pause
|
// downloading, seeding, checking torrents as well as the graceful pause
|
||||||
// TODO: test limits of tracker, DHT and LSD announces
|
// TODO: test limits of tracker, DHT and LSD announces
|
||||||
|
|
|
@ -279,6 +279,7 @@ namespace libtorrent
|
||||||
, m_pending_active_change(false)
|
, m_pending_active_change(false)
|
||||||
, m_use_resume_save_path(p.flags & add_torrent_params::flag_use_resume_save_path)
|
, m_use_resume_save_path(p.flags & add_torrent_params::flag_use_resume_save_path)
|
||||||
, m_merge_resume_http_seeds(p.flags & add_torrent_params::flag_merge_resume_http_seeds)
|
, m_merge_resume_http_seeds(p.flags & add_torrent_params::flag_merge_resume_http_seeds)
|
||||||
|
, m_stop_when_ready(p.flags & add_torrent_params::flag_stop_when_ready)
|
||||||
{
|
{
|
||||||
// we cannot log in the constructor, because it relies on shared_from_this
|
// we cannot log in the constructor, because it relies on shared_from_this
|
||||||
// being initialized, which happens after the constructor returns.
|
// being initialized, which happens after the constructor returns.
|
||||||
|
@ -11610,6 +11611,29 @@ namespace libtorrent
|
||||||
if (m_peer_list) m_peer_list->clear_peer_prio();
|
if (m_peer_list) m_peer_list->clear_peer_prio();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
bool is_downloading_state(int st)
|
||||||
|
{
|
||||||
|
switch (st)
|
||||||
|
{
|
||||||
|
case torrent_status::checking_files:
|
||||||
|
case torrent_status::allocating:
|
||||||
|
case torrent_status::checking_resume_data:
|
||||||
|
return false;
|
||||||
|
case torrent_status::downloading_metadata:
|
||||||
|
case torrent_status::downloading:
|
||||||
|
case torrent_status::finished:
|
||||||
|
case torrent_status::seeding:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
// unexpected state
|
||||||
|
TORRENT_ASSERT_VAL(false, st);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void torrent::set_state(torrent_status::state_t s)
|
void torrent::set_state(torrent_status::state_t s)
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(is_single_thread());
|
TORRENT_ASSERT(is_single_thread());
|
||||||
|
@ -11643,6 +11667,21 @@ namespace libtorrent
|
||||||
get_handle());
|
get_handle());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_stop_when_ready
|
||||||
|
&& !is_downloading_state(m_state)
|
||||||
|
&& is_downloading_state(s))
|
||||||
|
{
|
||||||
|
#ifndef TORRENT_DISABLE_LOGGING
|
||||||
|
debug_log("stop_when_ready triggered");
|
||||||
|
#endif
|
||||||
|
// stop_when_ready is set, and we're transitioning from a downloading
|
||||||
|
// state to a non-downloading state. pause the torrent. Note that
|
||||||
|
// "downloading" is defined broadly to include any state where we
|
||||||
|
// either upload or download (for the purpose of this flag).
|
||||||
|
auto_managed(false);
|
||||||
|
pause();
|
||||||
|
}
|
||||||
|
|
||||||
m_state = s;
|
m_state = s;
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_LOGGING
|
#ifndef TORRENT_DISABLE_LOGGING
|
||||||
|
@ -11742,6 +11781,7 @@ namespace libtorrent
|
||||||
st->announcing_to_trackers = m_announce_to_trackers;
|
st->announcing_to_trackers = m_announce_to_trackers;
|
||||||
st->announcing_to_lsd = m_announce_to_lsd;
|
st->announcing_to_lsd = m_announce_to_lsd;
|
||||||
st->announcing_to_dht = m_announce_to_dht;
|
st->announcing_to_dht = m_announce_to_dht;
|
||||||
|
st->stop_when_ready = m_stop_when_ready;
|
||||||
|
|
||||||
st->added_time = m_added_time;
|
st->added_time = m_added_time;
|
||||||
st->completed_time = m_completed_time;
|
st->completed_time = m_completed_time;
|
||||||
|
|
|
@ -329,6 +329,11 @@ namespace libtorrent
|
||||||
TORRENT_ASYNC_CALL1(pause, bool(flags & graceful_pause));
|
TORRENT_ASYNC_CALL1(pause, bool(flags & graceful_pause));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void torrent_handle::stop_when_ready(bool b) const
|
||||||
|
{
|
||||||
|
TORRENT_ASYNC_CALL1(stop_when_ready, b);
|
||||||
|
}
|
||||||
|
|
||||||
void torrent_handle::apply_ip_filter(bool b) const
|
void torrent_handle::apply_ip_filter(bool b) const
|
||||||
{
|
{
|
||||||
TORRENT_ASYNC_CALL1(set_apply_ip_filter, b);
|
TORRENT_ASYNC_CALL1(set_apply_ip_filter, b);
|
||||||
|
|
Loading…
Reference in New Issue