// Copyright Daniel Wallin 2006. Use, modification and distribution is // subject to the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "boost_python.hpp" #include #include #include #include #include #include #include #include "libtorrent/announce_entry.hpp" #include #include #include #include "gil.hpp" using namespace boost::python; using namespace lt; #ifdef _MSC_VER #pragma warning(push) // warning c4996: x: was declared deprecated #pragma warning( disable : 4996 ) #endif namespace { list url_seeds(torrent_handle& handle) { list ret; std::set urls; { allow_threading_guard guard; urls = handle.url_seeds(); } for (std::set::iterator i(urls.begin()) , end(urls.end()); i != end; ++i) ret.append(*i); return ret; } list http_seeds(torrent_handle& handle) { list ret; std::set urls; { allow_threading_guard guard; urls = handle.http_seeds(); } for (std::set::iterator i(urls.begin()) , end(urls.end()); i != end; ++i) ret.append(*i); return ret; } list piece_availability(torrent_handle& handle) { list ret; std::vector avail; { allow_threading_guard guard; handle.piece_availability(avail); } for (std::vector::iterator i(avail.begin()) , end(avail.end()); i != end; ++i) ret.append(*i); return ret; } list piece_priorities(torrent_handle& handle) { list ret; std::vector prio; { allow_threading_guard guard; prio = handle.piece_priorities(); } for (std::vector::iterator i(prio.begin()) , end(prio.end()); i != end; ++i) ret.append(*i); return ret; } } // namespace unnamed list file_progress(torrent_handle& handle, int flags) { std::vector p; { allow_threading_guard guard; std::shared_ptr ti = handle.torrent_file(); if (ti) { p.reserve(ti->num_files()); handle.file_progress(p, flags); } } list result; for (std::vector::iterator i(p.begin()), e(p.end()); i != e; ++i) result.append(*i); return result; } list get_peer_info(torrent_handle const& handle) { std::vector pi; { allow_threading_guard guard; handle.get_peer_info(pi); } list result; for (std::vector::iterator i = pi.begin(); i != pi.end(); ++i) result.append(*i); return result; } namespace { template T extract_fn(object o) { return boost::python::extract(o); } } void prioritize_pieces(torrent_handle& info, object o) { stl_input_iterator begin(o), end; if (begin == end) return; // determine which overload should be selected. the one taking a list of // priorities or the one taking a list of piece -> priority mappings bool const is_piece_list = extract>(*begin).check(); if (is_piece_list) { std::vector> piece_list; std::transform(begin, end, std::back_inserter(piece_list) , &extract_fn>); info.prioritize_pieces(piece_list); } else { std::vector priority_vector; std::transform(begin, end, std::back_inserter(priority_vector) , &extract_fn); info.prioritize_pieces(priority_vector); } } void prioritize_files(torrent_handle& info, object o) { stl_input_iterator begin(o), end; info.prioritize_files(std::vector (begin, end)); } list file_priorities(torrent_handle& handle) { list ret; std::vector priorities = handle.file_priorities(); for (std::vector::iterator i = priorities.begin(); i != priorities.end(); ++i) ret.append(*i); return ret; } int file_prioritity0(torrent_handle& h, file_index_t index) { return h.file_priority(index); } void file_prioritity1(torrent_handle& h, file_index_t index, int prio) { return h.file_priority(index, prio); } void dict_to_announce_entry(dict d, announce_entry& ae) { ae.url = extract(d["url"]); if (d.has_key("tier")) ae.tier = extract(d["tier"]); if (d.has_key("fail_limit")) ae.fail_limit = extract(d["fail_limit"]); } void replace_trackers(torrent_handle& h, object trackers) { object iter(trackers.attr("__iter__")()); std::vector result; for (;;) { handle<> entry(allow_null(PyIter_Next(iter.ptr()))); if (entry == handle<>()) break; if (extract(object(entry)).check()) { result.push_back(extract(object(entry))); } else { dict d; d = extract(object(entry)); announce_entry ae; dict_to_announce_entry(d, ae); result.push_back(ae); } } allow_threading_guard guard; h.replace_trackers(result); } void add_tracker(torrent_handle& h, dict d) { announce_entry ae; dict_to_announce_entry(d, ae); h.add_tracker(ae); } namespace { #if defined BOOST_ASIO_HAS_STD_CHRONO using std::chrono::system_clock; #else using boost::chrono::system_clock; #endif time_t to_ptime(time_point tpt) { return system_clock::to_time_t(system_clock::now() + duration_cast(tpt - clock_type::now())); } } list trackers(torrent_handle& h) { list ret; std::vector const trackers = h.trackers(); for (std::vector::const_iterator i = trackers.begin(), end(trackers.end()); i != end; ++i) { dict d; d["url"] = i->url; d["trackerid"] = i->trackerid; d["message"] = i->message; dict last_error; last_error["value"] = i->last_error.value(); last_error["category"] = i->last_error.category().name(); d["last_error"] = last_error; if (i->next_announce > min_time()) { d["next_announce"] = to_ptime(i->next_announce); } else { d["next_announce"] = object(); } if (i->min_announce > min_time()) { d["min_announce"] = to_ptime(i->min_announce); } else { d["min_announce"] = object(); } d["scrape_incomplete"] = i->scrape_incomplete; d["scrape_complete"] = i->scrape_complete; d["scrape_downloaded"] = i->scrape_downloaded; d["tier"] = i->tier; d["fail_limit"] = i->fail_limit; d["fails"] = i->fails; d["source"] = i->source; d["verified"] = i->verified; d["updating"] = i->updating; d["start_sent"] = i->start_sent; d["complete_sent"] = i->complete_sent; #ifndef TORRENT_NO_DEPRECATE d["send_stats"] = i->send_stats; #endif ret.append(d); } return ret; } list get_download_queue(torrent_handle& handle) { list ret; std::vector downloading; { allow_threading_guard guard; handle.get_download_queue(downloading); } for (std::vector::iterator i = downloading.begin() , end(downloading.end()); i != end; ++i) { dict partial_piece; partial_piece["piece_index"] = i->piece_index; partial_piece["blocks_in_piece"] = i->blocks_in_piece; list block_list; for (int k = 0; k < i->blocks_in_piece; ++k) { dict block_info; block_info["state"] = i->blocks[k].state; block_info["num_peers"] = i->blocks[k].num_peers; block_info["bytes_progress"] = i->blocks[k].bytes_progress; block_info["block_size"] = i->blocks[k].block_size; block_info["peer"] = boost::python::make_tuple( i->blocks[k].peer().address().to_string() , i->blocks[k].peer().port()); block_list.append(block_info); } partial_piece["blocks"] = block_list; ret.append(partial_piece); } return ret; } void set_metadata(torrent_handle& handle, std::string const& buf) { handle.set_metadata(buf); } #ifndef TORRENT_NO_DEPRECATE #if BOOST_VERSION > 104200 std::shared_ptr get_torrent_info(torrent_handle const& h) { allow_threading_guard guard; return h.torrent_file(); } #else std::shared_ptr get_torrent_info(torrent_handle const& h) { // I can't figure out how to expose shared_ptr // as well as supporting mutable instances. So, this hack is better // than compilation errors. It seems to work on newer versions of boost though allow_threading_guard guard; return std::const_pointer_cast(h.torrent_file()); } #endif #endif // TORRENT_NO_DEPRECAE void add_piece(torrent_handle& th, piece_index_t piece, char const *data, int flags) { th.add_piece(piece, data, flags); } using by_value = return_value_policy; void bind_torrent_handle() { // arguments are: number of seconds and tracker index void (torrent_handle::*force_reannounce0)(int, int) const = &torrent_handle::force_reannounce; #ifndef TORRENT_NO_DEPRECATE bool (torrent_handle::*super_seeding0)() const = &torrent_handle::super_seeding; #endif void (torrent_handle::*super_seeding1)(bool) const = &torrent_handle::super_seeding; int (torrent_handle::*piece_priority0)(piece_index_t) const = &torrent_handle::piece_priority; void (torrent_handle::*piece_priority1)(piece_index_t, int) const = &torrent_handle::piece_priority; void (torrent_handle::*move_storage0)(std::string const&, int flags) const = &torrent_handle::move_storage; void (torrent_handle::*rename_file0)(file_index_t, std::string const&) const = &torrent_handle::rename_file; #if TORRENT_USE_WSTRING && !defined TORRENT_NO_DEPRECATE void (torrent_handle::*move_storage1)(std::wstring const&, int flags) const = &torrent_handle::move_storage; void (torrent_handle::*rename_file1)(file_index_t, std::wstring const&) const = &torrent_handle::rename_file; #endif std::vector (torrent_handle::*file_status0)() const = &torrent_handle::file_status; #define _ allow_threads class_("torrent_handle") .def(self == self) .def(self != self) .def(self < self) .def("get_peer_info", get_peer_info) .def("status", _(&torrent_handle::status), arg("flags") = 0xffffffff) .def("get_download_queue", get_download_queue) .def("file_progress", file_progress, arg("flags") = 0) .def("trackers", trackers) .def("replace_trackers", replace_trackers) .def("add_tracker", add_tracker) .def("add_url_seed", _(&torrent_handle::add_url_seed)) .def("remove_url_seed", _(&torrent_handle::remove_url_seed)) .def("url_seeds", url_seeds) .def("add_http_seed", _(&torrent_handle::add_http_seed)) .def("remove_http_seed", _(&torrent_handle::remove_http_seed)) .def("http_seeds", http_seeds) .def("torrent_file", _(&torrent_handle::torrent_file)) .def("set_metadata", set_metadata) .def("is_valid", _(&torrent_handle::is_valid)) .def("pause", _(&torrent_handle::pause), arg("flags") = 0) .def("resume", _(&torrent_handle::resume)) .def("stop_when_ready", _(&torrent_handle::stop_when_ready)) .def("clear_error", _(&torrent_handle::clear_error)) .def("super_seeding", super_seeding1) .def("auto_managed", _(&torrent_handle::auto_managed)) .def("queue_position", _(&torrent_handle::queue_position)) .def("queue_position_up", _(&torrent_handle::queue_position_up)) .def("queue_position_down", _(&torrent_handle::queue_position_down)) .def("queue_position_top", _(&torrent_handle::queue_position_top)) .def("queue_position_bottom", _(&torrent_handle::queue_position_bottom)) // deprecated #ifndef TORRENT_NO_DEPRECATE .def("set_priority", _(&torrent_handle::set_priority)) .def("get_torrent_info", &get_torrent_info) .def("super_seeding", super_seeding0) .def("write_resume_data", _(&torrent_handle::write_resume_data)) .def("is_seed", _(&torrent_handle::is_seed)) .def("is_finished", _(&torrent_handle::is_finished)) .def("is_paused", _(&torrent_handle::is_paused)) .def("is_auto_managed", _(&torrent_handle::is_auto_managed)) .def("has_metadata", _(&torrent_handle::has_metadata)) .def("use_interface", &torrent_handle::use_interface) .def("name", _(&torrent_handle::name)) #endif .def("add_piece", add_piece) .def("read_piece", _(&torrent_handle::read_piece)) .def("have_piece", _(&torrent_handle::have_piece)) .def("set_piece_deadline", _(&torrent_handle::set_piece_deadline) , (arg("index"), arg("deadline"), arg("flags") = 0)) .def("reset_piece_deadline", _(&torrent_handle::reset_piece_deadline), (arg("index"))) .def("clear_piece_deadlines", _(&torrent_handle::clear_piece_deadlines), (arg("index"))) .def("piece_availability", &piece_availability) .def("piece_priority", _(piece_priority0)) .def("piece_priority", _(piece_priority1)) .def("prioritize_pieces", &prioritize_pieces) .def("piece_priorities", &piece_priorities) .def("prioritize_files", &prioritize_files) .def("file_priorities", &file_priorities) .def("file_priority", &file_prioritity0) .def("file_priority", &file_prioritity1) .def("file_status", _(file_status0)) .def("save_resume_data", _(&torrent_handle::save_resume_data), arg("flags") = 0) .def("need_save_resume_data", _(&torrent_handle::need_save_resume_data)) .def("force_reannounce", _(force_reannounce0) , (arg("seconds") = 0, arg("tracker_idx") = -1)) #ifndef TORRENT_DISABLE_DHT .def("force_dht_announce", _(&torrent_handle::force_dht_announce)) #endif .def("scrape_tracker", _(&torrent_handle::scrape_tracker), arg("index") = -1) .def("set_upload_mode", _(&torrent_handle::set_upload_mode)) .def("set_share_mode", _(&torrent_handle::set_share_mode)) .def("flush_cache", &torrent_handle::flush_cache) .def("apply_ip_filter", &torrent_handle::apply_ip_filter) .def("set_upload_limit", _(&torrent_handle::set_upload_limit)) .def("upload_limit", _(&torrent_handle::upload_limit)) .def("set_download_limit", _(&torrent_handle::set_download_limit)) .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", &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", &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("max_connections", _(&torrent_handle::max_connections)) #ifndef TORRENT_NO_DEPRECATE .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)) .def("force_recheck", _(&torrent_handle::force_recheck)) .def("rename_file", _(rename_file0)) .def("set_ssl_certificate", &torrent_handle::set_ssl_certificate, (arg("cert"), arg("private_key"), arg("dh_params"), arg("passphrase")="")) #if TORRENT_USE_WSTRING && !defined TORRENT_NO_DEPRECATE .def("move_storage", _(move_storage1), (arg("path"), arg("flags") = 0)) .def("rename_file", _(rename_file1)) #endif ; class_("open_file_state") .add_property("file_index", make_getter((&open_file_state::file_index), by_value())) .def_readonly("last_use", &open_file_state::last_use) .def_readonly("open_mode", &open_file_state::open_mode) ; enum_("file_open_mode") .value("read_only", file_open_mode::read_only) .value("write_only", file_open_mode::write_only) .value("read_write", file_open_mode::read_write) .value("rw_mask", file_open_mode::rw_mask) .value("sparse", file_open_mode::sparse) .value("no_atime", file_open_mode::no_atime) .value("random_access", file_open_mode::random_access) .value("locked", file_open_mode::locked) ; enum_("file_progress_flags") .value("piece_granularity", torrent_handle::piece_granularity) ; enum_("add_piece_flags_t") .value("overwrite_existing", torrent_handle::overwrite_existing) ; enum_("pause_flags_t") .value("graceful_pause", torrent_handle::graceful_pause) ; enum_("save_resume_flags_t") .value("flush_disk_cache", torrent_handle::flush_disk_cache) .value("save_info_dict", torrent_handle::save_info_dict) .value("only_if_modified", torrent_handle::only_if_modified) ; enum_("deadline_flags") .value("alert_when_available", torrent_handle::alert_when_available) ; enum_("status_flags_t") .value("query_distributed_copies", torrent_handle::query_distributed_copies) .value("query_accurate_download_counters", torrent_handle::query_accurate_download_counters) .value("query_last_seen_complete", torrent_handle::query_last_seen_complete) .value("query_pieces", torrent_handle::query_pieces) .value("query_verified_pieces", torrent_handle::query_verified_pieces) ; enum_("move_flags_t") .value("always_replace_files", always_replace_files) .value("fail_if_exist", fail_if_exist) .value("dont_replace", dont_replace) ; } #ifdef _MSC_VER #pragma warning(pop) #endif