mirror of
https://github.com/codex-storage/deluge.git
synced 2025-01-12 12:34:43 +00:00
Re-org Core and start using RPCServer
This commit is contained in:
parent
8ed2d25ce5
commit
04d14df8c7
@ -32,7 +32,7 @@ COMPONENT_STATE = [
|
||||
"Paused"
|
||||
]
|
||||
|
||||
class Component:
|
||||
class Component(object):
|
||||
def __init__(self, name, interval=1000, depend=None):
|
||||
# Register with the ComponentRegistry
|
||||
register(name, self, depend)
|
||||
|
@ -42,6 +42,7 @@ class AlertManager(component.Component):
|
||||
log.debug("AlertManager initialized..")
|
||||
component.Component.__init__(self, "AlertManager", interval=50)
|
||||
self.session = session
|
||||
|
||||
self.session.set_alert_mask(
|
||||
lt.alert.category_t.error_notification |
|
||||
lt.alert.category_t.port_mapping_notification |
|
||||
|
@ -22,22 +22,14 @@
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
|
||||
|
||||
import gettext
|
||||
import locale
|
||||
import pkg_resources
|
||||
import sys
|
||||
import glob
|
||||
import shutil
|
||||
import os
|
||||
import os.path
|
||||
import signal
|
||||
import deluge.SimpleXMLRPCServer as SimpleXMLRPCServer
|
||||
from SocketServer import ThreadingMixIn
|
||||
import deluge.xmlrpclib as xmlrpclib
|
||||
import gobject
|
||||
import threading
|
||||
import socket
|
||||
import pkg_resources
|
||||
|
||||
import gobject
|
||||
|
||||
try:
|
||||
import deluge.libtorrent as lt
|
||||
@ -57,7 +49,7 @@ from deluge.core.filtermanager import FilterManager
|
||||
from deluge.core.preferencesmanager import PreferencesManager
|
||||
from deluge.core.autoadd import AutoAdd
|
||||
from deluge.core.authmanager import AuthManager
|
||||
from deluge.core.rpcserver import BasicAuthXMLRPCRequestHandler
|
||||
from deluge.core.rpcserver import BasicAuthXMLRPCRequestHandler, export
|
||||
|
||||
from deluge.log import LOG as log
|
||||
|
||||
@ -71,104 +63,23 @@ STATUS_KEYS = ['active_time', 'compact', 'distributed_copies', 'download_payload
|
||||
'total_seeds', 'total_size', 'total_uploaded', 'total_wanted', 'tracker', 'tracker_host',
|
||||
'tracker_status', 'trackers', 'upload_payload_rate']
|
||||
|
||||
class Core(
|
||||
ThreadingMixIn,
|
||||
SimpleXMLRPCServer.SimpleXMLRPCServer,
|
||||
component.Component):
|
||||
def __init__(self, port):
|
||||
class Core(component.Component):
|
||||
def __init__(self):
|
||||
log.debug("Core init..")
|
||||
component.Component.__init__(self, "Core")
|
||||
self.client_address = None
|
||||
|
||||
self.prefmanager = PreferencesManager()
|
||||
|
||||
# Get config
|
||||
self.config = deluge.configmanager.ConfigManager("core.conf")
|
||||
|
||||
if port == None:
|
||||
port = self.config["daemon_port"]
|
||||
|
||||
if self.config["allow_remote"]:
|
||||
hostname = ""
|
||||
else:
|
||||
hostname = "127.0.0.1"
|
||||
|
||||
# Setup the xmlrpc server
|
||||
try:
|
||||
log.info("Starting XMLRPC server on port %s", port)
|
||||
SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(
|
||||
self, (hostname, port),
|
||||
requestHandler=BasicAuthXMLRPCRequestHandler,
|
||||
logRequests=False, allow_none=True)
|
||||
except:
|
||||
log.info("Daemon already running or port not available..")
|
||||
sys.exit(0)
|
||||
|
||||
self.register_multicall_functions()
|
||||
|
||||
# Register all export_* functions
|
||||
for func in dir(self):
|
||||
if func.startswith("export_"):
|
||||
self.register_function(getattr(self, "%s" % func), func[7:])
|
||||
|
||||
self.register_introspection_functions()
|
||||
|
||||
# Initialize gettext
|
||||
try:
|
||||
locale.setlocale(locale.LC_ALL, '')
|
||||
if hasattr(locale, "bindtextdomain"):
|
||||
locale.bindtextdomain("deluge", pkg_resources.resource_filename("deluge", "i18n"))
|
||||
if hasattr(locale, "textdomain"):
|
||||
locale.textdomain("deluge")
|
||||
gettext.bindtextdomain("deluge", pkg_resources.resource_filename("deluge", "i18n"))
|
||||
gettext.textdomain("deluge")
|
||||
gettext.install("deluge", pkg_resources.resource_filename("deluge", "i18n"))
|
||||
except Exception, e:
|
||||
log.error("Unable to initialize gettext/locale: %s", e)
|
||||
|
||||
# Setup signals
|
||||
signal.signal(signal.SIGINT, self._shutdown)
|
||||
signal.signal(signal.SIGTERM, self._shutdown)
|
||||
if not deluge.common.windows_check():
|
||||
signal.signal(signal.SIGHUP, self._shutdown)
|
||||
else:
|
||||
from win32api import SetConsoleCtrlHandler
|
||||
from win32con import CTRL_CLOSE_EVENT
|
||||
from win32con import CTRL_SHUTDOWN_EVENT
|
||||
result = 0
|
||||
def win_handler(ctrl_type):
|
||||
log.debug("ctrl_type: %s", ctrl_type)
|
||||
if ctrl_type == CTRL_CLOSE_EVENT or ctrl_type == CTRL_SHUTDOWN_EVENT:
|
||||
self._shutdown()
|
||||
result = 1
|
||||
return result
|
||||
SetConsoleCtrlHandler(win_handler)
|
||||
|
||||
def get_request(self):
|
||||
"""Get the request and client address from the socket.
|
||||
We override this so that we can get the ip address of the client.
|
||||
"""
|
||||
request, client_address = self.socket.accept()
|
||||
self.client_address = client_address[0]
|
||||
return (request, client_address)
|
||||
|
||||
def run(self):
|
||||
"""Starts the core"""
|
||||
|
||||
# Create the client fingerprint
|
||||
version = []
|
||||
for value in deluge.common.get_version().split("."):
|
||||
version.append(int(value.split("-")[0]))
|
||||
while len(version) < 4:
|
||||
version.append(0)
|
||||
fingerprint = lt.fingerprint("DE", *version)
|
||||
|
||||
# Start the libtorrent session
|
||||
log.debug("Starting libtorrent session..")
|
||||
self.session = lt.session(fingerprint, flags=0)
|
||||
|
||||
# Create the client fingerprint
|
||||
version = [int(value.split("-")[0]) for value in deluge.common.get_version().split(".")]
|
||||
while len(version) < 4:
|
||||
version.append(0)
|
||||
|
||||
self.session = lt.session(lt.fingerprint("DE", *version), flags=0)
|
||||
|
||||
# Load the session state if available
|
||||
self.load_session_state()
|
||||
self.__load_session_state()
|
||||
|
||||
# Load the GeoIP DB for country look-ups if available
|
||||
geoip_db = pkg_resources.resource_filename("deluge", os.path.join("data", "GeoIP.dat"))
|
||||
@ -180,105 +91,56 @@ class Core(
|
||||
self.settings.user_agent = "Deluge %s" % deluge.common.get_version()
|
||||
|
||||
# Set session settings
|
||||
self.settings.lazy_bitfields = 1
|
||||
self.settings.send_redundant_have = True
|
||||
self.session.set_settings(self.settings)
|
||||
|
||||
# Create an ip filter
|
||||
self.ip_filter = lt.ip_filter()
|
||||
|
||||
# This keeps track of the timer to set the ip filter.. We do this a few
|
||||
# seconds aftering adding a rule so that 'batch' adding of rules isn't slow.
|
||||
self._set_ip_filter_timer = None
|
||||
self.__set_ip_filter_timer = None
|
||||
|
||||
# Load metadata extension
|
||||
self.session.add_extension(lt.create_metadata_plugin)
|
||||
self.session.add_extension(lt.create_ut_metadata_plugin)
|
||||
self.session.add_extension(lt.create_smart_ban_plugin)
|
||||
|
||||
# Start the AlertManager
|
||||
self.alerts = AlertManager(self.session)
|
||||
|
||||
# Start the SignalManager
|
||||
self.signals = SignalManager()
|
||||
|
||||
# Load plugins
|
||||
self.plugins = PluginManager(self)
|
||||
|
||||
# Start the TorrentManager
|
||||
self.torrents = TorrentManager(self.session, self.alerts)
|
||||
|
||||
# Start the FilterManager
|
||||
# Create the components
|
||||
self.preferencesmanager = PreferencesManager()
|
||||
self.alertmanager = AlertManager(self.session)
|
||||
self.signalmanager = SignalManager()
|
||||
self.pluginmanager = PluginManager(self)
|
||||
self.torrentmanager = TorrentManager(self.session, self.alertmanager)
|
||||
self.filtermanager = FilterManager(self)
|
||||
|
||||
# Create the AutoAdd component
|
||||
self.autoadd = AutoAdd()
|
||||
|
||||
# Start the AuthManager
|
||||
self.authmanager = AuthManager()
|
||||
|
||||
# New release check information
|
||||
self.new_release = None
|
||||
|
||||
component.start("PreferencesManager")
|
||||
component.start()
|
||||
# Get the core config
|
||||
self.config = deluge.configmanager.ConfigManager("core.conf")
|
||||
|
||||
self._should_shutdown = False
|
||||
def start(self):
|
||||
"""Starts the core"""
|
||||
# New release check information
|
||||
self.__new_release = None
|
||||
|
||||
self.listen_thread = threading.Thread(target=self.handle_thread)
|
||||
self.listen_thread.setDaemon(False)
|
||||
self.listen_thread.start()
|
||||
gobject.threads_init()
|
||||
def stop(self):
|
||||
# Save the DHT state if necessary
|
||||
if self.config["dht"]:
|
||||
self.__save_dht_state()
|
||||
# Save the libtorrent session state
|
||||
self.__save_session_state()
|
||||
|
||||
self.loop = gobject.MainLoop()
|
||||
try:
|
||||
self.loop.run()
|
||||
except KeyboardInterrupt:
|
||||
self._shutdown()
|
||||
|
||||
def handle_thread(self):
|
||||
try:
|
||||
while not self._should_shutdown:
|
||||
self.handle_request()
|
||||
self._should_shutdown = False
|
||||
|
||||
except Exception, e:
|
||||
log.debug("handle_thread: %s", e)
|
||||
# Make sure the config file has been saved
|
||||
self.config.save()
|
||||
|
||||
def shutdown(self):
|
||||
pass
|
||||
|
||||
def _shutdown(self, *data):
|
||||
"""This is called by a thread from shutdown()"""
|
||||
log.info("Shutting down core..")
|
||||
self._should_shutdown = True
|
||||
|
||||
# Save the DHT state if necessary
|
||||
if self.config["dht"]:
|
||||
self.save_dht_state()
|
||||
|
||||
# Save the libtorrent session state
|
||||
self.save_session_state()
|
||||
|
||||
# Shutdown the socket
|
||||
try:
|
||||
self.socket.shutdown(socket.SHUT_RDWR)
|
||||
except Exception, e:
|
||||
log.debug("exception in socket shutdown: %s", e)
|
||||
log.debug("Joining listen thread to make sure it shutdowns cleanly..")
|
||||
# Join the listen thread for a maximum of 1 second
|
||||
self.listen_thread.join(1.0)
|
||||
|
||||
# Start shutting down the components
|
||||
component.shutdown()
|
||||
|
||||
# Make sure the config file has been saved
|
||||
self.config.save()
|
||||
del self.config
|
||||
del deluge.configmanager
|
||||
del self.session
|
||||
self.loop.quit()
|
||||
|
||||
def save_session_state(self):
|
||||
def __save_session_state(self):
|
||||
"""Saves the libtorrent session state"""
|
||||
try:
|
||||
open(deluge.common.get_default_config_dir("session.state"), "wb").write(
|
||||
@ -286,7 +148,7 @@ class Core(
|
||||
except Exception, e:
|
||||
log.warning("Failed to save lt state: %s", e)
|
||||
|
||||
def load_session_state(self):
|
||||
def __load_session_state(self):
|
||||
"""Loads the libtorrent session state"""
|
||||
try:
|
||||
self.session.load_state(lt.bdecode(
|
||||
@ -294,7 +156,7 @@ class Core(
|
||||
except Exception, e:
|
||||
log.warning("Failed to load lt state: %s", e)
|
||||
|
||||
def save_dht_state(self):
|
||||
def __save_dht_state(self):
|
||||
"""Saves the dht state to a file"""
|
||||
try:
|
||||
dht_data = open(deluge.common.get_default_config_dir("dht.state"), "wb")
|
||||
@ -320,32 +182,31 @@ class Core(
|
||||
nr = self.new_release.split("_")
|
||||
cv = deluge.common.get_version().split("_")
|
||||
if nr[0] > cv[0]:
|
||||
self.signals.emit("new_version_available", self.new_release)
|
||||
self.signalmanager.emit("new_version_available", self.new_release)
|
||||
return self.new_release
|
||||
return False
|
||||
|
||||
# Exported Methods
|
||||
def export_ping(self):
|
||||
@export
|
||||
def ping(self):
|
||||
"""A method to see if the core is running"""
|
||||
return True
|
||||
|
||||
def export_shutdown(self):
|
||||
"""Shutdown the core"""
|
||||
# Make shutdown an async call
|
||||
gobject.idle_add(self._shutdown)
|
||||
|
||||
def export_register_client(self, port):
|
||||
@export
|
||||
def register_client(self, port):
|
||||
"""Registers a client with the signal manager so that signals are
|
||||
sent to it."""
|
||||
self.signals.register_client(self.client_address, port)
|
||||
self.signalmanager.register_client(component.get("RPCServer").client_address, port)
|
||||
if self.config["new_release_check"]:
|
||||
self.check_new_release()
|
||||
|
||||
def export_deregister_client(self):
|
||||
@export
|
||||
def deregister_client(self):
|
||||
"""De-registers a client with the signal manager."""
|
||||
self.signals.deregister_client(self.client_address)
|
||||
self.signalmanager.deregister_client(component.get("RPCServer").client_address)
|
||||
|
||||
def export_add_torrent_file(self, filename, filedump, options):
|
||||
@export
|
||||
def add_torrent_file(self, filename, filedump, options):
|
||||
"""Adds a torrent file to the libtorrent session
|
||||
This requires the torrents filename and a dump of it's content
|
||||
"""
|
||||
@ -366,17 +227,17 @@ class Core(
|
||||
log.warning("Unable to decode torrent file: %s", e)
|
||||
return None
|
||||
|
||||
torrent_id = self.torrents.add(filedump=filedump, options=options, filename=filename)
|
||||
torrent_id = self.torrentmanager.add(filedump=filedump, options=options, filename=filename)
|
||||
|
||||
# Run the plugin hooks for 'post_torrent_add'
|
||||
self.plugins.run_post_torrent_add(torrent_id)
|
||||
self.pluginmanager.run_post_torrent_add(torrent_id)
|
||||
|
||||
|
||||
def export_get_stats(self):
|
||||
@export
|
||||
def get_stats(self):
|
||||
"""
|
||||
document me!!!
|
||||
"""
|
||||
stats = self.export_get_session_status(["payload_download_rate", "payload_upload_rate",
|
||||
stats = self.get_session_status(["payload_download_rate", "payload_upload_rate",
|
||||
"dht_nodes", "has_incoming_connections", "download_rate", "upload_rate"])
|
||||
|
||||
stats.update({
|
||||
@ -391,8 +252,8 @@ class Core(
|
||||
|
||||
return stats
|
||||
|
||||
|
||||
def export_get_session_status(self, keys):
|
||||
@export
|
||||
def get_session_status(self, keys):
|
||||
"""
|
||||
Gets the session status values for 'keys'
|
||||
|
||||
@ -408,10 +269,11 @@ class Core(
|
||||
|
||||
return status
|
||||
|
||||
def export_add_torrent_url(self, url, options):
|
||||
@export
|
||||
def add_torrent_url(self, url, options):
|
||||
log.info("Attempting to add url %s", url)
|
||||
|
||||
threading.Thread(target=self.fetch_torrent_url_thread, args=(self.export_add_torrent_file, url, options)).start()
|
||||
threading.Thread(target=self.fetch_torrent_url_thread, args=(self.add_torrent_file, url, options)).start()
|
||||
|
||||
def fetch_torrent_url_thread(self, callback, url, options):
|
||||
# Get the actual filename of the torrent from the url provided.
|
||||
@ -432,7 +294,8 @@ class Core(
|
||||
# Add the torrent to session
|
||||
return callback(filename, filedump, options)
|
||||
|
||||
def export_add_torrent_magnets(self, uris, options):
|
||||
@export
|
||||
def add_torrent_magnets(self, uris, options):
|
||||
for uri in uris:
|
||||
log.debug("Attempting to add by magnet uri: %s", uri)
|
||||
try:
|
||||
@ -440,71 +303,82 @@ class Core(
|
||||
except IndexError:
|
||||
option = None
|
||||
|
||||
torrent_id = self.torrents.add(magnet=uri, options=option)
|
||||
torrent_id = self.torrentmanager.add(magnet=uri, options=option)
|
||||
|
||||
# Run the plugin hooks for 'post_torrent_add'
|
||||
self.plugins.run_post_torrent_add(torrent_id)
|
||||
self.pluginmanager.run_post_torrent_add(torrent_id)
|
||||
|
||||
def export_remove_torrent(self, torrent_ids, remove_data):
|
||||
@export
|
||||
def remove_torrent(self, torrent_ids, remove_data):
|
||||
log.debug("Removing torrent %s from the core.", torrent_ids)
|
||||
for torrent_id in torrent_ids:
|
||||
if self.torrents.remove(torrent_id, remove_data):
|
||||
if self.torrentmanager.remove(torrent_id, remove_data):
|
||||
# Run the plugin hooks for 'post_torrent_remove'
|
||||
self.plugins.run_post_torrent_remove(torrent_id)
|
||||
self.pluginmanager.run_post_torrent_remove(torrent_id)
|
||||
|
||||
def export_force_reannounce(self, torrent_ids):
|
||||
@export
|
||||
def force_reannounce(self, torrent_ids):
|
||||
log.debug("Forcing reannouncment to: %s", torrent_ids)
|
||||
for torrent_id in torrent_ids:
|
||||
self.torrents[torrent_id].force_reannounce()
|
||||
self.torrentmanager[torrent_id].force_reannounce()
|
||||
|
||||
def export_pause_torrent(self, torrent_ids):
|
||||
@export
|
||||
def pause_torrent(self, torrent_ids):
|
||||
log.debug("Pausing: %s", torrent_ids)
|
||||
for torrent_id in torrent_ids:
|
||||
if not self.torrents[torrent_id].pause():
|
||||
if not self.torrentmanager[torrent_id].pause():
|
||||
log.warning("Error pausing torrent %s", torrent_id)
|
||||
|
||||
def export_connect_peer(self, torrent_id, ip, port):
|
||||
@export
|
||||
def connect_peer(self, torrent_id, ip, port):
|
||||
log.debug("adding peer %s to %s", ip, torrent_id)
|
||||
if not self.torrents[torrent_id].connect_peer(ip, port):
|
||||
if not self.torrentmanager[torrent_id].connect_peer(ip, port):
|
||||
log.warning("Error adding peer %s:%s to %s", ip, port, torrent_id)
|
||||
|
||||
def export_move_storage(self, torrent_ids, dest):
|
||||
@export
|
||||
def move_storage(self, torrent_ids, dest):
|
||||
log.debug("Moving storage %s to %s", torrent_ids, dest)
|
||||
for torrent_id in torrent_ids:
|
||||
if not self.torrents[torrent_id].move_storage(dest):
|
||||
if not self.torrentmanager[torrent_id].move_storage(dest):
|
||||
log.warning("Error moving torrent %s to %s", torrent_id, dest)
|
||||
|
||||
def export_pause_all_torrents(self):
|
||||
@export
|
||||
def pause_all_torrents(self):
|
||||
"""Pause all torrents in the session"""
|
||||
self.session.pause()
|
||||
|
||||
def export_resume_all_torrents(self):
|
||||
@export
|
||||
def resume_all_torrents(self):
|
||||
"""Resume all torrents in the session"""
|
||||
self.session.resume()
|
||||
self.signals.emit("torrent_all_resumed")
|
||||
self.signalmanager.emit("torrent_all_resumed")
|
||||
|
||||
def export_resume_torrent(self, torrent_ids):
|
||||
@export
|
||||
def resume_torrent(self, torrent_ids):
|
||||
log.debug("Resuming: %s", torrent_ids)
|
||||
for torrent_id in torrent_ids:
|
||||
self.torrents[torrent_id].resume()
|
||||
self.torrentmanager[torrent_id].resume()
|
||||
|
||||
def export_get_status_keys(self):
|
||||
@export
|
||||
def get_status_keys(self):
|
||||
"""
|
||||
returns all possible keys for the keys argument in get_torrent(s)_status.
|
||||
"""
|
||||
return STATUS_KEYS + self.plugins.status_fields.keys()
|
||||
return STATUS_KEYS + self.pluginmanager.status_fields.keys()
|
||||
|
||||
def export_get_torrent_status(self, torrent_id, keys):
|
||||
@export
|
||||
def get_torrent_status(self, torrent_id, keys):
|
||||
# Build the status dictionary
|
||||
status = self.torrents[torrent_id].get_status(keys)
|
||||
status = self.torrentmanager[torrent_id].get_status(keys)
|
||||
|
||||
# Get the leftover fields and ask the plugin manager to fill them
|
||||
leftover_fields = list(set(keys) - set(status.keys()))
|
||||
if len(leftover_fields) > 0:
|
||||
status.update(self.plugins.get_status(torrent_id, leftover_fields))
|
||||
status.update(self.pluginmanager.get_status(torrent_id, leftover_fields))
|
||||
return status
|
||||
|
||||
def export_get_torrents_status(self, filter_dict, keys):
|
||||
@export
|
||||
def get_torrents_status(self, filter_dict, keys):
|
||||
"""
|
||||
returns all torrents , optionally filtered by filter_dict.
|
||||
"""
|
||||
@ -513,32 +387,31 @@ class Core(
|
||||
|
||||
# Get the torrent status for each torrent_id
|
||||
for torrent_id in torrent_ids:
|
||||
status_dict[torrent_id] = self.export_get_torrent_status(torrent_id, keys)
|
||||
status_dict[torrent_id] = self.get_torrent_status(torrent_id, keys)
|
||||
|
||||
return status_dict
|
||||
|
||||
def export_get_filter_tree(self , show_zero_hits=True, hide_cat=None):
|
||||
@export
|
||||
def get_filter_tree(self , show_zero_hits=True, hide_cat=None):
|
||||
"""
|
||||
returns {field: [(value,count)] }
|
||||
for use in sidebar(s)
|
||||
"""
|
||||
return self.filtermanager.get_filter_tree(show_zero_hits, hide_cat)
|
||||
|
||||
def export_get_session_state(self):
|
||||
@export
|
||||
def get_session_state(self):
|
||||
"""Returns a list of torrent_ids in the session."""
|
||||
# Get the torrent list from the TorrentManager
|
||||
return self.torrents.get_torrent_list()
|
||||
return self.torrentmanager.get_torrent_list()
|
||||
|
||||
def export_save_state(self):
|
||||
"""Save the current session state to file."""
|
||||
# Have the TorrentManager save it's state
|
||||
self.torrents.save_state()
|
||||
|
||||
def export_get_config(self):
|
||||
@export
|
||||
def get_config(self):
|
||||
"""Get all the preferences as a dictionary"""
|
||||
return self.config.config
|
||||
|
||||
def export_get_config_value(self, key):
|
||||
@export
|
||||
def get_config_value(self, key):
|
||||
"""Get the config value for key"""
|
||||
try:
|
||||
value = self.config[key]
|
||||
@ -547,7 +420,8 @@ class Core(
|
||||
|
||||
return value
|
||||
|
||||
def export_get_config_values(self, keys):
|
||||
@export
|
||||
def get_config_values(self, keys):
|
||||
"""Get the config values for the entered keys"""
|
||||
config = {}
|
||||
for key in keys:
|
||||
@ -557,8 +431,8 @@ class Core(
|
||||
pass
|
||||
return config
|
||||
|
||||
|
||||
def export_set_config(self, config):
|
||||
@export
|
||||
def set_config(self, config):
|
||||
"""Set the config with values from dictionary"""
|
||||
# Load all the values into the configuration
|
||||
for key in config.keys():
|
||||
@ -566,128 +440,157 @@ class Core(
|
||||
config[key] = config[key].encode("utf8")
|
||||
self.config[key] = config[key]
|
||||
|
||||
def export_get_listen_port(self):
|
||||
@export
|
||||
def get_listen_port(self):
|
||||
"""Returns the active listen port"""
|
||||
return self.session.listen_port()
|
||||
|
||||
def export_get_num_connections(self):
|
||||
@export
|
||||
def get_num_connections(self):
|
||||
"""Returns the current number of connections"""
|
||||
return self.session.num_connections()
|
||||
|
||||
def export_get_dht_nodes(self):
|
||||
@export
|
||||
def get_dht_nodes(self):
|
||||
"""Returns the number of dht nodes"""
|
||||
return self.session.status().dht_nodes
|
||||
|
||||
def export_get_download_rate(self):
|
||||
@export
|
||||
def get_download_rate(self):
|
||||
"""Returns the payload download rate"""
|
||||
return self.session.status().payload_download_rate
|
||||
|
||||
def export_get_upload_rate(self):
|
||||
@export
|
||||
def get_upload_rate(self):
|
||||
"""Returns the payload upload rate"""
|
||||
return self.session.status().payload_upload_rate
|
||||
|
||||
def export_get_available_plugins(self):
|
||||
@export
|
||||
def get_available_plugins(self):
|
||||
"""Returns a list of plugins available in the core"""
|
||||
return self.plugins.get_available_plugins()
|
||||
return self.pluginmanager.get_available_plugins()
|
||||
|
||||
def export_get_enabled_plugins(self):
|
||||
@export
|
||||
def get_enabled_plugins(self):
|
||||
"""Returns a list of enabled plugins in the core"""
|
||||
return self.plugins.get_enabled_plugins()
|
||||
return self.pluginmanager.get_enabled_plugins()
|
||||
|
||||
def export_enable_plugin(self, plugin):
|
||||
self.plugins.enable_plugin(plugin)
|
||||
@export
|
||||
def enable_plugin(self, plugin):
|
||||
self.pluginmanager.enable_plugin(plugin)
|
||||
return None
|
||||
|
||||
def export_disable_plugin(self, plugin):
|
||||
self.plugins.disable_plugin(plugin)
|
||||
@export
|
||||
def disable_plugin(self, plugin):
|
||||
self.pluginmanager.disable_plugin(plugin)
|
||||
return None
|
||||
|
||||
def export_force_recheck(self, torrent_ids):
|
||||
@export
|
||||
def force_recheck(self, torrent_ids):
|
||||
"""Forces a data recheck on torrent_ids"""
|
||||
for torrent_id in torrent_ids:
|
||||
self.torrents[torrent_id].force_recheck()
|
||||
self.torrentmanager[torrent_id].force_recheck()
|
||||
|
||||
def export_set_torrent_options(self, torrent_ids, options):
|
||||
@export
|
||||
def set_torrent_options(self, torrent_ids, options):
|
||||
"""Sets the torrent options for torrent_ids"""
|
||||
for torrent_id in torrent_ids:
|
||||
self.torrents[torrent_id].set_options(options)
|
||||
self.torrentmanager[torrent_id].set_options(options)
|
||||
|
||||
def export_set_torrent_trackers(self, torrent_id, trackers):
|
||||
@export
|
||||
def set_torrent_trackers(self, torrent_id, trackers):
|
||||
"""Sets a torrents tracker list. trackers will be [{"url", "tier"}]"""
|
||||
return self.torrents[torrent_id].set_trackers(trackers)
|
||||
return self.torrentmanager[torrent_id].set_trackers(trackers)
|
||||
|
||||
def export_set_torrent_max_connections(self, torrent_id, value):
|
||||
@export
|
||||
def set_torrent_max_connections(self, torrent_id, value):
|
||||
"""Sets a torrents max number of connections"""
|
||||
return self.torrents[torrent_id].set_max_connections(value)
|
||||
return self.torrentmanager[torrent_id].set_max_connections(value)
|
||||
|
||||
def export_set_torrent_max_upload_slots(self, torrent_id, value):
|
||||
@export
|
||||
def set_torrent_max_upload_slots(self, torrent_id, value):
|
||||
"""Sets a torrents max number of upload slots"""
|
||||
return self.torrents[torrent_id].set_max_upload_slots(value)
|
||||
return self.torrentmanager[torrent_id].set_max_upload_slots(value)
|
||||
|
||||
def export_set_torrent_max_upload_speed(self, torrent_id, value):
|
||||
@export
|
||||
def set_torrent_max_upload_speed(self, torrent_id, value):
|
||||
"""Sets a torrents max upload speed"""
|
||||
return self.torrents[torrent_id].set_max_upload_speed(value)
|
||||
return self.torrentmanager[torrent_id].set_max_upload_speed(value)
|
||||
|
||||
def export_set_torrent_max_download_speed(self, torrent_id, value):
|
||||
@export
|
||||
def set_torrent_max_download_speed(self, torrent_id, value):
|
||||
"""Sets a torrents max download speed"""
|
||||
return self.torrents[torrent_id].set_max_download_speed(value)
|
||||
return self.torrentmanager[torrent_id].set_max_download_speed(value)
|
||||
|
||||
def export_set_torrent_file_priorities(self, torrent_id, priorities):
|
||||
@export
|
||||
def set_torrent_file_priorities(self, torrent_id, priorities):
|
||||
"""Sets a torrents file priorities"""
|
||||
return self.torrents[torrent_id].set_file_priorities(priorities)
|
||||
return self.torrentmanager[torrent_id].set_file_priorities(priorities)
|
||||
|
||||
def export_set_torrent_prioritize_first_last(self, torrent_id, value):
|
||||
@export
|
||||
def set_torrent_prioritize_first_last(self, torrent_id, value):
|
||||
"""Sets a higher priority to the first and last pieces"""
|
||||
return self.torrents[torrent_id].set_prioritize_first_last(value)
|
||||
return self.torrentmanager[torrent_id].set_prioritize_first_last(value)
|
||||
|
||||
def export_set_torrent_auto_managed(self, torrent_id, value):
|
||||
@export
|
||||
def set_torrent_auto_managed(self, torrent_id, value):
|
||||
"""Sets the auto managed flag for queueing purposes"""
|
||||
return self.torrents[torrent_id].set_auto_managed(value)
|
||||
return self.torrentmanager[torrent_id].set_auto_managed(value)
|
||||
|
||||
def export_set_torrent_stop_at_ratio(self, torrent_id, value):
|
||||
@export
|
||||
def set_torrent_stop_at_ratio(self, torrent_id, value):
|
||||
"""Sets the torrent to stop at 'stop_ratio'"""
|
||||
return self.torrents[torrent_id].set_stop_at_ratio(value)
|
||||
return self.torrentmanager[torrent_id].set_stop_at_ratio(value)
|
||||
|
||||
def export_set_torrent_stop_ratio(self, torrent_id, value):
|
||||
@export
|
||||
def set_torrent_stop_ratio(self, torrent_id, value):
|
||||
"""Sets the ratio when to stop a torrent if 'stop_at_ratio' is set"""
|
||||
return self.torrents[torrent_id].set_stop_ratio(value)
|
||||
return self.torrentmanager[torrent_id].set_stop_ratio(value)
|
||||
|
||||
def export_set_torrent_remove_at_ratio(self, torrent_id, value):
|
||||
@export
|
||||
def set_torrent_remove_at_ratio(self, torrent_id, value):
|
||||
"""Sets the torrent to be removed at 'stop_ratio'"""
|
||||
return self.torrents[torrent_id].set_remove_at_ratio(value)
|
||||
return self.torrentmanager[torrent_id].set_remove_at_ratio(value)
|
||||
|
||||
def export_set_torrent_move_on_completed(self, torrent_id, value):
|
||||
@export
|
||||
def set_torrent_move_on_completed(self, torrent_id, value):
|
||||
"""Sets the torrent to be moved when completed"""
|
||||
return self.torrents[torrent_id].set_move_on_completed(value)
|
||||
return self.torrentmanager[torrent_id].set_move_on_completed(value)
|
||||
|
||||
def export_set_torrent_move_on_completed_path(self, torrent_id, value):
|
||||
@export
|
||||
def set_torrent_move_on_completed_path(self, torrent_id, value):
|
||||
"""Sets the path for the torrent to be moved when completed"""
|
||||
return self.torrents[torrent_id].set_move_on_completed_path(value)
|
||||
return self.torrentmanager[torrent_id].set_move_on_completed_path(value)
|
||||
|
||||
def export_block_ip_range(self, range):
|
||||
@export
|
||||
def block_ip_range(self, range):
|
||||
"""Block an ip range"""
|
||||
self.ip_filter.add_rule(range[0], range[1], 1)
|
||||
|
||||
# Start a 2 second timer (and remove the previous one if it exists)
|
||||
if self._set_ip_filter_timer:
|
||||
gobject.source_remove(self._set_ip_filter_timer)
|
||||
self._set_ip_filter_timer = gobject.timeout_add(2000, self.session.set_ip_filter, self.ip_filter)
|
||||
if self.__set_ip_filter_timer:
|
||||
gobject.source_remove(self.__set_ip_filter_timer)
|
||||
self.__set_ip_filter_timer = gobject.timeout_add(2000, self.session.set_ip_filter, self.ip_filter)
|
||||
|
||||
def export_reset_ip_filter(self):
|
||||
@export
|
||||
def reset_ip_filter(self):
|
||||
"""Clears the ip filter"""
|
||||
self.ip_filter = lt.ip_filter()
|
||||
self.session.set_ip_filter(self.ip_filter)
|
||||
|
||||
def export_get_health(self):
|
||||
@export
|
||||
def get_health(self):
|
||||
"""Returns True if we have established incoming connections"""
|
||||
return self.session.status().has_incoming_connections
|
||||
|
||||
def export_get_path_size(self, path):
|
||||
@export
|
||||
def get_path_size(self, path):
|
||||
"""Returns the size of the file or folder 'path' and -1 if the path is
|
||||
unaccessible (non-existent or insufficient privs)"""
|
||||
return deluge.common.get_path_size(path)
|
||||
|
||||
def export_create_torrent(self, path, tracker, piece_length, comment, target,
|
||||
@export
|
||||
def create_torrent(self, path, tracker, piece_length, comment, target,
|
||||
url_list, private, created_by, httpseeds, add_to_session):
|
||||
|
||||
log.debug("creating torrent..")
|
||||
@ -719,9 +622,10 @@ class Core(
|
||||
httpseeds=httpseeds)
|
||||
log.debug("torrent created!")
|
||||
if add_to_session:
|
||||
self.export_add_torrent_file(os.path.split(target)[1], open(target, "rb").read(), None)
|
||||
self.add_torrent_file(os.path.split(target)[1], open(target, "rb").read(), None)
|
||||
|
||||
def export_upload_plugin(self, filename, plugin_data):
|
||||
@export
|
||||
def upload_plugin(self, filename, plugin_data):
|
||||
"""This method is used to upload new plugins to the daemon. It is used
|
||||
when connecting to the daemon remotely and installing a new plugin on
|
||||
the client side. 'plugin_data' is a xmlrpc.Binary object of the file data,
|
||||
@ -732,71 +636,79 @@ class Core(
|
||||
f.close()
|
||||
component.get("PluginManager").scan_for_plugins()
|
||||
|
||||
def export_rescan_plugins(self):
|
||||
@export
|
||||
def rescan_plugins(self):
|
||||
"""Rescans the plugin folders for new plugins"""
|
||||
component.get("PluginManager").scan_for_plugins()
|
||||
|
||||
def export_rename_files(self, torrent_id, filenames):
|
||||
@export
|
||||
def rename_files(self, torrent_id, filenames):
|
||||
"""Renames files in 'torrent_id'. The 'filenames' parameter should be a
|
||||
list of (index, filename) pairs."""
|
||||
self.torrents[torrent_id].rename_files(filenames)
|
||||
self.torrentmanager[torrent_id].rename_files(filenames)
|
||||
|
||||
def export_rename_folder(self, torrent_id, folder, new_folder):
|
||||
@export
|
||||
def rename_folder(self, torrent_id, folder, new_folder):
|
||||
"""Renames the 'folder' to 'new_folder' in 'torrent_id'."""
|
||||
self.torrents[torrent_id].rename_folder(folder, new_folder)
|
||||
self.torrentmanager[torrent_id].rename_folder(folder, new_folder)
|
||||
|
||||
## Queueing functions ##
|
||||
def export_queue_top(self, torrent_ids):
|
||||
@export
|
||||
def queue_top(self, torrent_ids):
|
||||
log.debug("Attempting to queue %s to top", torrent_ids)
|
||||
for torrent_id in torrent_ids:
|
||||
try:
|
||||
# If the queue method returns True, then we should emit a signal
|
||||
if self.torrents.queue_top(torrent_id):
|
||||
self.signals.emit("torrent_queue_changed")
|
||||
if self.torrentmanager.queue_top(torrent_id):
|
||||
self.signalmanager.emit("torrent_queue_changed")
|
||||
except KeyError:
|
||||
log.warning("torrent_id: %s does not exist in the queue", torrent_id)
|
||||
|
||||
def export_queue_up(self, torrent_ids):
|
||||
@export
|
||||
def queue_up(self, torrent_ids):
|
||||
log.debug("Attempting to queue %s to up", torrent_ids)
|
||||
#torrent_ids must be sorted before moving.
|
||||
torrent_ids.sort(key = lambda id: self.torrents.torrents[id].get_queue_position())
|
||||
torrent_ids.sort(key = lambda id: self.torrentmanager.torrents[id].get_queue_position())
|
||||
for torrent_id in torrent_ids:
|
||||
try:
|
||||
# If the queue method returns True, then we should emit a signal
|
||||
if self.torrents.queue_up(torrent_id):
|
||||
self.signals.emit("torrent_queue_changed")
|
||||
if self.torrentmanager.queue_up(torrent_id):
|
||||
self.signalmanager.emit("torrent_queue_changed")
|
||||
except KeyError:
|
||||
log.warning("torrent_id: %s does not exist in the queue", torrent_id)
|
||||
|
||||
def export_queue_down(self, torrent_ids):
|
||||
@export
|
||||
def queue_down(self, torrent_ids):
|
||||
log.debug("Attempting to queue %s to down", torrent_ids)
|
||||
#torrent_ids must be sorted before moving.
|
||||
torrent_ids.sort(key = lambda id: -self.torrents.torrents[id].get_queue_position())
|
||||
torrent_ids.sort(key = lambda id: -self.torrentmanager.torrents[id].get_queue_position())
|
||||
for torrent_id in torrent_ids:
|
||||
try:
|
||||
# If the queue method returns True, then we should emit a signal
|
||||
if self.torrents.queue_down(torrent_id):
|
||||
self.signals.emit("torrent_queue_changed")
|
||||
if self.torrentmanager.queue_down(torrent_id):
|
||||
self.signalmanager.emit("torrent_queue_changed")
|
||||
except KeyError:
|
||||
log.warning("torrent_id: %s does not exist in the queue", torrent_id)
|
||||
|
||||
def export_queue_bottom(self, torrent_ids):
|
||||
@export
|
||||
def queue_bottom(self, torrent_ids):
|
||||
log.debug("Attempting to queue %s to bottom", torrent_ids)
|
||||
for torrent_id in torrent_ids:
|
||||
try:
|
||||
# If the queue method returns True, then we should emit a signal
|
||||
if self.torrents.queue_bottom(torrent_id):
|
||||
self.signals.emit("torrent_queue_changed")
|
||||
if self.torrentmanager.queue_bottom(torrent_id):
|
||||
self.signalmanager.emit("torrent_queue_changed")
|
||||
except KeyError:
|
||||
log.warning("torrent_id: %s does not exist in the queue", torrent_id)
|
||||
|
||||
def export_glob(self, path):
|
||||
@export
|
||||
def glob(self, path):
|
||||
return glob.glob(path)
|
||||
|
||||
def export_test_listen_port(self):
|
||||
@export
|
||||
def test_listen_port(self):
|
||||
""" Checks if active port is open """
|
||||
import urllib
|
||||
port = self.export_get_listen_port()
|
||||
port = self.get_listen_port()
|
||||
try:
|
||||
status = urllib.urlopen("http://deluge-torrent.org/test_port.php?port=%s" % port).read()
|
||||
except IOError:
|
||||
|
@ -22,15 +22,54 @@
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
|
||||
import signal
|
||||
|
||||
import gobject
|
||||
import gettext
|
||||
import locale
|
||||
import pkg_resources
|
||||
|
||||
import deluge.component as component
|
||||
import deluge.configmanager
|
||||
import deluge.common
|
||||
from deluge.core.rpcserver import RPCServer, export
|
||||
from deluge.log import LOG as log
|
||||
|
||||
class Daemon:
|
||||
class Daemon(object):
|
||||
def __init__(self, options, args):
|
||||
# Initialize gettext
|
||||
try:
|
||||
locale.setlocale(locale.LC_ALL, '')
|
||||
if hasattr(locale, "bindtextdomain"):
|
||||
locale.bindtextdomain("deluge", pkg_resources.resource_filename("deluge", "i18n"))
|
||||
if hasattr(locale, "textdomain"):
|
||||
locale.textdomain("deluge")
|
||||
gettext.bindtextdomain("deluge", pkg_resources.resource_filename("deluge", "i18n"))
|
||||
gettext.textdomain("deluge")
|
||||
gettext.install("deluge", pkg_resources.resource_filename("deluge", "i18n"))
|
||||
except Exception, e:
|
||||
log.error("Unable to initialize gettext/locale: %s", e)
|
||||
|
||||
# Setup signals
|
||||
signal.signal(signal.SIGINT, self.shutdown)
|
||||
signal.signal(signal.SIGTERM, self.shutdown)
|
||||
if not deluge.common.windows_check():
|
||||
signal.signal(signal.SIGHUP, self.shutdown)
|
||||
else:
|
||||
from win32api import SetConsoleCtrlHandler
|
||||
from win32con import CTRL_CLOSE_EVENT
|
||||
from win32con import CTRL_SHUTDOWN_EVENT
|
||||
result = 0
|
||||
def win_handler(ctrl_type):
|
||||
log.debug("ctrl_type: %s", ctrl_type)
|
||||
if ctrl_type == CTRL_CLOSE_EVENT or ctrl_type == CTRL_SHUTDOWN_EVENT:
|
||||
self.__shutdown()
|
||||
result = 1
|
||||
return result
|
||||
SetConsoleCtrlHandler(win_handler)
|
||||
|
||||
version = deluge.common.get_version()
|
||||
if deluge.common.get_revision() != "":
|
||||
if deluge.common.get_revision():
|
||||
version = version + "r" + deluge.common.get_revision()
|
||||
|
||||
log.info("Deluge daemon %s", version)
|
||||
@ -41,5 +80,25 @@ class Daemon:
|
||||
|
||||
from deluge.core.core import Core
|
||||
# Start the core as a thread and join it until it's done
|
||||
self.core = Core(options.port).run()
|
||||
self.core = Core()
|
||||
|
||||
self.rpcserver = RPCServer(options.port if options.port else self.core.config["daemon_port"])
|
||||
self.rpcserver.register_object(self.core, "core")
|
||||
self.rpcserver.register_object(self, "daemon")
|
||||
|
||||
gobject.threads_init()
|
||||
|
||||
# Make sure we start the PreferencesManager first
|
||||
component.start("PreferencesManager")
|
||||
component.start()
|
||||
|
||||
self.loop = gobject.MainLoop()
|
||||
try:
|
||||
self.loop.run()
|
||||
except KeyboardInterrupt:
|
||||
self.shutdown()
|
||||
|
||||
@export
|
||||
def shutdown(self):
|
||||
component.shutdown()
|
||||
self.loop.quit()
|
||||
|
@ -75,7 +75,7 @@ class FilterManager(component.Component):
|
||||
component.Component.__init__(self, "FilterManager")
|
||||
log.debug("FilterManager init..")
|
||||
self.core = core
|
||||
self.torrents = core.torrents
|
||||
self.torrents = core.torrentmanager
|
||||
self.registered_filters = {}
|
||||
self.register_filter("keyword", filter_keywords)
|
||||
self.tree_fields = {}
|
||||
@ -129,7 +129,7 @@ class FilterManager(component.Component):
|
||||
|
||||
#leftover filter arguments:
|
||||
#default filter on status fields.
|
||||
status_func = self.core.export_get_torrent_status #premature optimalisation..
|
||||
status_func = self.core.get_torrent_status #premature optimalisation..
|
||||
for torrent_id in list(torrent_ids):
|
||||
status = status_func(torrent_id, filter_dict.keys()) #status={key:value}
|
||||
for field, values in filter_dict.iteritems():
|
||||
@ -144,7 +144,7 @@ class FilterManager(component.Component):
|
||||
for use in sidebar.
|
||||
"""
|
||||
torrent_ids = self.torrents.get_torrent_list()
|
||||
status_func = self.core.export_get_torrent_status #premature optimalisation..
|
||||
status_func = self.core.get_torrent_status #premature optimalisation..
|
||||
tree_keys = list(self.tree_fields.keys())
|
||||
if hide_cat:
|
||||
for cat in hide_cat:
|
||||
@ -196,7 +196,7 @@ class FilterManager(component.Component):
|
||||
del self.tree_fields[field]
|
||||
|
||||
def filter_state_active(self, torrent_ids):
|
||||
get_status = self.core.export_get_torrent_status
|
||||
get_status = self.core.get_torrent_status
|
||||
for torrent_id in list(torrent_ids):
|
||||
status = get_status(torrent_id, ["download_payload_rate", "upload_payload_rate"])
|
||||
if status["download_payload_rate"] or status["upload_payload_rate"]:
|
||||
@ -223,6 +223,3 @@ class FilterManager(component.Component):
|
||||
iy = 99
|
||||
|
||||
return ix - iy
|
||||
|
||||
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
|
||||
"""RPCServer Module"""
|
||||
|
||||
import gobject
|
||||
|
||||
@ -35,20 +36,29 @@ import deluge.component as component
|
||||
import deluge.configmanager
|
||||
|
||||
def export(func):
|
||||
"""
|
||||
Decorator function to register an object's method as an RPC. The object
|
||||
will need to be registered with an RPCServer to be effective.
|
||||
|
||||
:param func: function, the function to export
|
||||
"""
|
||||
func._rpcserver_export = True
|
||||
return func
|
||||
|
||||
class RPCServer(component.Component):
|
||||
def __init__(self, port):
|
||||
"""
|
||||
This class is used to handle rpc requests from the client. Objects are
|
||||
registered with this class and their methods are exported using the export
|
||||
decorator.
|
||||
|
||||
:param port: int, the port the RPCServer will listen on
|
||||
:param allow_remote: bool, set True if the server should allow remote connections
|
||||
"""
|
||||
|
||||
def __init__(self, port=58846, allow_remote=False):
|
||||
component.Component.__init__(self, "RPCServer")
|
||||
|
||||
# Get config
|
||||
self.config = deluge.configmanager.ConfigManager("core.conf")
|
||||
|
||||
if port == None:
|
||||
port = self.config["daemon_port"]
|
||||
|
||||
if self.config["allow_remote"]:
|
||||
if allow_remote:
|
||||
hostname = ""
|
||||
else:
|
||||
hostname = "localhost"
|
||||
@ -70,15 +80,24 @@ class RPCServer(component.Component):
|
||||
|
||||
self.server.socket.setblocking(False)
|
||||
|
||||
gobject.io_add_watch(self.server.socket.fileno(), gobject.IO_IN | gobject.IO_OUT | gobject.IO_PRI | gobject.IO_ERR | gobject.IO_HUP, self._on_socket_activity)
|
||||
gobject.io_add_watch(self.server.socket.fileno(), gobject.IO_IN | gobject.IO_OUT | gobject.IO_PRI | gobject.IO_ERR | gobject.IO_HUP, self.__on_socket_activity)
|
||||
|
||||
def _on_socket_activity(self, source, condition):
|
||||
"""This gets called when there is activity on the socket, ie, data to read
|
||||
or to write."""
|
||||
def __on_socket_activity(self, source, condition):
|
||||
"""
|
||||
This gets called when there is activity on the socket, ie, data to read
|
||||
or to write and is called by gobject.io_add_watch().
|
||||
"""
|
||||
self.server.handle_request()
|
||||
return True
|
||||
|
||||
def register_object(self, obj, name=None):
|
||||
"""
|
||||
Registers an object to export it's rpc methods. These methods should
|
||||
be exported with the export decorator prior to registering the object.
|
||||
|
||||
:param obj: object, the object that we want to export
|
||||
:param name: str, the name to use, if None, it will be the class name of the object
|
||||
"""
|
||||
if not name:
|
||||
name = obj.__class__.__name__
|
||||
|
||||
@ -89,10 +108,18 @@ class RPCServer(component.Component):
|
||||
log.debug("Registering method: %s", name + "." + d)
|
||||
self.server.register_function(getattr(obj, d), name + "." + d)
|
||||
|
||||
@property
|
||||
def client_address(self):
|
||||
"""
|
||||
The ip address of the current client.
|
||||
"""
|
||||
return self.server.client_address
|
||||
|
||||
class XMLRPCServer(ThreadingMixIn, SimpleXMLRPCServer):
|
||||
def get_request(self):
|
||||
"""Get the request and client address from the socket.
|
||||
We override this so that we can get the ip address of the client.
|
||||
"""
|
||||
Get the request and client address from the socket.
|
||||
We override this so that we can get the ip address of the client.
|
||||
"""
|
||||
request, client_address = self.socket.accept()
|
||||
self.client_address = client_address[0]
|
||||
|
@ -35,6 +35,7 @@ from deluge.log import LOG as log
|
||||
from deluge.plugins.corepluginbase import CorePluginBase
|
||||
import deluge.component as component
|
||||
import deluge.configmanager
|
||||
from deluge.core.rpcserver import export
|
||||
|
||||
from peerguardian import PGReader, PGException
|
||||
from text import TextReader, GZMuleReader, PGZip
|
||||
@ -72,7 +73,7 @@ class Core(CorePluginBase):
|
||||
|
||||
self.config = deluge.configmanager.ConfigManager("blocklist.conf", DEFAULT_PREFS)
|
||||
if self.config["load_on_start"]:
|
||||
self.export_import(self.need_new_blocklist())
|
||||
self.import_list(self.need_new_blocklist())
|
||||
|
||||
# This function is called every 'check_after_days' days, to download
|
||||
# and import a new list if needed.
|
||||
@ -82,7 +83,7 @@ class Core(CorePluginBase):
|
||||
|
||||
def disable(self):
|
||||
log.debug("Reset IP Filter..")
|
||||
component.get("Core").export_reset_ip_filter()
|
||||
component.get("Core").reset_ip_filter()
|
||||
self.config.save()
|
||||
log.debug('Blocklist: Plugin disabled')
|
||||
|
||||
@ -90,25 +91,30 @@ class Core(CorePluginBase):
|
||||
pass
|
||||
|
||||
## Exported RPC methods ###
|
||||
def export_download(self, _import=False):
|
||||
@export
|
||||
def download_list(self, _import=False):
|
||||
"""Download the blocklist specified in the config as url"""
|
||||
self.download_blocklist(_import)
|
||||
|
||||
def export_import(self, download=False, force=False):
|
||||
@export
|
||||
def import_list(self, download=False, force=False):
|
||||
"""Import the blocklist from the blocklist.cache, if load is True, then
|
||||
it will download the blocklist file if needed."""
|
||||
threading.Thread(target=self.import_blocklist, kwargs={"download": download, "force": force}).start()
|
||||
|
||||
def export_get_config(self):
|
||||
@export
|
||||
def get_config(self):
|
||||
"""Returns the config dictionary"""
|
||||
return self.config.config
|
||||
|
||||
def export_set_config(self, config):
|
||||
@export
|
||||
def set_config(self, config):
|
||||
"""Sets the config based on values in 'config'"""
|
||||
for key in config.keys():
|
||||
self.config[key] = config[key]
|
||||
|
||||
def export_get_status(self):
|
||||
@export
|
||||
def get_status(self):
|
||||
"""Returns the status of the plugin."""
|
||||
status = {}
|
||||
if self.is_downloading:
|
||||
@ -133,7 +139,7 @@ class Core(CorePluginBase):
|
||||
def on_download_blocklist(self, load):
|
||||
self.is_downloading = False
|
||||
if load:
|
||||
self.export_import()
|
||||
self.import_list()
|
||||
|
||||
def import_blocklist(self, download=False, force=False):
|
||||
"""Imports the downloaded blocklist into the session"""
|
||||
@ -147,7 +153,7 @@ class Core(CorePluginBase):
|
||||
|
||||
self.is_importing = True
|
||||
log.debug("Reset IP Filter..")
|
||||
component.get("Core").export_reset_ip_filter()
|
||||
component.get("Core").reset_ip_filter()
|
||||
|
||||
self.num_blocked = 0
|
||||
|
||||
@ -170,7 +176,7 @@ class Core(CorePluginBase):
|
||||
log.debug("Blocklist import starting..")
|
||||
ips = read_list.next()
|
||||
while ips:
|
||||
self.core.export_block_ip_range(ips)
|
||||
self.core.block_ip_range(ips)
|
||||
self.num_blocked += 1
|
||||
ips = read_list.next()
|
||||
except Exception, e:
|
||||
|
@ -108,7 +108,7 @@ class GtkUI(ui.UI):
|
||||
self.glade.get_widget("label_url").set_text(
|
||||
status["file_url"])
|
||||
|
||||
client.blocklist_get_status(_on_get_status)
|
||||
client.blocklist.get_status(_on_get_status)
|
||||
|
||||
def _on_show_prefs(self):
|
||||
def _on_get_config(config):
|
||||
@ -126,7 +126,7 @@ class GtkUI(ui.UI):
|
||||
self.glade.get_widget("chk_import_on_start").set_active(
|
||||
config["load_on_start"])
|
||||
|
||||
client.blocklist_get_config(_on_get_config)
|
||||
client.blocklist.get_config(_on_get_config)
|
||||
|
||||
def _on_apply_prefs(self):
|
||||
config = {}
|
||||
@ -135,13 +135,13 @@ class GtkUI(ui.UI):
|
||||
config["url"] = self.glade.get_widget("entry_url").get_text()
|
||||
config["check_after_days"] = self.glade.get_widget("spin_check_days").get_value_as_int()
|
||||
config["load_on_start"] = self.glade.get_widget("chk_import_on_start").get_active()
|
||||
client.blocklist_set_config(None, config)
|
||||
client.blocklist.set_config(None, config)
|
||||
|
||||
def _on_button_check_download_clicked(self, widget):
|
||||
client.blocklist_import(None, True, False)
|
||||
client.blocklist.import_list(None, True, False)
|
||||
|
||||
def _on_button_force_download_clicked(self, widget):
|
||||
client.blocklist_import(None, True, True)
|
||||
client.blocklist.import_list(None, True, True)
|
||||
|
||||
def _on_status_item_clicked(self, widget, event):
|
||||
component.get("Preferences").show("Blocklist")
|
||||
|
@ -51,18 +51,18 @@ class BlockListCfgForm(forms.Form):
|
||||
|
||||
#load/save:
|
||||
def initial_data(self):
|
||||
data = sclient.blocklist_get_config()
|
||||
data = sclient.blocklist.get_config()
|
||||
return data
|
||||
|
||||
def save(self, data):
|
||||
cfg = dict(data)
|
||||
del cfg["btn_download_now"]
|
||||
del cfg["btn_import_now"]
|
||||
sclient.blocklist_set_config(cfg)
|
||||
sclient.blocklist.set_config(cfg)
|
||||
if data.btn_import_now:
|
||||
aclient.blocklist_import(None, data.btn_download_now)
|
||||
aclient.blocklist.import_list(None, data.btn_download_now)
|
||||
elif data.btn_download_now:
|
||||
aclient.blocklist_download(None)
|
||||
aclient.blocklist.download(None)
|
||||
|
||||
|
||||
#input fields :
|
||||
@ -78,7 +78,7 @@ class BlockListCfgForm(forms.Form):
|
||||
|
||||
def post_html(self):
|
||||
"show blocklist status"
|
||||
status = sclient.blocklist_get_status()
|
||||
status = sclient.blocklist.get_status()
|
||||
|
||||
if status["state"] == "Downloading":
|
||||
txt = _("Downloading %.2f%%") % (status["file_progress"] * 100)
|
||||
@ -109,6 +109,3 @@ class WebUI(ui.UI):
|
||||
|
||||
def disable(self):
|
||||
config_page_manager.deregister('blocklist')
|
||||
|
||||
|
||||
|
||||
|
@ -22,19 +22,12 @@
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
|
||||
|
||||
import deluge.component as component
|
||||
from deluge.log import LOG as log
|
||||
|
||||
class CorePluginBase:
|
||||
def __init__(self, plugin_api, plugin_name):
|
||||
self.plugin = plugin_api
|
||||
# Register all export_* functions
|
||||
for func in dir(self):
|
||||
if func.startswith("export_"):
|
||||
log.debug("Registering export function %s as %s", func,
|
||||
plugin_name.lower() + "_" + func[7:])
|
||||
self.plugin.get_core().register_function(
|
||||
getattr(self, "%s" % func), plugin_name.lower()\
|
||||
+ "_" + func[7:])
|
||||
# Register RPC methods
|
||||
component.get("RPCServer").register_object(self, plugin_name.lower())
|
||||
log.debug("CorePlugin initialized..")
|
||||
|
||||
|
@ -28,6 +28,7 @@ adds a status field for tracker.
|
||||
|
||||
from deluge.log import LOG as log
|
||||
from deluge.plugins.corepluginbase import CorePluginBase
|
||||
from deluge.core.rpcserver import export
|
||||
from deluge.configmanager import ConfigManager
|
||||
import deluge.component as component
|
||||
from urlparse import urlparse
|
||||
@ -93,7 +94,7 @@ class Core(CorePluginBase):
|
||||
#self.set_config_defaults()
|
||||
|
||||
#reduce typing, assigning some values to self...
|
||||
self.torrents = core.torrents.torrents
|
||||
self.torrents = core.torrentmanager.torrents
|
||||
self.labels = self.config["labels"]
|
||||
self.torrent_labels = self.config["torrent_labels"]
|
||||
|
||||
@ -180,7 +181,8 @@ class Core(CorePluginBase):
|
||||
return sorted(self.labels.keys())
|
||||
|
||||
#Labels:
|
||||
def export_add(self, label_id):
|
||||
@export
|
||||
def add(self, label_id):
|
||||
"""add a label
|
||||
see label_set_options for more options.
|
||||
"""
|
||||
@ -191,7 +193,8 @@ class Core(CorePluginBase):
|
||||
|
||||
self.labels[label_id] = dict(OPTIONS_DEFAULTS)
|
||||
|
||||
def export_remove(self, label_id):
|
||||
@export
|
||||
def remove(self, label_id):
|
||||
"remove a label"
|
||||
CheckInput(label_id in self.labels, _("Unknown Label"))
|
||||
del self.labels[label_id]
|
||||
@ -230,7 +233,8 @@ class Core(CorePluginBase):
|
||||
return True
|
||||
return False
|
||||
|
||||
def export_set_options(self, label_id, options_dict , apply = False):
|
||||
@export
|
||||
def set_options(self, label_id, options_dict , apply = False):
|
||||
"""update the label options
|
||||
|
||||
options_dict :
|
||||
@ -266,11 +270,13 @@ class Core(CorePluginBase):
|
||||
|
||||
self.config.save()
|
||||
|
||||
def export_get_options(self, label_id):
|
||||
@export
|
||||
def get_options(self, label_id):
|
||||
"""returns the label options"""
|
||||
return self.labels[label_id]
|
||||
|
||||
def export_set_torrent(self, torrent_id , label_id):
|
||||
@export
|
||||
def set_torrent(self, torrent_id , label_id):
|
||||
"""
|
||||
assign a label to a torrent
|
||||
removes a label if the label_id parameter is empty.
|
||||
@ -291,11 +297,13 @@ class Core(CorePluginBase):
|
||||
|
||||
self.config.save()
|
||||
|
||||
def export_get_config(self):
|
||||
@export
|
||||
def get_config(self):
|
||||
"see : label_set_config"
|
||||
return dict((key, self.config[key]) for key in CORE_OPTIONS if key in self.config.config)
|
||||
|
||||
def export_set_config(self, options):
|
||||
@export
|
||||
def set_config(self, options):
|
||||
"""global_options:"""
|
||||
for key, value in options.items:
|
||||
if key in CORE_OPTIONS:
|
||||
|
@ -60,7 +60,7 @@ class LabelConfig(object):
|
||||
return pkg_resources.resource_filename("label", os.path.join("data", filename))
|
||||
|
||||
def load_settings(self, widget=None, data=None):
|
||||
aclient.label_get_config(self.cb_global_options)
|
||||
aclient.label.get_config(self.cb_global_options)
|
||||
|
||||
def cb_global_options(self, options):
|
||||
log.debug("options=%s" % options)
|
||||
@ -72,4 +72,4 @@ class LabelConfig(object):
|
||||
def on_apply_prefs(self):
|
||||
options = {}
|
||||
#update options dict here.
|
||||
aclient.label_set_config(None, options)
|
||||
aclient.label.set_config(None, options)
|
||||
|
@ -81,7 +81,7 @@ class LabelSidebarMenu(object):
|
||||
self.add_dialog.show()
|
||||
|
||||
def on_remove(self, event=None):
|
||||
aclient.label_remove(None, self.treeview.value)
|
||||
aclient.label.remove(None, self.treeview.value)
|
||||
|
||||
def on_options (self, event=None):
|
||||
self.options_dialog.show(self.treeview.value)
|
||||
@ -137,7 +137,7 @@ class AddDialog(object):
|
||||
|
||||
def on_ok(self, event=None):
|
||||
value = self.glade.get_widget("txt_add").get_text()
|
||||
aclient.label_add(None, value)
|
||||
aclient.label.add(None, value)
|
||||
self.dialog.destroy()
|
||||
|
||||
def on_cancel(self, event=None):
|
||||
@ -179,7 +179,7 @@ class OptionsDialog(object):
|
||||
chk = self.glade.get_widget(chk_id)
|
||||
chk.connect("toggled",self.apply_sensitivity)
|
||||
|
||||
aclient.label_get_options(self.load_options, self.label)
|
||||
aclient.label.get_options(self.load_options, self.label)
|
||||
|
||||
self.dialog.run()
|
||||
|
||||
@ -212,7 +212,7 @@ class OptionsDialog(object):
|
||||
options["auto_add_trackers"] = [x for x in tracker_lst if x] #filter out empty lines.
|
||||
|
||||
log.debug(options)
|
||||
aclient.label_set_options(None, self.label, options)
|
||||
aclient.label.set_options(None, self.label, options)
|
||||
self.dialog.destroy()
|
||||
|
||||
def apply_sensitivity(self, event=None):
|
||||
|
@ -58,7 +58,7 @@ class LabelMenu(gtk.MenuItem):
|
||||
|
||||
def on_show(self, widget=None, data=None):
|
||||
log.debug("label-on-show")
|
||||
aclient.label_get_labels(self.cb_labels)
|
||||
aclient.label.get_labels(self.cb_labels)
|
||||
aclient.force_call(block=True)
|
||||
|
||||
def cb_labels(self , labels):
|
||||
@ -73,5 +73,5 @@ class LabelMenu(gtk.MenuItem):
|
||||
def on_select_label(self, widget=None, label_id = None):
|
||||
log.debug("select label:%s,%s" % (label_id ,self.get_torrent_ids()) )
|
||||
for torrent_id in self.get_torrent_ids():
|
||||
aclient.label_set_torrent(None, torrent_id, label_id)
|
||||
aclient.label.set_torrent(None, torrent_id, label_id)
|
||||
#aclient.force_call(block=True)
|
||||
|
@ -54,12 +54,12 @@ class options:
|
||||
|
||||
@api.deco.deluge_page
|
||||
def GET(self, label_id):
|
||||
return self.page(label_id, sclient.label_get_options(label_id))
|
||||
return self.page(label_id, sclient.label.get_options(label_id))
|
||||
|
||||
@api.deco.check_session
|
||||
def POST(self, label_id):
|
||||
post_options = api.utils.get_newforms_data(OptionsForm)
|
||||
options = sclient.label_get_options(label_id)
|
||||
options = sclient.label.get_options(label_id)
|
||||
|
||||
log.debug(options)
|
||||
options.update(dict(post_options))
|
||||
@ -72,7 +72,7 @@ class options:
|
||||
else:
|
||||
error = None
|
||||
|
||||
sclient.label_set_options(label_id, options_form.cleaned_data)
|
||||
sclient.label.set_options(label_id, options_form.cleaned_data)
|
||||
api.utils.seeother("/config/label")
|
||||
|
||||
|
||||
@ -90,7 +90,7 @@ class config_page:
|
||||
"""for ajaxui."""
|
||||
@api.deco.deluge_page
|
||||
def GET(self, args):
|
||||
labels = sclient.label_get_labels()
|
||||
labels = sclient.label.get_labels()
|
||||
return api.render.label.config_page(labels)
|
||||
|
||||
|
||||
@ -125,7 +125,7 @@ class OptionsForm(forms.Form):
|
||||
|
||||
#load/save:
|
||||
def initial_data(self):
|
||||
return sclient.label_get_options(self.label_id)
|
||||
return sclient.label.get_options(self.label_id)
|
||||
|
||||
#maximum:
|
||||
apply_max = forms.CheckBox(_("apply_max"))
|
||||
@ -164,15 +164,15 @@ class ConfigForm(forms.Form):
|
||||
|
||||
#load/save:
|
||||
def initial_data(self):
|
||||
return sclient.label_get_config()
|
||||
return sclient.label.get_config()
|
||||
|
||||
def save(self, data):
|
||||
cfg = dict(data)
|
||||
sclient.label_set_config(cfg)
|
||||
sclient.label.set_config(cfg)
|
||||
|
||||
def pre_html(self):
|
||||
""" custom config html/template"""
|
||||
labels = sclient.label_get_labels()
|
||||
labels = sclient.label.get_labels()
|
||||
return api.render.label.config(labels)
|
||||
|
||||
|
||||
|
@ -111,6 +111,7 @@ class CoreProxy(gobject.GObject):
|
||||
if self.rpc_core is None:
|
||||
raise deluge.error.NoCoreError("The core proxy is invalid.")
|
||||
return
|
||||
|
||||
_func = getattr(self._multi, func)
|
||||
|
||||
if _func is not None:
|
||||
@ -200,6 +201,18 @@ class CoreProxy(gobject.GObject):
|
||||
|
||||
_core = CoreProxy()
|
||||
|
||||
class DottedObject(object):
|
||||
"""This is used for dotted name calls to client"""
|
||||
def __init__(self, client, base):
|
||||
self.client = client
|
||||
self.base = base
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
return self.client.get_method("core." + self.base)(*args, **kwargs)
|
||||
|
||||
def __getattr__(self, name):
|
||||
return self.client.get_method(self.base + "." + name)
|
||||
|
||||
class BaseClient(object):
|
||||
"""
|
||||
wraps all calls to core/coreproxy
|
||||
@ -242,8 +255,7 @@ class BaseClient(object):
|
||||
raise NotImplementedError()
|
||||
|
||||
def __getattr__(self, method_name):
|
||||
return self.get_method(method_name)
|
||||
#raise AttributeError("no attr/method named:%s" % attr)
|
||||
return DottedObject(self, method_name)
|
||||
|
||||
#custom wrapped methods:
|
||||
def add_torrent_file(self, torrent_files, torrent_options=None):
|
||||
@ -277,7 +289,7 @@ class BaseClient(object):
|
||||
options = None
|
||||
else:
|
||||
options = None
|
||||
self.get_method("add_torrent_file")(filename, fdump, options)
|
||||
self.get_method("core.add_torrent_file")(filename, fdump, options)
|
||||
|
||||
def add_torrent_file_binary(self, filename, fdump, options = None):
|
||||
"""
|
||||
@ -286,10 +298,11 @@ class BaseClient(object):
|
||||
Expects fdump as a bytestring (== result of f.read()).
|
||||
"""
|
||||
fdump_xmlrpc = xmlrpclib.Binary(fdump)
|
||||
self.get_method("add_torrent_file")(filename, fdump_xmlrpc, options)
|
||||
self.get_method("core.add_torrent_file")(filename, fdump_xmlrpc, options)
|
||||
|
||||
#utility:
|
||||
def has_callback(self, method_name):
|
||||
method_name = method_name.split(".")[-1]
|
||||
return not (method_name in self.no_callback_list)
|
||||
|
||||
def is_localhost(self):
|
||||
|
@ -7,4 +7,4 @@ from deluge.ui.client import aclient as client
|
||||
class Command(BaseCommand):
|
||||
"Shutdown the deluge server."
|
||||
def handle(self, **options):
|
||||
client.shutdown()
|
||||
client.daemon.shutdown(None)
|
||||
|
@ -358,7 +358,7 @@ class ConnectionManager(component.Component):
|
||||
host = xmlrpclib.ServerProxy(get_localhost_auth_uri(uri))
|
||||
else:
|
||||
host = xmlrpclib.ServerProxy(uri)
|
||||
host.ping()
|
||||
host.core.ping()
|
||||
except Exception:
|
||||
online = False
|
||||
|
||||
|
@ -230,7 +230,7 @@ class GtkUI:
|
||||
component.shutdown()
|
||||
if self.started_in_classic:
|
||||
try:
|
||||
client.shutdown()
|
||||
client.daemon.shutdown(None)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
@ -231,14 +231,14 @@ class MenuBar(component.Component):
|
||||
def on_menuitem_quitdaemon_activate(self, data=None):
|
||||
log.debug("on_menuitem_quitdaemon_activate")
|
||||
# Tell the core to shutdown
|
||||
client.shutdown()
|
||||
client.daemon.shutdown(None)
|
||||
self.window.quit()
|
||||
|
||||
def on_menuitem_quit_activate(self, data=None):
|
||||
log.debug("on_menuitem_quit_activate")
|
||||
if self.config["classic_mode"]:
|
||||
try:
|
||||
client.shutdown()
|
||||
client.daemon.shutdown(None)
|
||||
except deluge.error.NoCoreError:
|
||||
pass
|
||||
self.window.quit()
|
||||
|
@ -308,7 +308,7 @@ class SystemTray(component.Component):
|
||||
return
|
||||
|
||||
if self.config["classic_mode"]:
|
||||
client.shutdown()
|
||||
client.daemon.shutdown(None)
|
||||
|
||||
self.window.quit()
|
||||
|
||||
@ -318,7 +318,7 @@ class SystemTray(component.Component):
|
||||
if not self.unlock_tray():
|
||||
return
|
||||
|
||||
client.shutdown()
|
||||
client.daemon.shutdown(None)
|
||||
self.window.quit()
|
||||
|
||||
def tray_setbwdown(self, widget, data=None):
|
||||
|
Loading…
x
Reference in New Issue
Block a user