forked from premiere/premiere-libtorrent
add check and test for torrent parameter (#1541)
add test and fix for add_torrent_params python binding
This commit is contained in:
parent
32e0028e32
commit
c979802ce9
|
@ -1,3 +1,4 @@
|
||||||
|
* python binding add more add_torrent_params fields and an invalid key check
|
||||||
* introduce introduce distinct types for peer_class_t, piece_index_t and
|
* introduce introduce distinct types for peer_class_t, piece_index_t and
|
||||||
file_index_t.
|
file_index_t.
|
||||||
* fix crash caused by empty bitfield
|
* fix crash caused by empty bitfield
|
||||||
|
|
|
@ -109,6 +109,41 @@ struct tuple_to_pair
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<class T1, class T2>
|
||||||
|
struct dict_to_map
|
||||||
|
{
|
||||||
|
dict_to_map()
|
||||||
|
{
|
||||||
|
converter::registry::push_back(
|
||||||
|
&convertible, &construct, type_id<std::map<T1, T2>>()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* convertible(PyObject* x)
|
||||||
|
{
|
||||||
|
return PyDict_Check(x) ? x: nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void construct(PyObject* x, converter::rvalue_from_python_stage1_data* data)
|
||||||
|
{
|
||||||
|
void* storage = ((converter::rvalue_from_python_storage<
|
||||||
|
std::map<T1, T2>>*)data)->storage.bytes;
|
||||||
|
|
||||||
|
dict o(borrowed(x));
|
||||||
|
std::map<T1, T2> m;
|
||||||
|
|
||||||
|
list iterkeys = (list)o.keys();
|
||||||
|
int const len = int(boost::python::len(iterkeys));
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
object key = iterkeys[i];
|
||||||
|
m[extract<T1>(key)] = extract<T2>(o[key]);
|
||||||
|
}
|
||||||
|
new (storage) std::map<T1, T2>(m);
|
||||||
|
data->convertible = storage;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
struct vector_to_list
|
struct vector_to_list
|
||||||
{
|
{
|
||||||
|
@ -203,6 +238,7 @@ void bind_converters()
|
||||||
to_python_converter<lt::tcp::endpoint, endpoint_to_tuple<lt::tcp::endpoint>>();
|
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<lt::udp::endpoint, endpoint_to_tuple<lt::udp::endpoint>>();
|
||||||
to_python_converter<lt::address, address_to_tuple>();
|
to_python_converter<lt::address, address_to_tuple>();
|
||||||
|
to_python_converter<std::pair<std::string, int>, pair_to_tuple<std::string, int>>();
|
||||||
|
|
||||||
to_python_converter<std::vector<lt::stats_metric>, vector_to_list<lt::stats_metric>>();
|
to_python_converter<std::vector<lt::stats_metric>, vector_to_list<lt::stats_metric>>();
|
||||||
to_python_converter<std::vector<lt::pool_file_status>, vector_to_list<lt::pool_file_status>>();
|
to_python_converter<std::vector<lt::pool_file_status>, vector_to_list<lt::pool_file_status>>();
|
||||||
|
@ -223,6 +259,7 @@ void bind_converters()
|
||||||
tuple_to_endpoint<lt::tcp::endpoint>();
|
tuple_to_endpoint<lt::tcp::endpoint>();
|
||||||
tuple_to_endpoint<lt::udp::endpoint>();
|
tuple_to_endpoint<lt::udp::endpoint>();
|
||||||
tuple_to_pair<lt::piece_index_t, int>();
|
tuple_to_pair<lt::piece_index_t, int>();
|
||||||
|
dict_to_map<lt::file_index_t, std::string>();
|
||||||
list_to_vector<int>();
|
list_to_vector<int>();
|
||||||
list_to_vector<std::uint8_t>();
|
list_to_vector<std::uint8_t>();
|
||||||
list_to_vector<std::string>();
|
list_to_vector<std::string>();
|
||||||
|
|
|
@ -206,8 +206,16 @@ namespace
|
||||||
|
|
||||||
void dict_to_add_torrent_params(dict params, add_torrent_params& p)
|
void dict_to_add_torrent_params(dict params, add_torrent_params& p)
|
||||||
{
|
{
|
||||||
// torrent_info objects are always held by a shared_ptr in the python binding
|
list items = params.items();
|
||||||
if (params.has_key("ti") && params.get("ti") != boost::python::object())
|
int const len = int(boost::python::len(items));
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
boost::python::api::object_item item = items[i];
|
||||||
|
std::string const key = extract<std::string>(item[0]);
|
||||||
|
object const value = item[1];
|
||||||
|
// torrent_info objects are always held by a shared_ptr in the
|
||||||
|
// python binding, skip it if it is a object
|
||||||
|
if(key == "ti" && value != boost::python::object())
|
||||||
{
|
{
|
||||||
// make a copy here. We don't want to end up holding a python-owned
|
// make a copy here. We don't want to end up holding a python-owned
|
||||||
// object inside libtorrent. If the last reference goes out of scope
|
// object inside libtorrent. If the last reference goes out of scope
|
||||||
|
@ -215,49 +223,106 @@ namespace
|
||||||
// without holding the GIL and likely crash.
|
// without holding the GIL and likely crash.
|
||||||
// https://mail.python.org/pipermail/cplusplus-sig/2007-June/012130.html
|
// https://mail.python.org/pipermail/cplusplus-sig/2007-June/012130.html
|
||||||
p.ti = std::make_shared<torrent_info>(
|
p.ti = std::make_shared<torrent_info>(
|
||||||
extract<torrent_info const&>(params["ti"]));
|
extract<torrent_info const&>(value));
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
else if(key == "info_hash")
|
||||||
|
|
||||||
if (params.has_key("info_hash"))
|
|
||||||
p.info_hash = sha1_hash(bytes(extract<bytes>(params["info_hash"])).arr.data());
|
|
||||||
if (params.has_key("name"))
|
|
||||||
p.name = extract<std::string>(params["name"]);
|
|
||||||
p.save_path = extract<std::string>(params["save_path"]);
|
|
||||||
|
|
||||||
#ifndef TORRENT_NO_DEPRECATE
|
|
||||||
if (params.has_key("resume_data"))
|
|
||||||
{
|
{
|
||||||
std::string resume = extract<std::string>(params["resume_data"]);
|
p.info_hash = sha1_hash(
|
||||||
|
bytes(extract<bytes>(value)).arr.data());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if(key == "name")
|
||||||
|
{
|
||||||
|
p.name = extract<std::string>(value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if(key == "save_path")
|
||||||
|
{
|
||||||
|
p.save_path = extract<std::string>(value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#ifndef TORRENT_NO_DEPRECATE
|
||||||
|
else if(key == "resume_data")
|
||||||
|
{
|
||||||
|
std::string resume = extract<std::string>(value);
|
||||||
p.resume_data.assign(resume.begin(), resume.end());
|
p.resume_data.assign(resume.begin(), resume.end());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if(key == "uuid")
|
||||||
|
{
|
||||||
|
p.uuid = extract<std::string>(value);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (params.has_key("storage_mode"))
|
else if(key == "storage_mode")
|
||||||
p.storage_mode = extract<storage_mode_t>(params["storage_mode"]);
|
{
|
||||||
|
p.storage_mode = extract<storage_mode_t>(value);
|
||||||
if (params.has_key("trackers"))
|
continue;
|
||||||
p.trackers = extract<std::vector<std::string>>(params["trackers"]);
|
}
|
||||||
if (params.has_key("dht_nodes"))
|
else if(key == "trackers")
|
||||||
p.dht_nodes = extract<std::vector<std::pair<std::string, int>>>(params["dht_nodes"]);
|
{
|
||||||
if (params.has_key("http_seeds"))
|
p.trackers = extract<std::vector<std::string>>(value);
|
||||||
p.http_seeds = extract<std::vector<std::string>>(params["http_seeds"]);
|
continue;
|
||||||
if (params.has_key("peers"))
|
}
|
||||||
p.peers = extract<std::vector<tcp::endpoint>>(params["peers"]);
|
else if(key == "url_seeds")
|
||||||
if (params.has_key("banned_peers"))
|
{
|
||||||
p.banned_peers = extract<std::vector<tcp::endpoint>>(params["banned_peers"]);
|
p.url_seeds = extract<std::vector<std::string>>(value);
|
||||||
if (params.has_key("flags"))
|
continue;
|
||||||
p.flags = extract<std::uint64_t>(params["flags"]);
|
}
|
||||||
if (params.has_key("trackerid"))
|
else if(key == "http_seeds")
|
||||||
p.trackerid = extract<std::string>(params["trackerid"]);
|
{
|
||||||
if (params.has_key("url"))
|
p.http_seeds =
|
||||||
p.url = extract<std::string>(params["url"]);
|
extract<decltype(add_torrent_params::http_seeds)>(value);
|
||||||
#ifndef TORRENT_NO_DEPRECATE
|
continue;
|
||||||
if (params.has_key("uuid"))
|
}
|
||||||
p.uuid = extract<std::string>(params["uuid"]);
|
else if(key == "dht_nodes")
|
||||||
#endif
|
{
|
||||||
|
p.dht_nodes =
|
||||||
if (params.has_key("file_priorities"))
|
extract<std::vector<std::pair<std::string, int>>>(value);
|
||||||
p.file_priorities = extract<std::vector<std::uint8_t>>(params["file_priorities"]);
|
continue;
|
||||||
|
}
|
||||||
|
else if(key == "banned_peers")
|
||||||
|
{
|
||||||
|
p.banned_peers = extract<std::vector<lt::tcp::endpoint>>(value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if(key == "peers")
|
||||||
|
{
|
||||||
|
p.peers = extract<std::vector<lt::tcp::endpoint>>(value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if(key == "flags")
|
||||||
|
{
|
||||||
|
p.flags = extract<std::uint64_t>(value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if(key == "trackerid")
|
||||||
|
{
|
||||||
|
p.trackerid = extract<std::string>(value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if(key == "url")
|
||||||
|
{
|
||||||
|
p.url = extract<std::string>(value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if(key == "renamed_files")
|
||||||
|
{
|
||||||
|
p.renamed_files =
|
||||||
|
extract<std::map<lt::file_index_t, std::string>>(value);
|
||||||
|
}
|
||||||
|
else if(key == "file_priorities")
|
||||||
|
{
|
||||||
|
p.file_priorities = extract<std::vector<std::uint8_t>>(value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_KeyError,
|
||||||
|
("unknown name in torrent params: " + key).c_str());
|
||||||
|
throw_error_already_set();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
|
|
|
@ -127,6 +127,45 @@ class test_torrent_handle(unittest.TestCase):
|
||||||
cs = self.ses.get_cache_info(self.h)
|
cs = self.ses.get_cache_info(self.h)
|
||||||
self.assertEqual(cs.pieces, [])
|
self.assertEqual(cs.pieces, [])
|
||||||
|
|
||||||
|
def test_unknown_torrent_parameter(self):
|
||||||
|
self.ses = lt.session({'alert_mask': lt.alert.category_t.all_categories,
|
||||||
|
'enable_dht': False})
|
||||||
|
try:
|
||||||
|
self.h = self.ses.add_torrent({'unexpected-key-name': ''})
|
||||||
|
self.assertFalse('should have thrown an exception')
|
||||||
|
except KeyError as e:
|
||||||
|
print(e)
|
||||||
|
|
||||||
|
def test_torrent_parameter(self):
|
||||||
|
self.ses = lt.session({'alert_mask': lt.alert.category_t.all_categories,
|
||||||
|
'enable_dht': False})
|
||||||
|
self.ti = lt.torrent_info('url_seed_multi.torrent');
|
||||||
|
self.h = self.ses.add_torrent({
|
||||||
|
'ti': self.ti,
|
||||||
|
'save_path': os.getcwd(),
|
||||||
|
'trackers': ['http://test.com/announce'],
|
||||||
|
'dht_nodes': [('1.2.3.4', 6881), ('4.3.2.1', 6881)],
|
||||||
|
'file_priorities': [1,1],
|
||||||
|
'http_seeds': ['http://test.com/file3'],
|
||||||
|
'url_seeds': ['http://test.com/announce-url'],
|
||||||
|
'peers': [('5.6.7.8', 6881)],
|
||||||
|
'banned_peers': [('8.7.6.5', 6881)],
|
||||||
|
'renamed_files': { 0: 'test.txt', 2: 'test.txt' }
|
||||||
|
})
|
||||||
|
self.st = self.h.status()
|
||||||
|
self.assertEqual(self.st.save_path, os.getcwd())
|
||||||
|
trackers = self.h.trackers();
|
||||||
|
self.assertEqual(len(trackers), 1)
|
||||||
|
self.assertEqual(trackers[0].get('url'), 'http://test.com/announce')
|
||||||
|
self.assertEqual(trackers[0].get('tier'), 0)
|
||||||
|
self.assertEqual(self.h.file_priorities(), [1,1])
|
||||||
|
self.assertEqual(self.h.http_seeds(),['http://test.com/file3'])
|
||||||
|
# url_seeds was already set, test that it did not got overwritten
|
||||||
|
self.assertEqual(self.h.url_seeds(),
|
||||||
|
['http://test.com/announce-url/', 'http://test.com/file/'])
|
||||||
|
self.assertEqual(self.h.piece_priorities(),[4])
|
||||||
|
self.assertEqual(self.ti.merkle_tree(),[])
|
||||||
|
self.assertEqual(self.st.verified_pieces,[])
|
||||||
|
|
||||||
class test_torrent_info(unittest.TestCase):
|
class test_torrent_info(unittest.TestCase):
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue