summaryrefslogtreecommitdiffstats
path: root/deluge/core/alertmanager.py
diff options
context:
space:
mode:
Diffstat (limited to 'deluge/core/alertmanager.py')
-rw-r--r--deluge/core/alertmanager.py152
1 files changed, 152 insertions, 0 deletions
diff --git a/deluge/core/alertmanager.py b/deluge/core/alertmanager.py
new file mode 100644
index 0000000..2fe4222
--- /dev/null
+++ b/deluge/core/alertmanager.py
@@ -0,0 +1,152 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2007-2009 Andrew Resch <andrewresch@gmail.com>
+#
+# This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with
+# the additional special exception to link portions of this program with the OpenSSL library.
+# See LICENSE for more details.
+#
+
+"""
+
+The AlertManager handles all the libtorrent alerts.
+
+This should typically only be used by the Core. Plugins should utilize the
+`:mod:EventManager` for similar functionality.
+
+"""
+from __future__ import unicode_literals
+
+import logging
+import types
+
+from twisted.internet import reactor
+
+import deluge.component as component
+from deluge._libtorrent import lt
+from deluge.common import decode_bytes
+
+log = logging.getLogger(__name__)
+
+try:
+ SimpleNamespace = types.SimpleNamespace # Python 3.3+
+except AttributeError:
+
+ class SimpleNamespace(object): # Python 2.7
+ def __init__(self, **attr):
+ self.__dict__.update(attr)
+
+
+class AlertManager(component.Component):
+ """AlertManager fetches and processes libtorrent alerts"""
+
+ def __init__(self):
+ log.debug('AlertManager init...')
+ component.Component.__init__(self, 'AlertManager', interval=0.3)
+ self.session = component.get('Core').session
+
+ # Increase the alert queue size so that alerts don't get lost.
+ self.alert_queue_size = 10000
+ self.set_alert_queue_size(self.alert_queue_size)
+
+ alert_mask = (
+ lt.alert.category_t.error_notification
+ | lt.alert.category_t.port_mapping_notification
+ | lt.alert.category_t.storage_notification
+ | lt.alert.category_t.tracker_notification
+ | lt.alert.category_t.status_notification
+ | lt.alert.category_t.ip_block_notification
+ | lt.alert.category_t.performance_warning
+ )
+
+ self.session.apply_settings({'alert_mask': alert_mask})
+
+ # handlers is a dictionary of lists {"alert_type": [handler1,h2,..]}
+ self.handlers = {}
+ self.delayed_calls = []
+
+ def update(self):
+ self.delayed_calls = [dc for dc in self.delayed_calls if dc.active()]
+ self.handle_alerts()
+
+ def stop(self):
+ for delayed_call in self.delayed_calls:
+ if delayed_call.active():
+ delayed_call.cancel()
+ self.delayed_calls = []
+
+ def register_handler(self, alert_type, handler):
+ """
+ Registers a function that will be called when 'alert_type' is pop'd
+ in handle_alerts. The handler function should look like: handler(alert)
+ Where 'alert' is the actual alert object from libtorrent.
+
+ :param alert_type: str, this is string representation of the alert name
+ :param handler: func(alert), the function to be called when the alert is raised
+ """
+ if alert_type not in self.handlers:
+ # There is no entry for this alert type yet, so lets make it with an
+ # empty list.
+ self.handlers[alert_type] = []
+
+ # Append the handler to the list in the handlers dictionary
+ self.handlers[alert_type].append(handler)
+ log.debug('Registered handler for alert %s', alert_type)
+
+ def deregister_handler(self, handler):
+ """
+ De-registers the `:param:handler` function from all alert types.
+
+ :param handler: func, the handler function to deregister
+ """
+ # Iterate through all handlers and remove 'handler' where found
+ for (dummy_key, value) in self.handlers.items():
+ if handler in value:
+ # Handler is in this alert type list
+ value.remove(handler)
+
+ def handle_alerts(self):
+ """
+ Pops all libtorrent alerts in the session queue and handles them appropriately.
+ """
+ alerts = self.session.pop_alerts()
+ if not alerts:
+ return
+
+ num_alerts = len(alerts)
+ if log.isEnabledFor(logging.DEBUG):
+ log.debug('Alerts queued: %s', num_alerts)
+ if num_alerts > 0.9 * self.alert_queue_size:
+ log.warning(
+ 'Warning total alerts queued, %s, passes 90%% of queue size.',
+ num_alerts,
+ )
+
+ # Loop through all alerts in the queue
+ for alert in alerts:
+ alert_type = type(alert).__name__
+ # Display the alert message
+ if log.isEnabledFor(logging.DEBUG):
+ log.debug('%s: %s', alert_type, decode_bytes(alert.message()))
+ # Call any handlers for this alert type
+ if alert_type in self.handlers:
+ for handler in self.handlers[alert_type]:
+ if log.isEnabledFor(logging.DEBUG):
+ log.debug('Handling alert: %s', alert_type)
+ # Copy alert attributes
+ alert_copy = SimpleNamespace(
+ **{
+ attr: getattr(alert, attr)
+ for attr in dir(alert)
+ if not attr.startswith('__')
+ }
+ )
+ self.delayed_calls.append(reactor.callLater(0, handler, alert_copy))
+
+ def set_alert_queue_size(self, queue_size):
+ """Sets the maximum size of the libtorrent alert queue"""
+ log.info('Alert Queue Size set to %s', queue_size)
+ self.alert_queue_size = queue_size
+ component.get('Core').apply_session_setting(
+ 'alert_queue_size', self.alert_queue_size
+ )