remove torrent_file_path asynchronous loading of .torrent files. (#1848)

remove torrent_file_path asynchronous loading of .torrent files. This is not the responsibility of the client, to simplify and unify the path of adding torrents
This commit is contained in:
Arvid Norberg 2017-03-26 09:16:42 -04:00 committed by GitHub
parent cb867a6edc
commit 103b1176c1
7 changed files with 97 additions and 161 deletions

View File

@ -1,5 +1,5 @@
* optimize download queue management
* deprecated (undocumented) file:// urls, added torrent_file_path alternative
* deprecated (undocumented) file:// urls
* add limit for number of web seed connections
* added support for retrieval of DHT live nodes
* complete UNC path support

View File

@ -325,6 +325,22 @@ std::string path_append(std::string const& lhs, std::string const& rhs)
return lhs + (need_sep?TORRENT_SEPARATOR:"") + rhs;
}
std::string make_absolute_path(std::string const& p)
{
if (is_absolute_path(p)) return p;
std::string ret;
#if defined TORRENT_WINDOWS
char* cwd = ::_getcwd(nullptr, 0);
ret = path_append(cwd, p);
std::free(cwd);
#else
char* cwd = ::getcwd(nullptr, 0);
ret = path_append(cwd, p);
std::free(cwd);
#endif
return ret;
}
bool is_hex(char const *in, int len)
{
for (char const* end = in + len; in < end; ++in)
@ -587,9 +603,46 @@ void print_settings(int const start, int const num
}
}
void add_torrent(libtorrent::session& ses
, handles_t& files
, std::string torrent)
std::string resume_file(lt::sha1_hash const& info_hash)
{
return path_append(save_path, path_append(".resume"
, to_hex(info_hash) + ".resume"));
}
void add_magnet(lt::session& ses, lt::string_view uri)
{
lt::add_torrent_params p;
lt::error_code ec;
lt::parse_magnet_uri(uri.to_string(), p, ec);
if (ec)
{
std::printf("invalid magnet link \"%s\": %s\n"
, uri.to_string().c_str(), ec.message().c_str());
return;
}
std::vector<char> resume_data;
load_file(resume_file(p.info_hash), resume_data, ec);
if (!ec)
{
p = lt::read_resume_data(&resume_data[0], int(resume_data.size()), ec);
if (ec) std::printf(" failed to load resume data: %s\n", ec.message().c_str());
parse_magnet_uri(uri.to_string(), p, ec);
}
ec.clear();
if (seed_mode) p.flags |= lt::add_torrent_params::flag_seed_mode;
if (disable_storage) p.storage = lt::disabled_storage_constructor;
if (share_mode) p.flags |= lt::add_torrent_params::flag_share_mode;
p.save_path = save_path;
p.storage_mode = static_cast<lt::storage_mode_t>(allocation_mode);
std::printf("adding magnet: %s\n", uri.to_string().c_str());
ses.async_add_torrent(p);
}
void add_torrent(libtorrent::session& ses, handles_t& files, std::string torrent)
{
using namespace libtorrent;
static int counter = 0;
@ -597,15 +650,21 @@ void add_torrent(libtorrent::session& ses
std::printf("[%d] %s\n", counter++, torrent.c_str());
error_code ec;
auto ti = std::make_shared<torrent_info>(torrent, ec);
if (ec)
{
std::printf("failed to load torrent \"%s\": %s\n"
, torrent.c_str(), ec.message().c_str());
return;
}
add_torrent_params p;
std::vector<char> resume_data;
std::string filename = path_append(save_path, path_append(".resume"
, leaf_path(torrent) + ".resume"));
load_file(filename, resume_data, ec);
load_file(resume_file(ti->info_hash()), resume_data, ec);
if (!ec)
{
p = read_resume_data(&resume_data[0], int(resume_data.size()), ec);
p = lt::read_resume_data(&resume_data[0], int(resume_data.size()), ec);
if (ec) std::printf(" failed to load resume data: %s\n", ec.message().c_str());
}
ec.clear();
@ -614,7 +673,7 @@ void add_torrent(libtorrent::session& ses
if (disable_storage) p.storage = disabled_storage_constructor;
if (share_mode) p.flags |= add_torrent_params::flag_share_mode;
p.torrent_file_path = torrent;
p.ti = ti;
p.save_path = save_path;
p.storage_mode = (storage_mode_t)allocation_mode;
p.flags &= ~add_torrent_params::flag_duplicate_is_error;
@ -623,29 +682,6 @@ void add_torrent(libtorrent::session& ses
files.insert(std::pair<const std::string, torrent_handle>(torrent, torrent_handle()));
}
std::string make_absolute_path(char const* p)
{
std::string ret;
#if defined TORRENT_WINDOWS
if (p[0] != '\0' && !(p[1] == ':' && p[2] == '\\'))
{
char* cwd = ::_getcwd(nullptr, 0);
ret = path_append(cwd, p);
std::free(cwd);
}
else ret = p;
#else
if (p[0] != '/')
{
char* cwd = ::getcwd(nullptr, 0);
ret = path_append(cwd, p);
std::free(cwd);
}
else ret = p;
#endif
return ret;
}
std::vector<std::string> list_dir(std::string path
, bool (*filter_fun)(lt::string_view)
, libtorrent::error_code& ec)
@ -1000,8 +1036,7 @@ bool handle_alert(torrent_view& view, session_view& ses_view
torrent_handle h = p->handle;
auto const buf = write_resume_data_buf(p->params);
torrent_status st = h.status(torrent_handle::query_save_path);
save_file(path_append(st.save_path, path_append(".resume", leaf_path(
hash_to_filename[st.info_hash]) + ".resume")), buf);
save_file(resume_file(st.info_hash), buf);
if (h.is_valid()
&& non_files.find(h) == non_files.end()
&& std::none_of(files.begin(), files.end()
@ -1186,9 +1221,7 @@ int main(int argc, char* argv[])
std::set<torrent_handle> non_files;
// load the torrents given on the commandline
std::vector<add_torrent_params> magnet_links;
std::vector<std::string> torrents;
std::vector<lt::string_view> torrents;
ip_filter loaded_ip_filter;
for (int i = 1; i < argc; ++i)
@ -1362,52 +1395,16 @@ int main(int argc, char* argv[])
}
#endif
for (auto const& magnet : magnet_links)
ses.async_add_torrent(magnet);
for (auto const& i : torrents)
{
if (std::strstr(i.c_str(), "http://") == i.c_str()
|| std::strstr(i.c_str(), "https://") == i.c_str()
|| std::strstr(i.c_str(), "magnet:") == i.c_str())
if (i.substr(0, 7) == "magnet:")
{
add_torrent_params p;
if (std::strstr(i.c_str(), "magnet:") == i.c_str())
{
add_torrent_params tmp;
ec.clear();
parse_magnet_uri(i, tmp, ec);
if (ec) continue;
std::string filename = path_append(save_path, path_append(".resume"
, to_hex(tmp.info_hash) + ".resume"));
std::vector<char> resume_data;
load_file(filename, resume_data, ec);
if (!ec)
{
p = read_resume_data(&resume_data[0], int(resume_data.size()), ec);
if (ec) std::printf(" failed to load resume data: %s\n", ec.message().c_str());
}
ec.clear();
}
if (seed_mode) p.flags |= add_torrent_params::flag_seed_mode;
if (disable_storage) p.storage = disabled_storage_constructor;
if (share_mode) p.flags |= add_torrent_params::flag_share_mode;
p.save_path = save_path;
p.storage_mode = (storage_mode_t)allocation_mode;
p.url = i;
std::printf("adding URL: %s\n", i.c_str());
ses.async_add_torrent(p);
continue;
add_magnet(ses, i);
}
else
{
add_torrent(ses, files, i.to_string());
}
// if it's a torrent file, open it as usual
add_torrent(ses, files, i.c_str());
}
// main loop
@ -1515,39 +1512,10 @@ int main(int argc, char* argv[])
if (c == 'm')
{
char url[4096];
url[0] = '\0';
puts("Enter magnet link:\n");
int ret = std::scanf("%4095s", url);
add_torrent_params p;
if (ret == 1 && std::strstr(url, "magnet:") == url)
{
add_torrent_params tmp;
parse_magnet_uri(url, tmp, ec);
if (ec) continue;
std::string filename = path_append(save_path, path_append(".resume"
, to_hex(tmp.info_hash) + ".resume"));
std::vector<char> resume_data;
load_file(filename, resume_data, ec);
if (!ec)
{
p = read_resume_data(&resume_data[0], int(resume_data.size()), ec);
if (ec) std::printf(" failed to load resume data: %s\n", ec.message().c_str());
}
ec.clear();
}
if (seed_mode) p.flags |= add_torrent_params::flag_seed_mode;
if (disable_storage) p.storage = disabled_storage_constructor;
if (share_mode) p.flags |= add_torrent_params::flag_share_mode;
p.save_path = save_path;
p.storage_mode = (storage_mode_t)allocation_mode;
p.url = url;
std::printf("adding URL: %s\n", url);
ses.async_add_torrent(p);
if (std::scanf("%4095s", url) == 1) add_magnet(ses, url);
else std::printf("failed to read magnet link\n");
}
if (c == 'q') break;

View File

@ -60,8 +60,6 @@ namespace libtorrent
// * url - when you have a magnet link
// * info_hash - when all you have is an info-hash (this is similar to a
// magnet link)
// * torrent_file_path - when you have the path to a .torrent file and want
// libtorrent to load it. (This is especially useful with async_add_torrent)
//
// one of those fields must be set. Another mandatory field is
// ``save_path``. The add_torrent_params object is passed into one of the
@ -360,10 +358,6 @@ namespace libtorrent
// state (``torrent_status::error``) will indicate what went wrong.
std::string url;
// if you specify a ``torrent_file_path``, libtorrent will attempt to load
// a .torrent file from the file at the given path.
std::string torrent_file_path;
// flags controlling aspects of this torrent and how it's added. See
// flags_t for details.
//

View File

@ -480,7 +480,10 @@ namespace libtorrent
std::pair<std::shared_ptr<torrent>, bool>
add_torrent_impl(add_torrent_params& p, error_code& ec);
void async_add_torrent(add_torrent_params* params);
#ifndef TORRENT_NO_DEPRECATE
void on_async_load_torrent(add_torrent_params* params, error_code ec);
#endif
void remove_torrent(torrent_handle const& h, int options) override;
void remove_torrent_impl(std::shared_ptr<torrent> tptr, int options) override;
@ -1091,6 +1094,7 @@ namespace libtorrent
std::shared_ptr<upnp> m_upnp;
std::shared_ptr<lsd> m_lsd;
#ifndef TORRENT_NO_DEPRECATE
struct work_thread_t
{
work_thread_t()
@ -1110,6 +1114,7 @@ namespace libtorrent
std::thread thread;
};
std::unique_ptr<work_thread_t> m_torrent_load_thread;
#endif
// mask is a bitmask of which protocols to remap on:
// 1: NAT-PMP

View File

@ -167,7 +167,7 @@ namespace libtorrent
#endif // BOOST_NO_EXCEPTIONS
#endif // TORRENT_NO_DEPRECATE
// TODO: 3 take string_ref here instead
// TODO: 3 take string_view here instead
void parse_magnet_uri(std::string const& uri, add_torrent_params& p, error_code& ec)
{
ec.clear();

View File

@ -4597,22 +4597,18 @@ namespace aux {
#ifndef TORRENT_NO_DEPRECATE
if (!params->ti && string_begins_no_case("file://", params->url.c_str()))
{
params->torrent_file_path = resolve_file_url(params->url);
params->url.clear();
}
#endif
if (!params->ti && !params->torrent_file_path.empty())
{
if (!m_torrent_load_thread)
m_torrent_load_thread.reset(new work_thread_t());
m_torrent_load_thread->ios.post([params, this]
{
std::string const torrent_file_path = resolve_file_url(params->url);
params->url.clear();
std::unique_ptr<add_torrent_params> holder2(params);
error_code ec;
params->ti = std::make_shared<torrent_info>(params->torrent_file_path, ec);
params->ti = std::make_shared<torrent_info>(torrent_file_path, ec);
this->m_io_service.post(std::bind(&session_impl::on_async_load_torrent
, this, params, ec));
holder2.release();
@ -4620,11 +4616,13 @@ namespace aux {
holder.release();
return;
}
#endif
error_code ec;
add_torrent(*params, ec);
}
#ifndef TORRENT_NO_DEPRECATE
void session_impl::on_async_load_torrent(add_torrent_params* params, error_code ec)
{
std::unique_ptr<add_torrent_params> holder(params);
@ -4640,6 +4638,7 @@ namespace aux {
params->url.clear();
add_torrent(*params, ec);
}
#endif
#ifndef TORRENT_DISABLE_EXTENSIONS
void session_impl::add_extensions_to_torrent(
@ -4792,25 +4791,20 @@ namespace aux {
parse_magnet_uri(params.url, params, ec);
if (ec) return std::make_pair(ptr_t(), false);
params.url.clear();
params.torrent_file_path.clear();
}
#ifndef TORRENT_NO_DEPRECATE
if (!params.ti && string_begins_no_case("file://", params.url.c_str()))
{
params.torrent_file_path = resolve_file_url(params.url);
std::string const torrent_file_path = resolve_file_url(params.url);
params.url.clear();
auto t = std::make_shared<torrent_info>(torrent_file_path, std::ref(ec), 0);
if (ec) return std::make_pair(ptr_t(), false);
params.url.clear();
params.ti = t;
}
#endif
if (!params.ti && !params.torrent_file_path.empty())
{
auto t = std::make_shared<torrent_info>(params.torrent_file_path, std::ref(ec), 0);
if (ec) return std::make_pair(ptr_t(), false);
params.url.clear();
params.torrent_file_path.clear();
params.ti = t;
}
if (params.ti && !params.ti->is_valid())
{

View File

@ -440,31 +440,6 @@ TORRENT_TEST(async_load_deprecated)
}
#endif
TORRENT_TEST(async_load)
{
settings_pack pack = settings();
lt::session ses(pack);
add_torrent_params p;
p.flags &= ~add_torrent_params::flag_paused;
p.flags &= ~add_torrent_params::flag_auto_managed;
std::string dir = parent_path(current_working_directory());
p.torrent_file_path = combine_path(combine_path(dir, "test_torrents"), "base.torrent");
p.save_path = ".";
ses.async_add_torrent(p);
alert const* a = wait_for_alert(ses, add_torrent_alert::alert_type);
TEST_CHECK(a);
if (a == nullptr) return;
auto const* ta = alert_cast<add_torrent_alert const>(a);
TEST_CHECK(ta);
if (ta == nullptr) return;
TEST_CHECK(!ta->error);
TEST_CHECK(ta->params.ti->name() == "temp");
}
TORRENT_TEST(torrent_status)
{
TEST_EQUAL(static_cast<int>(torrent_status::error_file_none), -1);