Updates to the Connection Manager.

Updates to TorrentManager.
This commit is contained in:
Andrew Resch 2007-11-09 12:08:15 +00:00
parent a043858f2e
commit 7d9a30a545
4 changed files with 177 additions and 106 deletions

1
TODO
View File

@ -18,4 +18,5 @@
* Add queue preferences tab * Add queue preferences tab
* Add classic/normal mode to preferences * Add classic/normal mode to preferences
* Implement 'Classic' mode * Implement 'Classic' mode
* Add remove torrent dialog and ability to remove data

View File

@ -136,16 +136,7 @@ class TorrentManager:
filedump = "".join(chr(b) for b in filedump) filedump = "".join(chr(b) for b in filedump)
else: else:
# Get the data from the file # Get the data from the file
try: filedump = self.load_torrent(filename)
log.debug("Attempting to open %s for add.", filename)
_file = open(
os.path.join(
self.config["torrentfiles_location"], filename), "rb")
filedump = _file.read()
_file.close()
except IOError:
log.warning("Unable to open %s", filename)
return None
# Attempt to load fastresume data # Attempt to load fastresume data
try: try:
@ -156,12 +147,10 @@ class TorrentManager:
"rb") "rb")
fastresume = lt.bdecode(_file.read()) fastresume = lt.bdecode(_file.read())
_file.close() _file.close()
except IOError: except IOError, e:
log.debug("Unable to load .fastresume..") log.debug("Unable to load .fastresume: %s", e)
fastresume = None fastresume = None
# Bdecode the filedata
torrent_filedump = lt.bdecode(filedump)
handle = None handle = None
# Make sure we have a valid download_location # Make sure we have a valid download_location
@ -180,13 +169,13 @@ class TorrentManager:
try: try:
handle = self.session.add_torrent( handle = self.session.add_torrent(
lt.torrent_info(torrent_filedump), lt.torrent_info(filedump),
str(save_path), str(save_path),
resume_data=fastresume, resume_data=fastresume,
storage_mode=storage_mode, storage_mode=storage_mode,
paused=paused) paused=paused)
except RuntimeError: except RuntimeError, e:
log.warning("Error adding torrent") log.warning("Error adding torrent: %s", e)
if not handle or not handle.is_valid(): if not handle or not handle.is_valid():
# The torrent was not added to the session # The torrent was not added to the session
@ -202,7 +191,16 @@ class TorrentManager:
# Set per-torrent limits # Set per-torrent limits
handle.set_max_connections(self.max_connections) handle.set_max_connections(self.max_connections)
handle.set_max_uploads(self.max_uploads) handle.set_max_uploads(self.max_uploads)
# Save the torrent file
self.save_torrent(filename, filedump)
# Save the session state
self.save_state()
return torrent.torrent_id
def save_torrent(self, filename, filedump):
"""Saves a torrent file"""
log.debug("Attempting to save torrent file: %s", filename) log.debug("Attempting to save torrent file: %s", filename)
# Test if the torrentfiles_location is accessible # Test if the torrentfiles_location is accessible
if os.access( if os.access(
@ -211,25 +209,37 @@ class TorrentManager:
# The directory probably doesn't exist, so lets create it # The directory probably doesn't exist, so lets create it
try: try:
os.makedirs(os.path.join(self.config["torrentfiles_location"])) os.makedirs(os.path.join(self.config["torrentfiles_location"]))
except IOError: except IOError, e:
log.warning("Unable to create torrent files directory..") log.warning("Unable to create torrent files directory: %s", e)
# Write the .torrent file to the torrent directory # Write the .torrent file to the torrent directory
try: try:
save_file = open(os.path.join(self.config["torrentfiles_location"], save_file = open(os.path.join(self.config["torrentfiles_location"],
filename), filename),
"wb") "wb")
save_file.write(lt.bencode(torrent_filedump)) save_file.write(lt.bencode(filedump))
save_file.close() save_file.close()
except IOError: except IOError, e:
log.warning("Unable to save torrent file: %s", filename) log.warning("Unable to save torrent file: %s", e)
log.debug("Torrent %s added.", handle.info_hash())
# Save the session state def load_torrent(self, filename):
self.save_state() """Load a torrent file and return it's torrent info"""
return torrent.torrent_id filedump = None
# Get the torrent data from the torrent file
try:
log.debug("Attempting to open %s for add.", filename)
_file = open(
os.path.join(
self.config["torrentfiles_location"], filename),
"rb")
filedump = lt.bdecode(_file.read())
_file.close()
except IOError, e:
log.warning("Unable to open %s: e", filename, e)
return False
return filedump
def remove(self, torrent_id): def remove(self, torrent_id):
"""Remove a torrent from the manager""" """Remove a torrent from the manager"""
try: try:
@ -302,67 +312,52 @@ class TorrentManager:
return False return False
return True return True
def force_recheck(self, torrent_id): def force_recheck(self, torrent_id):
"""Forces a re-check of the torrent's data""" """Forces a re-check of the torrent's data"""
log.debug("Doing a forced recheck on %s", torrent_id) log.debug("Doing a forced recheck on %s", torrent_id)
torrent = self.torrents[torrent_id]
paused = self.torrents[torrent_id].handle.status().paused paused = self.torrents[torrent_id].handle.status().paused
torrent_info = None
### Check for .torrent file prior to removing and make a copy if needed ### Check for .torrent file prior to removing and make a copy if needed
### FIXME if os.access(os.path.join(self.config["torrentfiles_location"] +\
"/" + torrent.filename), os.F_OK) is False:
torrent_info = torrent.handle.get_torrent_info().create_torrent()
self.save_torrent(torrent.filename, torrent_info)
# We start by removing it from the lt session
try: try:
# We start by removing it from the lt session self.session.remove_torrent(torrent.handle, 0)
self.session.remove_torrent(self.torrents[torrent_id].handle, 0)
except (RuntimeError, KeyError), e: except (RuntimeError, KeyError), e:
log.warning("Error removing torrent: %s", e) log.warning("Error removing torrent: %s", e)
return False return False
# Remove the fastresume file if there # Remove the fastresume file if there
self.delete_fastresume(torrent_id) self.delete_fastresume(torrent_id)
# Get the torrent data from the torrent file # Load the torrent info from file if needed
filename = self.torrents[torrent_id].filename if torrent_info == None:
try: torrent_info = self.load_torrent(torrent.filename)
log.debug("Attempting to open %s for add.", filename)
_file = open(
os.path.join(
self.config["torrentfiles_location"], filename), "rb")
filedump = _file.read()
_file.close()
except IOError, e:
log.warning("Unable to open %s: e", filename, e)
return False
# Bdecode the filedata
torrent_filedump = lt.bdecode(filedump)
handle = None
# Next we re-add the torrent # Next we re-add the torrent
# Make sure we have a valid download_location
if self.torrents[torrent_id].save_path is None:
self.torrents[torrent_id].save_path = \
self.config["download_location"]
# Make sure we are adding it with the correct allocation method.
if self.torrents[torrent_id].compact is None:
self.torrents[torrent_id].compact = \
self.config["compact_allocation"]
# Set the right storage_mode # Set the right storage_mode
if self.torrents[torrent_id].compact: if torrent.compact:
storage_mode = lt.storage_mode_t(1) storage_mode = lt.storage_mode_t(1)
else: else:
storage_mode = lt.storage_mode_t(2) storage_mode = lt.storage_mode_t(2)
# Add the torrent to the lt session
try: try:
handle = self.session.add_torrent( torrent.handle = self.session.add_torrent(
lt.torrent_info(torrent_filedump), lt.torrent_info(torrent_info),
str(self.torrents[torrent_id].save_path), str(torrent.save_path),
storage_mode=storage_mode, storage_mode=storage_mode,
paused=paused) paused=paused)
except RuntimeError, e: except RuntimeError, e:
log.warning("Error adding torrent: %s", e) log.warning("Error adding torrent: %s", e)
if not handle or not handle.is_valid(): if not torrent.handle or not torrent.handle.is_valid():
# The torrent was not added to the session # The torrent was not added to the session
return False return False

