summaryrefslogtreecommitdiffstats
path: root/deluge/core
diff options
context:
space:
mode:
Diffstat (limited to 'deluge/core')
-rw-r--r--deluge/core/alertmanager.py75
-rw-r--r--deluge/core/core.py3
-rw-r--r--deluge/core/rpcserver.py4
-rw-r--r--deluge/core/torrentmanager.py76
4 files changed, 81 insertions, 77 deletions
diff --git a/deluge/core/alertmanager.py b/deluge/core/alertmanager.py
index 9a1ded5..51a7f29 100644
--- a/deluge/core/alertmanager.py
+++ b/deluge/core/alertmanager.py
@@ -14,8 +14,11 @@ This should typically only be used by the Core. Plugins should utilize the
`:mod:EventManager` for similar functionality.
"""
+import contextlib
import logging
+from collections import defaultdict
from types import SimpleNamespace
+from typing import Any, Callable
from twisted.internet import reactor
@@ -52,7 +55,7 @@ class AlertManager(component.Component):
self.session.apply_settings({'alert_mask': alert_mask})
# handlers is a dictionary of lists {"alert_type": [handler1,h2,..]}
- self.handlers = {}
+ self.handlers = defaultdict(list)
self.delayed_calls = []
def update(self):
@@ -65,35 +68,33 @@ class AlertManager(component.Component):
delayed_call.cancel()
self.delayed_calls = []
- def register_handler(self, alert_type, handler):
+ def register_handler(self, alert_type: str, handler: Callable[[Any], None]) -> None:
"""
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
+ Args:
+ alert_type: String representation of the libtorrent alert name.
+ Can be supplied with or without `_alert` suffix.
+ handler: Callback function 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] = []
+ if alert_type and alert_type.endswith('_alert'):
+ alert_type = alert_type[: -len('_alert')]
- # 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):
+ def deregister_handler(self, handler: Callable[[Any], None]):
"""
- De-registers the `:param:handler` function from all alert types.
+ De-registers the `handler` function from all alert types.
- :param handler: func, the handler function to deregister
+ Args:
+ handler: 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)
+ for alert_type_handlers in self.handlers.values():
+ with contextlib.suppress(ValueError):
+ alert_type_handlers.remove(handler)
def handle_alerts(self):
"""
@@ -112,26 +113,36 @@ class AlertManager(component.Component):
num_alerts,
)
- # Loop through all alerts in the queue
for alert in alerts:
- alert_type = type(alert).__name__
+ alert_type = alert.what()
+
# Display the alert message
if log.isEnabledFor(logging.DEBUG):
log.debug('%s: %s', alert_type, decode_bytes(alert.message()))
+
+ if alert_type not in self.handlers:
+ continue
+
# 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))
+ for handler in self.handlers[alert_type]:
+ if log.isEnabledFor(logging.DEBUG):
+ log.debug('Handling alert: %s', alert_type)
+
+ alert_copy = self.create_alert_copy(alert)
+ self.delayed_calls.append(reactor.callLater(0, handler, alert_copy))
+
+ @staticmethod
+ def create_alert_copy(alert):
+ """Create a Python copy of libtorrent alert
+
+ Avoid segfault if an alert is handled after next pop_alert call"""
+ return SimpleNamespace(
+ **{
+ attr: getattr(alert, attr)
+ for attr in dir(alert)
+ if not attr.startswith('__')
+ }
+ )
def set_alert_queue_size(self, queue_size):
"""Sets the maximum size of the libtorrent alert queue"""
diff --git a/deluge/core/core.py b/deluge/core/core.py
index 35cf019..198410e 100644
--- a/deluge/core/core.py
+++ b/deluge/core/core.py
@@ -199,7 +199,7 @@ class Core(component.Component):
self.session_status_timer_interval = 0.5
self.session_status_timer = task.LoopingCall(self.session.post_session_stats)
self.alertmanager.register_handler(
- 'session_stats_alert', self._on_alert_session_stats
+ 'session_stats', self._on_alert_session_stats
)
self.session_rates_timer_interval = 2
self.session_rates_timer = task.LoopingCall(self._update_session_rates)
@@ -1000,7 +1000,6 @@ class Core(component.Component):
trackers,
add_to_session,
):
-
log.debug('creating torrent..')
threading.Thread(
target=self._create_torrent_thread,
diff --git a/deluge/core/rpcserver.py b/deluge/core/rpcserver.py
index d4ca5d1..81ab2e0 100644
--- a/deluge/core/rpcserver.py
+++ b/deluge/core/rpcserver.py
@@ -545,8 +545,8 @@ class RPCServer(component.Component):
:type event: :class:`deluge.event.DelugeEvent`
"""
log.debug('intevents: %s', self.factory.interested_events)
- # Find sessions interested in this event
- for session_id, interest in self.factory.interested_events.items():
+ # Use copy of `interested_events` since it can mutate while iterating.
+ for session_id, interest in self.factory.interested_events.copy().items():
if event.name in interest:
log.debug('Emit Event: %s %s', event.name, event.args)
# This session is interested so send a RPC_EVENT
diff --git a/deluge/core/torrentmanager.py b/deluge/core/torrentmanager.py
index 5609df4..a758d5c 100644
--- a/deluge/core/torrentmanager.py
+++ b/deluge/core/torrentmanager.py
@@ -50,10 +50,10 @@ from deluge.event import (
log = logging.getLogger(__name__)
LT_DEFAULT_ADD_TORRENT_FLAGS = (
- lt.add_torrent_params_flags_t.flag_paused
- | lt.add_torrent_params_flags_t.flag_auto_managed
- | lt.add_torrent_params_flags_t.flag_update_subscribe
- | lt.add_torrent_params_flags_t.flag_apply_ip_filter
+ lt.torrent_flags.paused
+ | lt.torrent_flags.auto_managed
+ | lt.torrent_flags.update_subscribe
+ | lt.torrent_flags.apply_ip_filter
)
@@ -202,34 +202,32 @@ class TorrentManager(component.Component):
# Register alert functions
alert_handles = [
- 'external_ip_alert',
- 'performance_alert',
- 'add_torrent_alert',
- 'metadata_received_alert',
- 'torrent_finished_alert',
- 'torrent_paused_alert',
- 'torrent_checked_alert',
- 'torrent_resumed_alert',
- 'tracker_reply_alert',
- 'tracker_announce_alert',
- 'tracker_warning_alert',
- 'tracker_error_alert',
- 'file_renamed_alert',
- 'file_error_alert',
- 'file_completed_alert',
- 'storage_moved_alert',
- 'storage_moved_failed_alert',
- 'state_update_alert',
- 'state_changed_alert',
- 'save_resume_data_alert',
- 'save_resume_data_failed_alert',
- 'fastresume_rejected_alert',
+ 'external_ip',
+ 'performance',
+ 'add_torrent',
+ 'metadata_received',
+ 'torrent_finished',
+ 'torrent_paused',
+ 'torrent_checked',
+ 'torrent_resumed',
+ 'tracker_reply',
+ 'tracker_announce',
+ 'tracker_warning',
+ 'tracker_error',
+ 'file_renamed',
+ 'file_error',
+ 'file_completed',
+ 'storage_moved',
+ 'storage_moved_failed',
+ 'state_update',
+ 'state_changed',
+ 'save_resume_data',
+ 'save_resume_data_failed',
+ 'fastresume_rejected',
]
for alert_handle in alert_handles:
- on_alert_func = getattr(
- self, ''.join(['on_alert_', alert_handle.replace('_alert', '')])
- )
+ on_alert_func = getattr(self, ''.join(['on_alert_', alert_handle]))
self.alerts.register_handler(alert_handle, on_alert_func)
# Define timers
@@ -369,11 +367,11 @@ class TorrentManager(component.Component):
add_torrent_params.flags = (
(
LT_DEFAULT_ADD_TORRENT_FLAGS
- | lt.add_torrent_params_flags_t.flag_duplicate_is_error
- | lt.add_torrent_params_flags_t.flag_upload_mode
+ | lt.torrent_flags.duplicate_is_error
+ | lt.torrent_flags.upload_mode
)
- ^ lt.add_torrent_params_flags_t.flag_auto_managed
- ^ lt.add_torrent_params_flags_t.flag_paused
+ ^ lt.torrent_flags.auto_managed
+ ^ lt.torrent_flags.paused
)
torrent_handle = self.session.add_torrent(add_torrent_params)
@@ -481,16 +479,12 @@ class TorrentManager(component.Component):
# Set flags: enable duplicate_is_error & override_resume_data, disable auto_managed.
add_torrent_params['flags'] = (
- LT_DEFAULT_ADD_TORRENT_FLAGS
- | lt.add_torrent_params_flags_t.flag_duplicate_is_error
- | lt.add_torrent_params_flags_t.flag_override_resume_data
- ) ^ lt.add_torrent_params_flags_t.flag_auto_managed
+ LT_DEFAULT_ADD_TORRENT_FLAGS | lt.torrent_flags.duplicate_is_error
+ ) ^ lt.torrent_flags.auto_managed
if options['seed_mode']:
- add_torrent_params['flags'] |= lt.add_torrent_params_flags_t.flag_seed_mode
+ add_torrent_params['flags'] |= lt.torrent_flags.seed_mode
if options['super_seeding']:
- add_torrent_params[
- 'flags'
- ] |= lt.add_torrent_params_flags_t.flag_super_seeding
+ add_torrent_params['flags'] |= lt.torrent_flags.super_seeding
return torrent_id, add_torrent_params