Merge pull request #609 from arvidn/py-read_resume_data

improve python binding of read_resume_data
This commit is contained in:
Arvid Norberg 2016-04-15 00:49:24 -04:00
commit 6e50c8f2ef
10 changed files with 241 additions and 74 deletions

View File

@ -1,5 +1,6 @@
* added new read_resume_data() function, initializing add_torrent_params
* removed deprecated fields from add_torrent_params
* deprecate "resume_data" field in add_torrent_params
* improved support for bind-to-device
* deprecated ssl_listen, SSL sockets are specified in listen_interfaces now
* improved support for listening on multiple sockets and interfaces

View File

@ -19,44 +19,12 @@ bytes get_buffer(read_piece_alert const& rpa)
: bytes();
}
tuple endpoint_to_tuple(tcp::endpoint const& ep)
{
return boost::python::make_tuple(ep.address().to_string(), ep.port());
}
tuple endpoint_to_tuple(udp::endpoint const& ep)
{
return boost::python::make_tuple(ep.address().to_string(), ep.port());
}
tuple peer_alert_ip(peer_alert const& pa)
{
return endpoint_to_tuple(pa.ip);
}
std::string peer_blocked_alert_ip(peer_blocked_alert const& pa)
{
error_code ec;
return pa.ip.to_string(ec);
}
std::string dht_announce_alert_ip(dht_announce_alert const& pa)
{
error_code ec;
return pa.ip.to_string(ec);
}
tuple incoming_connection_alert_ip(incoming_connection_alert const& ica)
{
return endpoint_to_tuple(ica.ip);
}
tuple dht_outgoing_get_peers_alert_ip(dht_outgoing_get_peers_alert const& a)
{
return endpoint_to_tuple(a.ip);
}
std::string external_ip_alert_ip(external_ip_alert const& eia)
{
return eia.external_address.to_string();
@ -282,7 +250,8 @@ void bind_alert()
class_<peer_alert, bases<torrent_alert>, noncopyable>(
"peer_alert", no_init)
.add_property("ip", &peer_alert_ip)
.add_property("ip", make_getter(&peer_alert::ip
, return_value_policy<return_by_value>()))
.def_readonly("pid", &peer_alert::pid)
;
class_<tracker_error_alert, bases<tracker_alert>, noncopyable>(
@ -469,7 +438,8 @@ void bind_alert()
class_<peer_blocked_alert, bases<alert>, noncopyable>(
"peer_blocked_alert", no_init)
.add_property("ip", &peer_blocked_alert_ip)
.add_property("ip", make_getter(&peer_blocked_alert::ip
, return_value_policy<return_by_value>()))
;
class_<scrape_reply_alert, bases<tracker_alert>, noncopyable>(
@ -494,7 +464,9 @@ void bind_alert()
class_<external_ip_alert, bases<alert>, noncopyable>(
"external_ip_alert", no_init)
.add_property("external_address", &external_ip_alert_ip)
.add_property("external_address"
, make_getter(&external_ip_alert::external_address
, return_value_policy<return_by_value>()))
;
class_<save_resume_data_alert, bases<torrent_alert>, noncopyable>(
@ -667,11 +639,12 @@ void bind_alert()
class_<incoming_connection_alert, bases<alert>, noncopyable>(
"incoming_connection_alert", no_init)
.def_readonly("socket_type", &incoming_connection_alert::socket_type)
.add_property("ip", &incoming_connection_alert_ip)
.add_property("ip", make_getter(&incoming_connection_alert::ip
, return_value_policy<return_by_value>()))
;
class_<torrent_need_cert_alert, bases<torrent_alert>, noncopyable>(
"torrent_need_cert_alert", no_init)
.def_readonly("error", &torrent_need_cert_alert::error)
.def_readonly("error", &torrent_need_cert_alert::error)
;
class_<add_torrent_alert, bases<torrent_alert>, noncopyable>(
@ -692,7 +665,8 @@ void bind_alert()
"dht_outgoing_get_peers_alert", no_init)
.def_readonly("info_hash", &dht_outgoing_get_peers_alert::info_hash)
.def_readonly("obfuscated_info_hash", &dht_outgoing_get_peers_alert::obfuscated_info_hash)
.add_property("ip", &dht_outgoing_get_peers_alert_ip)
.add_property("ip", make_getter(&dht_outgoing_get_peers_alert::ip
, return_value_policy<return_by_value>()))
;
#ifndef TORRENT_DISABLE_LOGGING

View File

@ -3,15 +3,65 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "boost_python.hpp"
#include "libtorrent/socket.hpp"
#include "libtorrent/address.hpp"
#include "libtorrent/error_code.hpp"
#include <vector>
using namespace boost::python;
namespace bp = boost::python;
namespace lt = libtorrent;
template<class T>
struct endpoint_to_tuple
{
static PyObject* convert(T const& ep)
{
return incref(bp::make_tuple(ep.address().to_string(), ep.port()).ptr());
}
};
template<class T>
struct tuple_to_endpoint
{
tuple_to_endpoint()
{
converter::registry::push_back(
&convertible, &construct, type_id<T>()
);
}
static void* convertible(PyObject* x)
{
if (!PyTuple_Check(x)) return NULL;
if (PyTuple_Size(x) != 2) return NULL;
if (!PyString_Check(PyTuple_GetItem(x, 0))) return NULL;
if (!PyNumber_Check(PyTuple_GetItem(x, 1))) return NULL;
lt::error_code ec;
lt::address::from_string(PyString_AsString(PyTuple_GetItem(x, 0)), ec);
if (ec) return NULL;
return x;
}
static void construct(PyObject* x, converter::rvalue_from_python_stage1_data* data)
{
void* storage = ((converter::rvalue_from_python_storage<T*>*)data)
->storage.bytes;
object o(borrowed(x));
new (storage) T(lt::address::from_string(
extract<std::string>(o[0]))
, extract<int>(o[1]));
data->convertible = storage;
}
};
template<class T1, class T2>
struct pair_to_tuple
{
static PyObject* convert(const std::pair<T1, T2>& p)
{
return incref(make_tuple(p.first, p.second).ptr());
return incref(bp::make_tuple(p.first, p.second).ptr());
}
};
@ -27,7 +77,7 @@ struct tuple_to_pair
static void* convertible(PyObject* x)
{
return PyTuple_Check(x) ? x: 0;
return (PyTuple_Check(x) && PyTuple_Size(x) == 2) ? x: NULL;
}
static void construct(PyObject* x, converter::rvalue_from_python_stage1_data* data)
@ -44,8 +94,78 @@ struct tuple_to_pair
}
};
template<class T>
struct vector_to_list
{
static PyObject* convert(const std::vector<T>& v)
{
list l;
for (int i = 0; i < v.size(); ++i)
{
l.append(v[i]);
}
return incref(l.ptr());
}
};
template<class T>
struct list_to_vector
{
list_to_vector()
{
converter::registry::push_back(
&convertible, &construct, type_id<std::vector<T> >()
);
}
static void* convertible(PyObject* x)
{
return PyList_Check(x) ? x: 0;
}
static void construct(PyObject* x, converter::rvalue_from_python_stage1_data* data)
{
void* storage = ((converter::rvalue_from_python_storage<
std::vector<T> >*)data)->storage.bytes;
std::vector<T> p;
int const size = PyList_Size(x);
p.reserve(size);
for (int i = 0; i < size; ++i)
{
object o(borrowed(PyList_GetItem(x, i)));
p.push_back(extract<T>(o));
}
std::vector<T>* ptr = new (storage) std::vector<T>();
ptr->swap(p);
data->convertible = storage;
}
};
void bind_converters()
{
// C++ -> python conversions
to_python_converter<std::pair<int, int>, pair_to_tuple<int, int> >();
to_python_converter<std::pair<std::string, int>, pair_to_tuple<std::string, int> >();
to_python_converter<lt::tcp::endpoint, endpoint_to_tuple<lt::tcp::endpoint> >();
to_python_converter<lt::udp::endpoint, endpoint_to_tuple<lt::udp::endpoint> >();
to_python_converter<std::vector<std::string>, vector_to_list<std::string> >();
to_python_converter<std::vector<int>, vector_to_list<int> >();
to_python_converter<std::vector<boost::uint8_t>, vector_to_list<boost::uint8_t> >();
to_python_converter<std::vector<lt::tcp::endpoint>, vector_to_list<lt::tcp::endpoint> >();
to_python_converter<std::vector<lt::udp::endpoint>, vector_to_list<lt::udp::endpoint> >();
to_python_converter<std::vector<std::pair<std::string, int> >, vector_to_list<std::pair<std::string, int> > >();
// python -> C++ conversions
tuple_to_pair<int, int>();
tuple_to_pair<std::string, int>();
tuple_to_endpoint<lt::tcp::endpoint>();
tuple_to_endpoint<lt::udp::endpoint>();
list_to_vector<int>();
list_to_vector<boost::uint8_t>();
list_to_vector<std::string>();
list_to_vector<lt::tcp::endpoint>();
list_to_vector<lt::udp::endpoint>();
list_to_vector<std::pair<std::string, int> >();
}

View File

@ -680,6 +680,59 @@ void bind_session()
#endif // TORRENT_DISABLE_DHT
#endif // TORRENT_NO_DEPRECATE
#define PROP(val) \
make_getter(val, return_value_policy<return_by_value>()), \
make_setter(val, return_value_policy<return_by_value>())
class_<add_torrent_params>("add_torrent_params")
.def_readwrite("version", &add_torrent_params::version)
.def_readwrite("ti", &add_torrent_params::ti)
.add_property("trackers", PROP(&add_torrent_params::trackers))
.add_property("tracker_tiers", PROP(&add_torrent_params::tracker_tiers))
.add_property("dht_nodes", PROP(&add_torrent_params::dht_nodes))
.def_readwrite("name", &add_torrent_params::name)
.def_readwrite("save_path", &add_torrent_params::save_path)
.def_readwrite("storage_mode", &add_torrent_params::storage_mode)
// .def_readwrite("storage", &add_torrent_params::storage)
.add_property("file_priorities", PROP(&add_torrent_params::file_priorities))
.def_readwrite("trackerid", &add_torrent_params::trackerid)
.def_readwrite("url", &add_torrent_params::url)
.def_readwrite("flags", &add_torrent_params::flags)
.def_readwrite("info_hash", &add_torrent_params::info_hash)
.def_readwrite("max_uploads", &add_torrent_params::max_uploads)
.def_readwrite("max_connections", &add_torrent_params::max_connections)
.def_readwrite("upload_limit", &add_torrent_params::upload_limit)
.def_readwrite("download_limit", &add_torrent_params::download_limit)
.def_readwrite("total_uploaded", &add_torrent_params::total_uploaded)
.def_readwrite("total_downloaded", &add_torrent_params::total_downloaded)
.def_readwrite("active_time", &add_torrent_params::active_time)
.def_readwrite("finished_time", &add_torrent_params::finished_time)
.def_readwrite("seeding_time", &add_torrent_params::seeding_time)
.def_readwrite("added_time", &add_torrent_params::added_time)
.def_readwrite("completed_time", &add_torrent_params::completed_time)
.def_readwrite("last_seen_complete", &add_torrent_params::last_seen_complete)
.def_readwrite("num_complete", &add_torrent_params::num_complete)
.def_readwrite("num_incomplete", &add_torrent_params::num_incomplete)
.def_readwrite("num_downloaded", &add_torrent_params::num_downloaded)
.add_property("http_seeds", PROP(&add_torrent_params::http_seeds))
.add_property("url_seeds", PROP(&add_torrent_params::url_seeds))
.add_property("peers", PROP(&add_torrent_params::peers))
.add_property("banned_peers", PROP(&add_torrent_params::banned_peers))
.add_property("unfinished_pieces", PROP(&add_torrent_params::unfinished_pieces))
.add_property("have_pieces", PROP(&add_torrent_params::have_pieces))
.add_property("verified_pieces", PROP(&add_torrent_params::verified_pieces))
.add_property("piece_priorities", PROP(&add_torrent_params::piece_priorities))
.add_property("merkle_tree", PROP(&add_torrent_params::merkle_tree))
.add_property("renamed_files", PROP(&add_torrent_params::renamed_files))
#ifndef TORRENT_NO_DEPRECATE
.def_readwrite("uuid", &add_torrent_params::uuid)
.def_readwrite("source_feed_url", &add_torrent_params::source_feed_url)
.def_readwrite("resume_data", &add_torrent_params::resume_data)
#endif
;
enum_<storage_mode_t>("storage_mode_t")
.value("storage_mode_allocate", storage_mode_allocate)
.value("storage_mode_sparse", storage_mode_sparse)
@ -791,6 +844,8 @@ void bind_session()
#endif // TORRENT_DISABLE_DHT
.def("add_torrent", &add_torrent)
.def("async_add_torrent", &async_add_torrent)
.def("async_add_torrent", &lt::session::async_add_torrent)
.def("add_torrent", allow_threads((lt::torrent_handle (session_handle::*)(add_torrent_params const&))&lt::session::add_torrent))
#ifndef BOOST_NO_EXCEPTIONS
#ifndef TORRENT_NO_DEPRECATE
.def(

View File

@ -301,19 +301,6 @@ void set_metadata(torrent_handle& handle, std::string const& buf)
handle.set_metadata(buf.c_str(), buf.size());
}
namespace
{
tcp::endpoint tuple_to_endpoint(tuple const& t)
{
return tcp::endpoint(address::from_string(extract<std::string>(t[0])), extract<int>(t[1]));
}
}
void connect_peer(torrent_handle& th, tuple ip, int source)
{
th.connect_peer(tuple_to_endpoint(ip), source);
}
#ifndef TORRENT_NO_DEPRECATE
#if BOOST_VERSION > 104200
@ -336,16 +323,6 @@ boost::shared_ptr<torrent_info> get_torrent_info(torrent_handle const& h)
#endif
void set_peer_upload_limit(torrent_handle& th, tuple const& ip, int limit)
{
th.set_peer_upload_limit(tuple_to_endpoint(ip), limit);
}
void set_peer_download_limit(torrent_handle& th, tuple const& ip, int limit)
{
th.set_peer_download_limit(tuple_to_endpoint(ip), limit);
}
#endif // TORRENT_NO_DEPRECAE
void add_piece(torrent_handle& th, int piece, char const *data, int flags)
@ -471,18 +448,18 @@ void bind_torrent_handle()
.def("download_limit", _(&torrent_handle::download_limit))
.def("set_sequential_download", _(&torrent_handle::set_sequential_download))
#ifndef TORRENT_NO_DEPRECATE
.def("set_peer_upload_limit", &set_peer_upload_limit)
.def("set_peer_download_limit", &set_peer_download_limit)
.def("set_peer_upload_limit", &torrent_handle::set_peer_upload_limit)
.def("set_peer_download_limit", &torrent_handle::set_peer_download_limit)
.def("set_ratio", _(&torrent_handle::set_ratio))
.def("save_path", _(&torrent_handle::save_path))
#endif
.def("connect_peer", &connect_peer)
.def("set_max_uploads", _(&torrent_handle::set_max_uploads))
.def("connect_peer", &torrent_handle::connect_peer, (arg("endpoint"), arg("source")=0, arg("flags")=0xd))
.def("set_max_uploads", &torrent_handle::set_max_uploads)
.def("max_uploads", _(&torrent_handle::max_uploads))
.def("set_max_connections", _(&torrent_handle::set_max_connections))
.def("set_max_connections", &torrent_handle::set_max_connections)
.def("max_connections", _(&torrent_handle::max_connections))
#ifndef TORRENT_NO_DEPRECATE
.def("set_tracker_login", _(&torrent_handle::set_tracker_login))
.def("set_tracker_login", &torrent_handle::set_tracker_login)
#endif
.def("move_storage", _(move_storage0), (arg("path"), arg("flags") = 0))
.def("info_hash", _(&torrent_handle::info_hash))

View File

@ -21,10 +21,36 @@ class test_torrent_handle(unittest.TestCase):
h.prioritize_pieces([0])
self.assertEqual(h.piece_priorities(), [0])
# also test the overload that takes a list of piece->priority mappings
# also test the overload that takes a list of piece->priority mappings
h.prioritize_pieces([(0, 1)])
self.assertEqual(h.piece_priorities(), [1])
def test_read_resume_data(self):
resume_data = lt.bencode({'file-format': 'libtorrent resume file',
'info-hash': 'abababababababababab',
'name': 'test',
'save_path': '.',
'peers': '\x01\x01\x01\x01\x00\x01\x02\x02\x02\x02\x00\x02',
'file_priority': [0, 1, 1]})
tp = lt.read_resume_data(resume_data)
self.assertEqual(tp.name, 'test')
self.assertEqual(tp.info_hash, lt.sha1_hash('abababababababababab'))
self.assertEqual(tp.file_priorities, [0, 1, 1])
self.assertEqual(tp.peers, [('1.1.1.1', 1), ('2.2.2.2', 2)])
ses = lt.session({'alert_mask': lt.alert.category_t.all_categories})
h = ses.add_torrent(tp)
h.connect_peer(('3.3.3.3', 3))
for i in range(0, 10):
alerts = ses.pop_alerts()
for a in alerts:
print(a.message())
time.sleep(0.1)
class test_torrent_info(unittest.TestCase):
def test_bencoded_constructor(self):

View File

@ -41,6 +41,8 @@ POSSIBILITY OF SUCH DAMAGE.
#include <libtorrent/alert_types.hpp>
#include <libtorrent/bencode.hpp>
#include <libtorrent/torrent_status.hpp>
#include <libtorrent/read_resume_data.hpp>
#include <libtorrent/error_code.hpp>
namespace lt = libtorrent;
using clk = std::chrono::steady_clock;
@ -74,14 +76,16 @@ int main(int argc, char const* argv[])
| lt::alert::status_notification);
lt::session ses(pack);
lt::add_torrent_params atp;
clk::time_point last_save_resume = clk::now();
// load resume data from disk and pass it in as we add the magnet link
std::ifstream ifs(".resume_file", std::ios_base::binary);
ifs.unsetf(std::ios_base::skipws);
atp.resume_data.assign(std::istream_iterator<char>(ifs)
, std::istream_iterator<char>());
std::vector<char> buf{std::istream_iterator<char>(ifs)
, std::istream_iterator<char>()};
lt::error_code ec;
lt::add_torrent_params atp = lt::read_resume_data(&buf[0], buf.size(), ec);
atp.url = argv[1];
atp.save_path = "."; // save in current dir
ses.async_add_torrent(atp);

@ -1 +1 @@
Subproject commit 5f7cbb8bd222ed0e5cfdaffc2a2f5010fb5b4a29
Subproject commit 0151d5c17fa3f4cf0ce518d0b8f90a23792c9b24

View File

@ -89,6 +89,8 @@ namespace libtorrent
return ret;
}
ret.name = rd.dict_find_string_value("name");
ret.info_hash.assign(info_hash);
// TODO: 4 add unit test for this, and all other fields of the resume data

View File

@ -281,6 +281,8 @@ namespace libtorrent
#ifndef BOOST_NO_EXCEPTIONS
torrent_handle session_handle::add_torrent(add_torrent_params const& params)
{
TORRENT_ASSERT_PRECOND(!params.save_path.empty());
#ifndef TORRENT_NO_DEPRECATE
add_torrent_params p = params;
handle_backwards_compatible_resume_data(p);
@ -296,6 +298,8 @@ namespace libtorrent
torrent_handle session_handle::add_torrent(add_torrent_params const& params, error_code& ec)
{
TORRENT_ASSERT_PRECOND(!params.save_path.empty());
ec.clear();
#ifndef TORRENT_NO_DEPRECATE
add_torrent_params p = params;
@ -308,6 +312,8 @@ namespace libtorrent
void session_handle::async_add_torrent(add_torrent_params const& params)
{
TORRENT_ASSERT_PRECOND(!params.save_path.empty());
add_torrent_params* p = new add_torrent_params(params);
#ifndef TORRENT_NO_DEPRECATE
@ -353,6 +359,8 @@ namespace libtorrent
, storage_constructor_type sc
, void* userdata)
{
TORRENT_ASSERT_PRECOND(!save_path.empty());
add_torrent_params p(sc);
p.trackers.push_back(tracker_url);
p.info_hash = info_hash;