diff --git a/deluge/core/torrent.py b/deluge/core/torrent.py index 57ec26f37a..5bc9b31e7e 100644 --- a/deluge/core/torrent.py +++ b/deluge/core/torrent.py @@ -263,6 +263,8 @@ def __init__(self, handle, options, state=None, filename=None, magnet=None): self.state = None self.moving_storage_dest_path = None self.tracker_status = '' + self.trackers_status = {} + self.trackers_peers = {} self.tracker_host = None self.forcing_recheck = False self.forcing_recheck_paused = False @@ -605,11 +607,12 @@ def set_trackers(self, trackers=None): self.force_reannounce() self.tracker_host = None - def set_tracker_status(self, status): + def set_tracker_status(self, status: str, tracker_url: str): """Sets the tracker status. Args: - status (str): The tracker status. + status: The tracker status. + tracker_url: The tracker url. Emits: TorrentTrackerStatusEvent upon tracker status change. @@ -618,12 +621,32 @@ def set_tracker_status(self, status): self.tracker_host = None - if self.tracker_status != status: + if self.state == 'Paused': + return + + if self.trackers_status.get(tracker_url) != status: + self.trackers_status[tracker_url] = status self.tracker_status = status component.get('EventManager').emit( - TorrentTrackerStatusEvent(self.torrent_id, self.tracker_status) + TorrentTrackerStatusEvent( + self.torrent_id, + self.trackers_status[tracker_url], + ) ) + def set_tracker_peers(self, peers: int, tracker_url: str): + """Sets the tracker peers amount + + Args: + peers: The number of peers the tracker has. + tracker_url: The tracker url. + """ + if self.state == 'Paused': + return + + if self.trackers_peers.get(tracker_url) != peers: + self.trackers_peers[tracker_url] = peers + def merge_trackers(self, torrent_info): """Merges new trackers in torrent_info into torrent""" log.info( @@ -666,6 +689,8 @@ def update_state(self): self.state = 'Queued' elif session_paused or status.paused: self.state = 'Paused' + self.trackers_peers = {} + self.trackers_status = {} else: self.state = LT_TORRENT_STATE_MAP.get(str(status.state), str(status.state)) @@ -865,6 +890,65 @@ def get_peers(self): return ret + def get_peers_source(self): + """Get the peers source statistics for this torrent. + + A list of peers sources and the statistics about them. + + Returns: + List: The peers source statistics. + + The format for the source data:: + + { + "name": str, + "count" int, + "enabled": bool + } + """ + ret = [] + for name in ['dht', 'pex', 'lsd']: + ret.append({'name': name, 'count': 0, 'enabled': False}) + + peers = self.handle.get_peer_info() + + private = self.torrent_info.priv() + session_config = component.get('Core').get_config() + handle_flags = self.handle.flags() + + if ( + not private + and not handle_flags & lt.torrent_flags.disable_dht + and session_config['dht'] + ): + ret[0]['enabled'] = True + if ( + not private + and not handle_flags & lt.torrent_flags.disable_pex + and session_config['utpex'] + ): + ret[1]['enabled'] = True + if ( + not private + and not handle_flags & lt.torrent_flags.disable_lsd + and session_config['lsd'] + ): + ret[2]['enabled'] = True + + for peer in peers: + # We do not want to report peers that are half-connected + if peer.flags & peer.connecting or peer.flags & peer.handshake: + continue + + if peer.source & peer.dht: + ret[0]['count'] += 1 + if peer.source & peer.pex: + ret[1]['count'] += 1 + if peer.source & peer.lsd: + ret[2]['count'] += 1 + + return ret + def get_queue_position(self): """Get the torrents queue position @@ -1158,7 +1242,10 @@ def _create_status_funcs(self): 'tracker': lambda: self.status.current_tracker, 'tracker_host': self.get_tracker_host, 'trackers': lambda: self.trackers, + # Deprecated: Use trackers_status 'tracker_status': lambda: self.tracker_status, + 'trackers_status': lambda: self.trackers_status, + 'trackers_peers': lambda: self.trackers_peers, 'upload_payload_rate': lambda: self.status.upload_payload_rate, 'comment': lambda: decode_bytes(self.torrent_info.comment()) if self.has_metadata @@ -1185,6 +1272,7 @@ def _create_status_funcs(self): 'orig_files': self.get_orig_files, 'is_seed': lambda: self.status.is_seeding, 'peers': self.get_peers, + 'peers_source': self.get_peers_source, 'queue': lambda: self.status.queue_position, 'ratio': self.get_ratio, 'completed_time': lambda: self.status.completed_time, diff --git a/deluge/core/torrentmanager.py b/deluge/core/torrentmanager.py index 41e1966b04..3e831692ef 100644 --- a/deluge/core/torrentmanager.py +++ b/deluge/core/torrentmanager.py @@ -1351,7 +1351,9 @@ def on_alert_tracker_reply(self, alert): return # Set the tracker status for the torrent - torrent.set_tracker_status('Announce OK') + torrent.set_tracker_status('Announce OK', alert.url) + # Set the amount of peers of the tracker + torrent.set_tracker_peers(alert.num_peers, alert.url) # Check for peer information from the tracker, if none then send a scrape request. torrent.get_lt_status() @@ -1366,7 +1368,7 @@ def on_alert_tracker_announce(self, alert): return # Set the tracker status for the torrent - torrent.set_tracker_status('Announce Sent') + torrent.set_tracker_status('Announce Sent', alert.url) def on_alert_tracker_warning(self, alert): """Alert handler for libtorrent tracker_warning_alert""" @@ -1375,7 +1377,10 @@ def on_alert_tracker_warning(self, alert): except (RuntimeError, KeyError): return # Set the tracker status for the torrent - torrent.set_tracker_status('Warning: %s' % decode_bytes(alert.message())) + torrent.set_tracker_status( + 'Warning: %s' % decode_bytes(alert.message()), + alert.url, + ) def on_alert_tracker_error(self, alert): """Alert handler for libtorrent tracker_error_alert""" @@ -1398,9 +1403,9 @@ def on_alert_tracker_error(self, alert): endpoint['last_error']['value'] == 0 for endpoint in tracker['endpoints'] ): - torrent.set_tracker_status('Announce OK') + torrent.set_tracker_status('Announce OK', alert.url) else: - torrent.set_tracker_status('Error: ' + error_message) + torrent.set_tracker_status('Error: ' + error_message, alert.url) break def on_alert_storage_moved(self, alert):