Create torrent remotely progress information.
Support progress information when creating torrents remotely. For this to be possible, a method was added to the `RPCServer`, `emit_event_for_session_id()`, which does exactly what is says. This is needed because the event created, `CreateTorrentProgressEvent` needs to be addressed to a single session id, not all session ids interested in that event. Fixed a bug that apparently was not found yet. When creating torrents locally, we defer that task to a thread. Since this thread updates UI widgets, namely the progress bar info and since we can't guarantee that it's the main thread, updating the widgets must be done by calling `gobject.iddle_add()`.
This commit is contained in:
parent
12d0e9574b
commit
dbad4684db
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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")
|
||||
|
|
Loading…
Reference in New Issue