From b6ee1d0e37db53bb753971c4abf87cd6b02db70a Mon Sep 17 00:00:00 2001 From: Marcos Pinto Date: Tue, 31 Jul 2007 06:04:40 +0000 Subject: [PATCH] torrent piece plugin - micah --- libtorrent/include/libtorrent/alert_types.hpp | 57 +++++ .../include/libtorrent/torrent_handle.hpp | 6 + libtorrent/src/peer_connection.cpp | 29 ++- libtorrent/src/torrent.cpp | 5 + libtorrent/src/torrent_handle.cpp | 3 + plugins/TorrentPieces/__init__.py | 98 +++++++++ plugins/TorrentPieces/tab_pieces.py | 115 ++++++++++ po/POTFILES.in | 2 + po/deluge.pot | 65 ++++++ src/core.py | 15 +- src/deluge_core.cpp | 196 +++++++++++++++--- 11 files changed, 561 insertions(+), 30 deletions(-) create mode 100644 plugins/TorrentPieces/__init__.py create mode 100644 plugins/TorrentPieces/tab_pieces.py diff --git a/libtorrent/include/libtorrent/alert_types.hpp b/libtorrent/include/libtorrent/alert_types.hpp index 006e3a547..f78deb069 100755 --- a/libtorrent/include/libtorrent/alert_types.hpp +++ b/libtorrent/include/libtorrent/alert_types.hpp @@ -183,6 +183,63 @@ namespace libtorrent { return std::auto_ptr(new torrent_finished_alert(*this)); } }; + struct TORRENT_EXPORT piece_finished_alert: torrent_alert + { + piece_finished_alert( + const torrent_handle& h + , int piece_num + , const std::string& msg) + : torrent_alert(h, alert::warning, msg) + , piece_index(piece_num) + { assert(piece_index >= 0);} + + int piece_index; + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new piece_finished_alert(*this)); } + }; + + struct TORRENT_EXPORT block_finished_alert: torrent_alert + { + block_finished_alert( + const torrent_handle& h + , int block_num + , int piece_num + , const std::string& msg) + : torrent_alert(h, alert::warning, msg) + , block_index(block_num) + , piece_index(piece_num) + { assert(block_index >= 0 && piece_index >= 0);} + + int block_index; + int piece_index; + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new block_finished_alert(*this)); } + }; + + struct TORRENT_EXPORT block_downloading_alert: torrent_alert + { + block_downloading_alert( + const torrent_handle& h + , std::string& speedmsg + , int block_num + , int piece_num + , const std::string& msg) + : torrent_alert(h, alert::warning, msg) + , peer_speedmsg(speedmsg) + , block_index(block_num) + , piece_index(piece_num) + { assert(block_index >= 0 && piece_index >= 0);} + + std::string peer_speedmsg; + int block_index; + int piece_index; + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new block_downloading_alert(*this)); } + }; + struct TORRENT_EXPORT storage_moved_alert: torrent_alert { storage_moved_alert(torrent_handle const& h, std::string const& path) diff --git a/libtorrent/include/libtorrent/torrent_handle.hpp b/libtorrent/include/libtorrent/torrent_handle.hpp index a4c8af923..6fbaaffad 100755 --- a/libtorrent/include/libtorrent/torrent_handle.hpp +++ b/libtorrent/include/libtorrent/torrent_handle.hpp @@ -241,6 +241,12 @@ namespace libtorrent enum { max_blocks_per_piece = 256 }; int piece_index; int blocks_in_piece; + // the number of blocks in the finished state + int finished; + // the number of blocks in the writing state + int writing; + // the number of blocks in the requested state + int requested; block_info blocks[max_blocks_per_piece]; enum state_t { none, slow, medium, fast }; state_t piece_state; diff --git a/libtorrent/src/peer_connection.cpp b/libtorrent/src/peer_connection.cpp index 7dbef4381..397c7b16f 100755 --- a/libtorrent/src/peer_connection.cpp +++ b/libtorrent/src/peer_connection.cpp @@ -1183,6 +1183,11 @@ namespace libtorrent assert(p.start == j.offset); piece_block block_finished(p.piece, p.start / t->block_size()); picker.mark_as_finished(block_finished, peer_info_struct()); + if (t->alerts().should_post(alert::info)) + { + t->alerts().post_alert(block_finished_alert(t->get_handle(), + block_finished.block_index, block_finished.piece_index, "block finished")); + } if (!has_peer_choked() && !t->is_seed() && !m_torrent.expired()) { @@ -1290,11 +1295,29 @@ namespace libtorrent piece_picker::piece_state_t state; peer_speed_t speed = peer_speed(); - if (speed == fast) state = piece_picker::fast; - else if (speed == medium) state = piece_picker::medium; - else state = piece_picker::slow; + std::string speedmsg; + if (speed == fast) + { + speedmsg = "fast"; + state = piece_picker::fast; + } + else if (speed == medium) + { + speedmsg = "medium"; + state = piece_picker::medium; + } + else + { + speedmsg = "slow"; + state = piece_picker::slow; + } t->picker().mark_as_downloading(block, peer_info_struct(), state); + if (t->alerts().should_post(alert::info)) + { + t->alerts().post_alert(block_downloading_alert(t->get_handle(), + speedmsg, block.block_index, block.piece_index, "block downloading")); + } m_request_queue.push_back(block); } diff --git a/libtorrent/src/torrent.cpp b/libtorrent/src/torrent.cpp index 39f29172f..9d83cc6d9 100755 --- a/libtorrent/src/torrent.cpp +++ b/libtorrent/src/torrent.cpp @@ -831,6 +831,11 @@ namespace libtorrent if (passed_hash_check) { + if (m_ses.m_alerts.should_post(alert::info)) + { + m_ses.m_alerts.post_alert(piece_finished_alert(get_handle() + , index, "piece finished")); + } // the following call may cause picker to become invalid // in case we just became a seed announce_piece(index); diff --git a/libtorrent/src/torrent_handle.cpp b/libtorrent/src/torrent_handle.cpp index 10e1172fa..4538e66e8 100755 --- a/libtorrent/src/torrent_handle.cpp +++ b/libtorrent/src/torrent_handle.cpp @@ -773,6 +773,9 @@ namespace libtorrent partial_piece_info pi; pi.piece_state = (partial_piece_info::state_t)i->state; pi.blocks_in_piece = p.blocks_in_piece(i->index); + pi.finished = (int)i->finished; + pi.writing = (int)i->writing; + pi.requested = (int)i->requested; int piece_size = t->torrent_file().piece_size(i->index); for (int j = 0; j < pi.blocks_in_piece; ++j) { diff --git a/plugins/TorrentPieces/__init__.py b/plugins/TorrentPieces/__init__.py new file mode 100644 index 000000000..55db89471 --- /dev/null +++ b/plugins/TorrentPieces/__init__.py @@ -0,0 +1,98 @@ +# Copyright (C) 2007 - Micah Bucy +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + +### Initialization ### + +plugin_name = _("Torrent Pieces") +plugin_author = "Micah Bucy" +plugin_version = "0.1" +plugin_description = _(""" +Adds a pieces tab which gives piece by piece progress for a torrent. +Each piece is represented by a small progress bar. + +Pieces currently downloading show up as partially filled progress bars, +but this does not represent percentage done. + +More information is provided as a tooltip for each piece. +For currently downloading pieces, the tooltip contains the number +of blocks finished as well as the peer speed for that piece. + +When the plugin initializes, such as when enabling the plugin or +when a different torrent is selected, the cpu will spike. This is normal, +as initialization must get information on every piece from libtorrent, +and the cpu will normalize once all of the information is retrieved.""") + +def deluge_init(deluge_path): + global path + path = deluge_path + +def enable(core, interface): + global path + return TorrentPieces(path, core, interface) + +### The Plugin ### +import deluge +import gtk +from TorrentPieces.tab_pieces import PiecesManager + +class TorrentPieces: + + def __init__(self, path, core, interface): + print "Loading TorrentPieces plugin..." + self.manager = core + self.parent = interface + self.table = gtk.Table() + self.viewport = gtk.Viewport() + self.viewport.add(self.table) + self.scrolledWindow = gtk.ScrolledWindow() + self.scrolledWindow.add(self.viewport) + self.scrolledWindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + + self.topWidget = self.scrolledWindow + + self.parentNotebook = self.parent.notebook + + self.parentNotebook.append_page(self.topWidget, gtk.Label(_("Pieces"))) + self.viewport.show() + self.scrolledWindow.show() + self.table.show() + self.tab_pieces = PiecesManager(self.table, self.manager) + + def unload(self): + self.manager.disconnect_event(self.manager.constants['EVENT_PIECE_FINISHED'], self.tab_pieces.handle_event) + self.manager.disconnect_event(self.manager.constants['EVENT_BLOCK_FINISHED'], self.tab_pieces.handle_event) + self.manager.disconnect_event(self.manager.constants['EVENT_BLOCK_DOWNLOADING'], self.tab_pieces.handle_event) + numPages = self.parentNotebook.get_n_pages() + for page in xrange(numPages): + if self.parentNotebook.get_nth_page(page) == self.topWidget: + self.parentNotebook.remove_page(page) + break + + def update(self): + unique_id = self.parent.get_selected_torrent() + # If no torrents added or more than one torrent selected + if unique_id is None: + return + if unique_id != self.tab_pieces.unique_id: + self.manager.disconnect_event(self.manager.constants['EVENT_PIECE_FINISHED'], self.tab_pieces.handle_event) + self.manager.disconnect_event(self.manager.constants['EVENT_BLOCK_FINISHED'], self.tab_pieces.handle_event) + self.manager.disconnect_event(self.manager.constants['EVENT_BLOCK_DOWNLOADING'], self.tab_pieces.handle_event) + self.tab_pieces.clear_pieces_store() + self.tab_pieces.set_unique_id(unique_id) + self.tab_pieces.prepare_pieces_store() + self.manager.connect_event(self.manager.constants['EVENT_PIECE_FINISHED'], self.tab_pieces.handle_event) + self.manager.connect_event(self.manager.constants['EVENT_BLOCK_FINISHED'], self.tab_pieces.handle_event) + self.manager.connect_event(self.manager.constants['EVENT_BLOCK_DOWNLOADING'], self.tab_pieces.handle_event) diff --git a/plugins/TorrentPieces/tab_pieces.py b/plugins/TorrentPieces/tab_pieces.py new file mode 100644 index 000000000..5a3ec9c32 --- /dev/null +++ b/plugins/TorrentPieces/tab_pieces.py @@ -0,0 +1,115 @@ +import gtk + +import math + +class PiecesManager(object): + def __init__(self, table, manager): + self.table = table + self.manager = manager + self.progress = [] + self.tooltips = [] + self.eventboxes = [] + self.rows = 0 + self.columns = 33 + self.piece_width = 30 + self.piece_height = 20 + self.unique_id = -1 + self.peer_speed = [] + self.piece_info = [] + + def set_unique_id(self, unique_id): + self.unique_id = unique_id + + def clear_pieces_store(self): + self.unique_id = -1 + self.rows = 0 + for widget in self.eventboxes: + widget.destroy() + for widget in self.progress: + widget.hide() + widget.destroy() + self.peer_speed = [] + self.eventboxes = [] + self.progress = [] + self.piece_info = [] + self.tooltips = [] + + def prepare_pieces_store(self): + state = self.manager.get_torrent_state(self.unique_id) + num_pieces = state["num_pieces"] + self.rows = int(math.ceil(num_pieces/self.columns)) + self.table.resize(self.rows, self.columns) + self.table.set_size_request((self.columns+1)*self.piece_width, (self.rows+1)*self.piece_height) + for index in xrange(num_pieces): + self.piece_info.append({'blocks_total':0, 'blocks_finished':0, 'blocks_requested':0}) + self.progress.append(gtk.ProgressBar()) + self.tooltips.append(gtk.Tooltips()) + self.eventboxes.append(gtk.EventBox()) + self.peer_speed.append("unknown") + self.progress[index].set_size_request(self.piece_width, self.piece_height) + row = index/self.columns + column = index%self.columns + self.table.attach(self.eventboxes[index], column, column+1, row, row+1, + xoptions=0, yoptions=0, xpadding=0, ypadding=0) + self.eventboxes[index].add(self.progress[index]) + if self.manager.has_piece(self.unique_id, index): + self.progress[index].set_fraction(1) + self.tooltips[index].set_tip(self.eventboxes[index], _("Piece finished")) + else: + self.tooltips[index].set_tip(self.eventboxes[index], _("Piece not started")) + self.eventboxes[index].show_all() + all_piece_info = self.manager.get_all_piece_info(self.unique_id) + for piece_index in all_piece_info: + temp_piece_info = {'blocks_total':piece_index['blocks_total'], \ + 'blocks_finished':piece_index['blocks_finished']} + self.piece_info[piece_index['piece_index']] = temp_piece_info + blocks_total = str(temp_piece_info['blocks_total']) + info_string = str(temp_piece_info['blocks_finished']) + "/" + blocks_total + " " + _("blocks finished") + "\n" \ + + _("peer speed: unknown") + if self.progress[index].get_fraction() == 0: + self.progress[index].set_fraction(0.5) + self.tooltips[index].set_tip(self.eventboxes[index], info_string) + + def handle_event(self, event): + if event['event_type'] is self.manager.constants['EVENT_PIECE_FINISHED']: + if event['unique_ID'] == self.unique_id: + self.update_pieces_store(event['piece_index'], piece_finished=True) + elif event['event_type'] is self.manager.constants['EVENT_BLOCK_DOWNLOADING']: + if event['unique_ID'] == self.unique_id: + index = event['piece_index'] + if self.piece_info[index]['blocks_total'] == 0: + self.piece_info[index] = self.manager.get_piece_info(self.unique_id, index) + temp_peer_speed = event['peer_speed'] + if temp_peer_speed == "fast": + peer_speed_msg = _("fast") + elif temp_peer_speed == "slow": + peer_speed_msg = _("slow") + elif temp_peer_speed == "medium": + peer_speed_msg = _("medium") + else: + peer_speed_msg = _("unknown") + self.peer_speed[index] = peer_speed_msg + self.update_pieces_store(index) + else: + if event['unique_ID'] == self.unique_id: + index = event['piece_index'] + if self.piece_info[index]['blocks_total'] == 0: + self.piece_info[index] = self.manager.get_piece_info(self.unique_id, index) + else: + self.piece_info[index]['blocks_finished'] += 1 + self.update_pieces_store(event['piece_index']) + + def update_pieces_store(self, index, piece_finished=False): + if piece_finished: + self.progress[index].set_fraction(1) + self.tooltips[index].set_tip(self.eventboxes[index], _("Piece finished")) + else: + temp_fraction = self.progress[index].get_fraction() + if temp_fraction == 0: + self.progress[index].set_fraction(0.5) + if temp_fraction != 1: + temp_piece_info = self.piece_info[index] + blocks_total = str(temp_piece_info['blocks_total']) + info_string = str(temp_piece_info['blocks_finished']) + "/" + blocks_total + " " + _("blocks finished") + "\n" \ + + _("peer speed: ") + self.peer_speed[index] + self.tooltips[index].set_tip(self.eventboxes[index], info_string) diff --git a/po/POTFILES.in b/po/POTFILES.in index 98a05bc79..045bf8ec4 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -30,3 +30,5 @@ plugins/BlocklistImport/ui.py plugins/BlocklistImport/text.py plugins/BlocklistImport/test.py plugins/BlocklistImport/peerguardian.py +plugins/TorrentPieces/__init__.py +plugins/TorrentPieces/tab_pieces.py diff --git a/po/deluge.pot b/po/deluge.pot index 3e848764d..5bdfa2323 100644 --- a/po/deluge.pot +++ b/po/deluge.pot @@ -1377,3 +1377,68 @@ msgstr "" #: plugins/BlocklistImport/peerguardian.py:37 msgid "Invalid version" msgstr "" + +#: plugins/TorrentPieces/__init__.py:22 +msgid "Torrent Pieces" +msgstr "" + +#: plugins/TorrentPieces/__init__.py:22 +msgid "" +"\n" +"Adds a pieces tab which gives piece by piece progress for a torrent.\n" +"Each piece is represented by a small progress bar.\n" +"\n" +"Pieces currently downloading show up as partially filled progress bars,\n" +"but this does not represent percentage done.\n" +"\n" +"More information is provided as a tooltip for each piece.\n" +"For currently downloading pieces, the tooltip contains the number\n" +"of blocks finished as well as the peer speed for that piece.\n" +"\n" +"When the plugin initializes, such as when enabling the plugin or\n" +"when a different torrent is selected, the cpu will spike. This is normal,\n" +"as initialization must get information on every piece from libtorrent,\n" +"and the cpu will normalize once all of the information is retrieved.\n" +msgstr "" + +#: plugins/TorrentPieces/__init__.py:68 +msgid "Pieces" +msgstr "" + +#: plugins/TorrentPieces/tab_pieces.py:57 +#: plugins/TorrentPieces/tab_pieces.py:105 +msgid "Piece finished" +msgstr "" + +#: plugins/TorrentPieces/tab_pieces.py:59 +msgid "Piece not started" +msgstr "" + +#: plugins/TorrentPieces/tab_pieces.py:67 +#: plugins/TorrentPieces/tab_pieces.py:113 +msgid "blocks finished" +msgstr "" + +#: plugins/TorrentPieces/tab_pieces.py:68 +msgid "peer speed: unknown" +msgstr "" + +#: plugins/TorrentPieces/tab_pieces.py:84 +msgid "fast" +msgstr "" + +#: plugins/TorrentPieces/tab_pieces.py:86 +msgid "slow" +msgstr "" + +#: plugins/TorrentPieces/tab_pieces.py:88 +msgid "medium" +msgstr "" + +#: plugins/TorrentPieces/tab_pieces.py:90 +msgid "unknown" +msgstr "" + +#: plugins/TorrentPieces/tab_pieces.py:114 +msgid "peer speed: " +msgstr "" diff --git a/src/core.py b/src/core.py index e9f344ebe..2b7a6e15d 100644 --- a/src/core.py +++ b/src/core.py @@ -317,7 +317,11 @@ class Manager: def get_pref(self, key): # Get the value from the preferences object return self.config.get(key) - + + # Check if piece is finished + def has_piece(self, unique_id, piece_index): + return deluge_core.has_piece(unique_id, piece_index) + # Dump torrent info without adding def dump_torrent_file_info(self, torrent): return deluge_core.dump_file_info(torrent) @@ -437,6 +441,12 @@ class Manager: def get_torrent_file_info(self, unique_ID): return self.get_core_torrent_file_info(unique_ID) + def get_piece_info(self, unique_ID, piece_index): + return deluge_core.get_piece_info(unique_ID, piece_index) + + def get_all_piece_info(self, unique_ID): + return deluge_core.get_all_piece_info(unique_ID) + # Queueing functions def queue_top(self, unique_ID, enforce_queue=True): @@ -571,8 +581,7 @@ class Manager: if 'unique_ID' in event and \ event['unique_ID'] not in self.unique_IDs: continue - - # Call plugins events callbacks + if event['event_type'] in self.event_callbacks: for callback in self.event_callbacks[event['event_type']]: callback(event) diff --git a/src/deluge_core.cpp b/src/deluge_core.cpp index 0e030bde4..df37a7b74 100644 --- a/src/deluge_core.cpp +++ b/src/deluge_core.cpp @@ -83,7 +83,9 @@ using namespace libtorrent; #define EVENT_TRACKER_WARNING 12 #define EVENT_OTHER 13 #define EVENT_STORAGE_MOVED 14 - +#define EVENT_PIECE_FINISHED 15 +#define EVENT_BLOCK_DOWNLOADING 16 +#define EVENT_BLOCK_FINISHED 17 #define STATE_QUEUED 0 #define STATE_CHECKING 1 @@ -181,6 +183,17 @@ long get_index_from_unique_ID(long unique_ID) RAISE_INT(DelugeError, "No such unique_ID."); } +partial_piece_info internal_get_piece_info(torrent_handle h, long piece_index) +{ + std::vector queue; + std::vector& q = queue; + h.get_download_queue(q); + for (unsigned long i = 0; i < q.size(); i++) + { + if ((long)q[i].piece_index == piece_index) return queue[i]; + } +} + torrent_info internal_get_torrent_info(std::string const& torrent_name) { std::ifstream in(torrent_name.c_str(), std::ios_base::binary); @@ -264,6 +277,10 @@ long get_peer_index(tcp::endpoint addr, std::vector const& peers) return index; } +bool internal_has_piece(std::vector const& pieces, long index) +{ + return pieces[index]; +} // The following function contains code by Christophe Dumez and Arvid Norberg void internal_add_files(torrent_info& t, @@ -359,29 +376,32 @@ static PyObject *torrent_init(PyObject *self, PyObject *args) M_ses->add_extension(&libtorrent::create_metadata_plugin); - M_constants = Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i}", - "EVENT_NULL", EVENT_NULL, - "EVENT_FINISHED", EVENT_FINISHED, - "EVENT_PEER_ERROR", EVENT_PEER_ERROR, - "EVENT_INVALID_REQUEST", EVENT_INVALID_REQUEST, - "EVENT_FILE_ERROR", EVENT_FILE_ERROR, - "EVENT_HASH_FAILED_ERROR", EVENT_HASH_FAILED_ERROR, - "EVENT_PEER_BAN_ERROR", EVENT_PEER_BAN_ERROR, - "EVENT_FASTRESUME_REJECTED_ERROR", EVENT_FASTRESUME_REJECTED_ERROR, - "EVENT_TRACKER_ANNOUNCE", EVENT_TRACKER_ANNOUNCE, - "EVENT_TRACKER_REPLY", EVENT_TRACKER_REPLY, - "EVENT_TRACKER_ALERT", EVENT_TRACKER_ALERT, - "EVENT_TRACKER_WARNING", EVENT_TRACKER_WARNING, - "EVENT_OTHER", EVENT_OTHER, - "EVENT_STORAGE_MOVED", EVENT_STORAGE_MOVED, - "STATE_QUEUED", STATE_QUEUED, - "STATE_CHECKING", STATE_CHECKING, - "STATE_CONNECTING", STATE_CONNECTING, - "STATE_DOWNLOADING_META", STATE_DOWNLOADING_META, - "STATE_DOWNLOADING", STATE_DOWNLOADING, - "STATE_FINISHED", STATE_FINISHED, - "STATE_SEEDING", STATE_SEEDING, - "STATE_ALLOCATING", STATE_ALLOCATING); + M_constants = Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i}", + "EVENT_NULL", EVENT_NULL, + "EVENT_FINISHED", EVENT_FINISHED, + "EVENT_PEER_ERROR", EVENT_PEER_ERROR, + "EVENT_INVALID_REQUEST", EVENT_INVALID_REQUEST, + "EVENT_FILE_ERROR", EVENT_FILE_ERROR, + "EVENT_HASH_FAILED_ERROR", EVENT_HASH_FAILED_ERROR, + "EVENT_PEER_BAN_ERROR", EVENT_PEER_BAN_ERROR, + "EVENT_FASTRESUME_REJECTED_ERROR", EVENT_FASTRESUME_REJECTED_ERROR, + "EVENT_TRACKER_ANNOUNCE", EVENT_TRACKER_ANNOUNCE, + "EVENT_TRACKER_REPLY", EVENT_TRACKER_REPLY, + "EVENT_TRACKER_ALERT", EVENT_TRACKER_ALERT, + "EVENT_TRACKER_WARNING", EVENT_TRACKER_WARNING, + "EVENT_OTHER", EVENT_OTHER, + "EVENT_STORAGE_MOVED", EVENT_STORAGE_MOVED, + "EVENT_PIECE_FINISHED", EVENT_PIECE_FINISHED, + "EVENT_BLOCK_DOWNLOADING", EVENT_BLOCK_DOWNLOADING, + "EVENT_BLOCK_FINISHED", EVENT_BLOCK_FINISHED, + "STATE_QUEUED", STATE_QUEUED, + "STATE_CHECKING", STATE_CHECKING, + "STATE_CONNECTING", STATE_CONNECTING, + "STATE_DOWNLOADING_META", STATE_DOWNLOADING_META, + "STATE_DOWNLOADING", STATE_DOWNLOADING, + "STATE_FINISHED", STATE_FINISHED, + "STATE_SEEDING", STATE_SEEDING, + "STATE_ALLOCATING", STATE_ALLOCATING); Py_INCREF(Py_None); return Py_None; }; @@ -733,6 +753,77 @@ static PyObject *torrent_resume(PyObject *self, PyObject *args) Py_INCREF(Py_None); return Py_None; } +static PyObject *torrent_has_piece(PyObject *self, PyObject *args) +{ + python_long unique_ID; + long piece_index; + bool has_piece; + if (!PyArg_ParseTuple(args, "ii", &unique_ID, &piece_index)) + return NULL; + + long index = get_index_from_unique_ID(unique_ID); + if (PyErr_Occurred()) + return NULL; + + torrent_status s = M_torrents->at(index).handle.status(); + has_piece = internal_has_piece(*s.pieces, piece_index); + return Py_BuildValue("b", has_piece); +} + +static PyObject *torrent_get_all_piece_info(PyObject *self, PyObject *args) +{ + python_long unique_ID; + if (!PyArg_ParseTuple(args, "i", &unique_ID)) + return NULL; + + long index = get_index_from_unique_ID(unique_ID); + if (PyErr_Occurred()) + return NULL; + + torrent_handle h = M_torrents->at(index).handle; + std::vector queue; + std::vector& q = queue; + h.get_download_queue(q); + PyObject *piece_info; + long piece_index = 0; + PyObject *ret = PyTuple_New(q.size()); + + for(unsigned long i=0; iat(index).handle; + partial_piece_info piece_info = internal_get_piece_info(h, piece_index); + int blocks_total=0, blocks_finished=0; + if(piece_info.piece_index == piece_index) + { + blocks_total = piece_info.blocks_in_piece; + blocks_finished = piece_info.finished; + } + return Py_BuildValue("{s:i,s:i}", + "blocks_total", blocks_total, + "blocks_finished", blocks_finished); +} static PyObject *torrent_get_torrent_state(PyObject *self, PyObject *args) { @@ -810,6 +901,60 @@ static PyObject *torrent_pop_event(PyObject *self, PyObject *args) if (!popped_alert) { Py_INCREF(Py_None); return Py_None; + } else if (dynamic_cast(popped_alert)) + { + torrent_handle handle = (dynamic_cast(popped_alert))->handle; + int piece_index = (dynamic_cast(popped_alert))->piece_index; + int block_index = (dynamic_cast(popped_alert))->block_index; + std::string speedmsg = (dynamic_cast(popped_alert))->peer_speedmsg; + long index = get_torrent_index(handle); + if (PyErr_Occurred()) + return NULL; + + if (handle_exists(handle)) + return Py_BuildValue("{s:i,s:i,s:i,s:i,s:s,s:s}", + "event_type", EVENT_BLOCK_DOWNLOADING, + "unique_ID", M_torrents->at(index).unique_ID, + "block_index", block_index, + "piece_index", piece_index, + "peer_speed", speedmsg.c_str(), + "message", a->msg().c_str()); + else + { Py_INCREF(Py_None); return Py_None; } + } else if (dynamic_cast(popped_alert)) + { + torrent_handle handle = (dynamic_cast(popped_alert))->handle; + int piece_index = (dynamic_cast(popped_alert))->piece_index; + int block_index = (dynamic_cast(popped_alert))->block_index; + long index = get_torrent_index(handle); + if (PyErr_Occurred()) + return NULL; + + if (handle_exists(handle)) + return Py_BuildValue("{s:i,s:i,s:i,s:i,s:s}", + "event_type", EVENT_BLOCK_FINISHED, + "unique_ID", M_torrents->at(index).unique_ID, + "block_index", block_index, + "piece_index", piece_index, + "message", a->msg().c_str()); + else + { Py_INCREF(Py_None); return Py_None; } + } else if (dynamic_cast(popped_alert)) + { + torrent_handle handle = (dynamic_cast(popped_alert))->handle; + int piece_index = (dynamic_cast(popped_alert))->piece_index; + long index = get_torrent_index(handle); + if (PyErr_Occurred()) + return NULL; + + if (handle_exists(handle)) + return Py_BuildValue("{s:i,s:i,s:i,s:s}", + "event_type", EVENT_PIECE_FINISHED, + "unique_ID", M_torrents->at(index).unique_ID, + "piece_index", piece_index, + "message", a->msg().c_str()); + else + { Py_INCREF(Py_None); return Py_None; } } else if (dynamic_cast(popped_alert)) { torrent_handle handle = (dynamic_cast(popped_alert))->handle; @@ -1719,6 +1864,9 @@ static PyMethodDef deluge_core_methods[] = {"prioritize_first_last_pieces", torrent_prioritize_first_last_pieces, METH_VARARGS, "."}, {"set_priv", torrent_set_priv, METH_VARARGS, "."}, {"test_duplicate", torrent_test_duplicate, METH_VARARGS, "."}, + {"has_piece", torrent_has_piece, METH_VARARGS, "."}, + {"get_piece_info", torrent_get_piece_info, METH_VARARGS, "."}, + {"get_all_piece_info", torrent_get_all_piece_info, METH_VARARGS, "."}, {NULL} };