View File

@ -193,10 +193,30 @@ class ConnectionManager(component.Component):
self.liststore.foreach(update_row) self.liststore.foreach(update_row)
# Update the buttons # Update the buttons
self.update_buttons() self.update_buttons()
# See if there is any row selected
paths = self.hostlist.get_selection().get_selected_rows()[1]
if len(paths) < 1:
# And there is at least 1 row
if self.liststore.iter_n_children(None) > 0:
# Then select the first row
self.hostlist.get_selection().select_iter(self.liststore.get_iter_first())
return True return True
def update_buttons(self): def update_buttons(self):
"""Updates the buttons based on selection""" """Updates the buttons based on selection"""
if self.liststore.iter_n_children(None) < 1:
# There is nothing in the list
self.glade.get_widget("button_startdaemon").set_sensitive(True)
self.glade.get_widget("button_connect").set_sensitive(False)
self.glade.get_widget("button_removehost").set_sensitive(False)
self.glade.get_widget("image_startdaemon").set_from_stock(
gtk.STOCK_EXECUTE, gtk.ICON_SIZE_MENU)
self.glade.get_widget("label_startdaemon").set_text(
"_Start Daemon")
self.glade.get_widget("label_startdaemon").set_use_underline(
True)
# Get the selected row's URI # Get the selected row's URI
paths = self.hostlist.get_selection().get_selected_rows()[1] paths = self.hostlist.get_selection().get_selected_rows()[1]
# If nothing is selected, just return # If nothing is selected, just return
@ -213,33 +233,46 @@ class ConnectionManager(component.Component):
# Make actual URI string # Make actual URI string
uri = "http://" + uri uri = "http://" + uri
# Make sure buttons are sensitive at start
self.glade.get_widget("button_startdaemon").set_sensitive(True)
self.glade.get_widget("button_connect").set_sensitive(True)
self.glade.get_widget("button_removehost").set_sensitive(True)
# See if this is the currently connected URI # See if this is the currently connected URI
if status == HOSTLIST_STATUS.index("Connected"): if status == HOSTLIST_STATUS.index("Connected"):
# Display a disconnect button if we're connected to this host # Display a disconnect button if we're connected to this host
self.glade.get_widget("button_connect").set_label("gtk-disconnect") self.glade.get_widget("button_connect").set_label("gtk-disconnect")
self.glade.get_widget("button_removehost").set_sensitive(False)
else: else:
self.glade.get_widget("button_connect").set_label("gtk-connect") self.glade.get_widget("button_connect").set_label("gtk-connect")
if status == HOSTLIST_STATUS.index("Offline") and not localhost:
self.glade.get_widget("button_connect").set_sensitive(False)
# Check to see if the host is online
if status == HOSTLIST_STATUS.index("Connected") \
or status == HOSTLIST_STATUS.index("Online"):
self.glade.get_widget("image_startdaemon").set_from_stock(
gtk.STOCK_STOP, gtk.ICON_SIZE_MENU)
self.glade.get_widget("label_startdaemon").set_text(
"_Stop Daemon")
# Update the start daemon button if the selected host is localhost # Update the start daemon button if the selected host is localhost
if localhost: if localhost and status == HOSTLIST_STATUS.index("Offline"):
# Check to see if the host is online # The localhost is not online
if status == HOSTLIST_STATUS.index("Connected") \ self.glade.get_widget("image_startdaemon").set_from_stock(
or status == HOSTLIST_STATUS.index("Online"): gtk.STOCK_EXECUTE, gtk.ICON_SIZE_MENU)
self.glade.get_widget("image_startdaemon").set_from_stock( self.glade.get_widget("label_startdaemon").set_text(
gtk.STOCK_STOP, gtk.ICON_SIZE_MENU) "_Start Daemon")
self.glade.get_widget("label_startdaemon").set_text(
"_Stop local daemon") if not localhost:
else: # An offline host
# The localhost is not online self.glade.get_widget("button_startdaemon").set_sensitive(False)
self.glade.get_widget("image_startdaemon").set_from_stock(
gtk.STOCK_EXECUTE, gtk.ICON_SIZE_MENU) # Make sure label is displayed correctly using mnemonics
self.glade.get_widget("label_startdaemon").set_text( self.glade.get_widget("label_startdaemon").set_use_underline(
"_Start local daemon") True)
# Make sure label is displayed correctly using mnemonics
self.glade.get_widget("label_startdaemon").set_use_underline(
True)
def save(self): def save(self):
"""Save the current host list to file""" """Save the current host list to file"""
def append_row(model=None, path=None, row=None, columns=None): def append_row(model=None, path=None, row=None, columns=None):
@ -279,27 +312,29 @@ class ConnectionManager(component.Component):
response = dialog.run() response = dialog.run()
if response == 1: if response == 1:
# We add the host # We add the host
hostname = hostname_entry.get_text() self.add_host(hostname_entry.get_text(),
if hostname.startswith("http://"): port_spinbutton.get_value_as_int())
hostname = hostname[7:]
# Check to make sure the hostname is at least 1 character long dialog.hide()
if len(hostname) < 1:
dialog.hide() def add_host(self, hostname, port):
return """Adds the host to the list"""
if hostname.startswith("http://"):
# Get the port and concatenate the hostname string hostname = hostname[7:]
port = port_spinbutton.get_value_as_int()
hostname = hostname + ":" + str(port)
row = self.liststore.append()
self.liststore.set_value(row, HOSTLIST_COL_URI, hostname)
# Save the host list to file
self.save()
# Update the status of the hosts
self._update()
dialog.hide()
# Check to make sure the hostname is at least 1 character long
if len(hostname) < 1:
return
# Get the port and concatenate the hostname string
hostname = hostname + ":" + str(port)
row = self.liststore.append()
self.liststore.set_value(row, HOSTLIST_COL_URI, hostname)
# Save the host list to file
self.save()
# Update the status of the hosts
self._update()
def on_button_removehost_clicked(self, widget): def on_button_removehost_clicked(self, widget):
log.debug("on_button_removehost_clicked") log.debug("on_button_removehost_clicked")
# Get the selected rows # Get the selected rows
@ -307,12 +342,24 @@ class ConnectionManager(component.Component):
for path in paths: for path in paths:
self.liststore.remove(self.liststore.get_iter(path)) self.liststore.remove(self.liststore.get_iter(path))
# Update the hostlist
self._update()
# Save the host list # Save the host list
self.save() self.save()
def on_button_startdaemon_clicked(self, widget): def on_button_startdaemon_clicked(self, widget):
log.debug("on_button_startdaemon_clicked") log.debug("on_button_startdaemon_clicked")
if self.liststore.iter_n_children(None) < 1:
# There is nothing in the list, so lets create a localhost entry
self.add_host("localhost", 58846)
# ..and start the daemon.
self.start_localhost(58846)
return
paths = self.hostlist.get_selection().get_selected_rows()[1] paths = self.hostlist.get_selection().get_selected_rows()[1]
if len(paths) < 1:
return
row = self.liststore.get_iter(paths[0]) row = self.liststore.get_iter(paths[0])
status = self.liststore.get_value(row, HOSTLIST_COL_STATUS) status = self.liststore.get_value(row, HOSTLIST_COL_STATUS)
uri = self.liststore.get_value(row, HOSTLIST_COL_URI) uri = self.liststore.get_value(row, HOSTLIST_COL_URI)
@ -327,10 +374,15 @@ class ConnectionManager(component.Component):
# Update display to show change # Update display to show change
self.update() self.update()
elif HOSTLIST_STATUS[status] == "Offline": elif HOSTLIST_STATUS[status] == "Offline":
log.debug("Start localhost daemon..") self.start_localhost(port)
# Spawn a local daemon
os.popen("deluged -p %s" % port)
def start_localhost(self, port):
"""Starts a localhost daemon"""
port = str(port)
log.info("Starting localhost:%s daemon..", port)
# Spawn a local daemon
os.popen("deluged -p %s" % port)
def on_button_close_clicked(self, widget): def on_button_close_clicked(self, widget):
log.debug("on_button_close_clicked") log.debug("on_button_close_clicked")
self.hide() self.hide()
@ -341,6 +393,12 @@ class ConnectionManager(component.Component):
row = self.liststore.get_iter(paths[0]) row = self.liststore.get_iter(paths[0])
status = self.liststore.get_value(row, HOSTLIST_COL_STATUS) status = self.liststore.get_value(row, HOSTLIST_COL_STATUS)
uri = self.liststore.get_value(row, HOSTLIST_COL_URI) uri = self.liststore.get_value(row, HOSTLIST_COL_URI)
# Determine if this is a localhost
localhost = False
port = uri.split(":")[1]
if uri.split(":")[0] == "localhost":
localhost = True
uri = "http://" + uri uri = "http://" + uri
if status == HOSTLIST_STATUS.index("Connected"): if status == HOSTLIST_STATUS.index("Connected"):
# If we are connected to this host, then we will disconnect. # If we are connected to this host, then we will disconnect.
@ -352,8 +410,19 @@ class ConnectionManager(component.Component):
# column information because it can be up to 5 seconds out of sync. # column information because it can be up to 5 seconds out of sync.
if not self.test_online_status(uri): if not self.test_online_status(uri):
log.warning("Host does not appear to be online..") log.warning("Host does not appear to be online..")
# If this is an offline localhost.. lets start it and connect
if localhost:
self.start_localhost(port)
# We need to wait for the host to start before connecting
while not self.test_online_status(uri):
sleep(10)
client.set_core_uri(uri)
self._update()
self.hide()
# Update the list to show proper status # Update the list to show proper status
self._update() self._update()
return return
# Status is OK, so lets change to this host # Status is OK, so lets change to this host

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd"> <!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
<!--Generated with glade3 3.2.2 on Thu Oct 25 01:07:45 2007 by andrew@fragment--> <!--Generated with glade3 3.2.2 on Fri Nov 9 03:49:00 2007 by andrew@fragment-->
<glade-interface> <glade-interface>
<widget class="GtkDialog" id="connection_manager"> <widget class="GtkDialog" id="connection_manager">
<property name="has_focus">True</property> <property name="has_focus">True</property>
@ -270,6 +270,10 @@
<property name="response_id">0</property> <property name="response_id">0</property>
<signal name="clicked" handler="on_button_close_clicked"/> <signal name="clicked" handler="on_button_close_clicked"/>
</widget> </widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child> </child>
<child> <child>
<widget class="GtkButton" id="button_connect"> <widget class="GtkButton" id="button_connect">
@ -283,6 +287,8 @@
<signal name="clicked" handler="on_button_connect_clicked"/> <signal name="clicked" handler="on_button_connect_clicked"/>
</widget> </widget>
<packing> <packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property> <property name="position">1</property>
</packing> </packing>
</child> </child>