diff --git a/deluge/core/rpcserver.py b/deluge/core/rpcserver.py index 93315d4a7..b9b417e75 100644 --- a/deluge/core/rpcserver.py +++ b/deluge/core/rpcserver.py @@ -427,14 +427,14 @@ class RPCServer(component.Component): def deregister_object(self, obj): """ Deregisters an objects exported rpc methods. - + :param obj: the object that was previously registered - + """ for key, value in self.factory.methods.items(): if value.im_self == obj: del self.factory.methods[key] - + def get_object_method(self, name): """ Returns a registered method. @@ -535,6 +535,29 @@ class RPCServer(component.Component): (RPC_EVENT, event.name, event.args) ) + def emit_event_for_session_id(self, session_id, event): + """ + Emits the event to specified session_id. + + :param session_id: the event to emit + :type session_id: int + :param event: the event to emit + :type event: :class:`deluge.event.DelugeEvent` + """ + if not self.is_session_valid(session_id): + log.debug("Session ID %s is not valid. Not sending event \"%s\".", session_id, event.name) + return + if session_id not in self.factory.interested_events: + log.debug("Session ID %s is not interested in any events. Not sending event \"%s\".", session_id, event.name) + return + if event.name not in self.factory.interested_events[session_id]: + log.debug("Session ID %s is not interested in event \"%s\". Not sending it.", session_id, event.name) + return + log.debug("Sending event \"%s\" with args \"%s\" to session id \"%s\".", + event.name, event.args, session_id) + self.factory.session_protocols[session_id].sendData((RPC_EVENT, event.name, event.args)) + + def check_ssl_keys(): """ Check for SSL cert/key and create them if necessary diff --git a/deluge/event.py b/deluge/event.py index 23027673f..4a1d644e4 100644 --- a/deluge/event.py +++ b/deluge/event.py @@ -197,6 +197,13 @@ class TorrentFileCompletedEvent(DelugeEvent): """ self._args = [torrent_id, index] +class CreateTorrentProgressEvent(DelugeEvent): + """ + Emitted when creating a torrent file remotely. + """ + def __init__(self, piece_count, num_pieces): + self._args = [piece_count, num_pieces] + class NewVersionAvailableEvent(DelugeEvent): """ Emitted when a more recent version of Deluge is available. diff --git a/deluge/metafile.py b/deluge/metafile.py index 8e3549a03..9617f0277 100644 --- a/deluge/metafile.py +++ b/deluge/metafile.py @@ -16,14 +16,15 @@ # Written by Bram Cohen # Modifications for use in Deluge by Andrew Resch 2008 -import os import os.path import sys import time import logging from hashlib import sha1 as sha +import deluge.component as component from deluge.bencode import bencode +from deluge.event import CreateTorrentProgressEvent log = logging.getLogger(__name__) @@ -57,10 +58,18 @@ def decode_from_filesystem(path): def dummy(*v): pass -def make_meta_file(path, url, piece_length, progress=dummy, - title=None, comment=None, safe=None, content_type=None, - target=None, webseeds=None, name=None, private=False, - created_by=None, trackers=None): +class RemoteFileProgress(object): + def __init__(self, session_id): + self.session_id = session_id + + def __call__(self, piece_count, num_pieces): + component.get("RPCServer").emit_event_for_session_id( + self.session_id, CreateTorrentProgressEvent(piece_count, num_pieces) + ) + +def make_meta_file(path, url, piece_length, progress=None, title=None, comment=None, + safe=None, content_type=None, target=None, webseeds=None, name=None, + private=False, created_by=None, trackers=None): data = {'creation date': int(gmtime())} if url: data['announce'] = url.strip() @@ -72,6 +81,14 @@ def make_meta_file(path, url, piece_length, progress=dummy, f = os.path.join(a, b + '.torrent') else: f = target + + if progress is None: + session_id = component.get("RPCServer").get_session_id() + if not session_id: + progress = dummy + else: + progress = RemoteFileProgress(component.get("RPCServer").get_session_id()) + info = makeinfo(path, piece_length, progress, name, content_type, private) #check_info(info) @@ -118,18 +135,18 @@ def calcsize(path): def makeinfo(path, piece_length, progress, name = None, content_type = None, private=False): # HEREDAVE. If path is directory, - # how do we assign content type? + # how do we assign content type? def to_utf8(name): if isinstance(name, unicode): u = name else: try: u = decode_from_filesystem(name) - except Exception, e: + except Exception: raise Exception('Could not convert file/directory name %r to ' - 'Unicode. Either the assumed filesystem ' - 'encoding "%s" is wrong or the filename contains ' - 'illegal bytes.' % (name, get_filesystem_encoding())) + 'Unicode. Either the assumed filesystem ' + 'encoding "%s" is wrong or the filename contains ' + 'illegal bytes.' % (name, get_filesystem_encoding())) if u.translate(noncharacter_translate) != u: raise Exception('File/directory name "%s" contains reserved ' @@ -181,6 +198,7 @@ def makeinfo(path, piece_length, progress, name = None, h.close() if done > 0: pieces.append(sh.digest()) + piece_count += 1 progress(piece_count, num_pieces) if name is not None: diff --git a/deluge/ui/gtkui/createtorrentdialog.py b/deluge/ui/gtkui/createtorrentdialog.py index 6ee06ba64..8f71f3977 100644 --- a/deluge/ui/gtkui/createtorrentdialog.py +++ b/deluge/ui/gtkui/createtorrentdialog.py @@ -241,13 +241,12 @@ class CreateTorrentDialog: return is_remote = self.files_treestore[0][1] == gtk.STOCK_NETWORK + torrent_filename = "%s.torrent" % os.path.split(self.files_treestore[0][0].rstrip('/'))[-1] if is_remote: # This is a remote path dialog = self.builder.get_object("remote_save_dialog") dialog.set_transient_for(self.dialog) - self.builder.get_object("entry_save_path").set_text( - os.path.split(self.files_treestore[0][0])[-1] + ".torrent" - ) + self.builder.get_object("entry_save_path").set_text(torrent_filename) response = dialog.run() if response == gtk.RESPONSE_OK: result = self.builder.get_object("entry_save_path").get_text() @@ -276,7 +275,7 @@ class CreateTorrentDialog: file_filter.add_pattern("*") chooser.add_filter(file_filter) - chooser.set_current_name(os.path.split(self.files_treestore[0][0])[-1] + ".torrent") + chooser.set_current_name(torrent_filename) # Run the dialog response = chooser.run() @@ -327,6 +326,18 @@ class CreateTorrentDialog: add_to_session = self.builder.get_object("chk_add_to_session").get_active() if is_remote: + def torrent_created(): + self.builder.get_object("progress_dialog").hide_all() + client.deregister_event_handler("CreateTorrentProgressEvent", on_create_torrent_progress_event) + + def on_create_torrent_progress_event(piece_count, num_pieces): + self._on_create_torrent_progress(piece_count, num_pieces) + if piece_count == num_pieces: + from twisted.internet import reactor + reactor.callLater(0.5, torrent_created) + + client.register_event_handler("CreateTorrentProgressEvent", on_create_torrent_progress_event) + client.core.create_torrent( path, tracker, @@ -340,9 +351,6 @@ class CreateTorrentDialog: add_to_session) else: - # Setup progress dialog - self.builder.get_object("progress_dialog").set_transient_for(component.get("MainWindow").window) - self.builder.get_object("progress_dialog").show_all() def hide_progress(result): self.builder.get_object("progress_dialog").hide_all() @@ -360,6 +368,10 @@ class CreateTorrentDialog: trackers, add_to_session).addCallback(hide_progress) + # Setup progress dialog + self.builder.get_object("progress_dialog").set_transient_for(component.get("MainWindow").window) + self.builder.get_object("progress_dialog").show_all() + self.dialog.destroy() def create_torrent(self, path, tracker, piece_length, progress, comment, target, @@ -385,10 +397,17 @@ class CreateTorrentDialog: def _on_create_torrent_progress(self, value, num_pieces): percent = float(value)/float(num_pieces) - pbar = self.builder.get_object("progressbar") - pbar.set_text("%.2f%%" % (percent*100)) - if percent >= 0 and percent <= 1.0: + + def update_pbar_with_gobject(percent): + pbar = self.builder.get_object("progressbar") + pbar.set_text("%.2f%%" % (percent*100)) pbar.set_fraction(percent) + return False + + if percent >= 0 and percent <= 1.0: + # Make sure there are no threads race conditions that can + # crash the UI while updating it. + gobject.idle_add(update_pbar_with_gobject, percent) def _on_button_up_clicked(self, widget): log.debug("_on_button_up_clicked")