[Core] Stopped using libtorrent deprecated functions

As part of the process of adding support to LT 2.0, we should stop using
all deprecated function, as some (if not all) were removed.
For this process, we should use the LT 1.2 upgrade (guide)[1].

The change includes:
* stop using file entries directly
* start using the torrent handle's set/unset flags
* stop using url key in add_torrent_params (for magnet)
* stop accessing resume_data from save_resume_data_alert
* stop using deprecated session status keys in UI

[1] https://libtorrent.org/upgrade_to_1.2-ref.html
Closes: https://dev.deluge-torrent.org/ticket/3499
Closes: https://github.com/deluge-torrent/deluge/pull/342
This commit is contained in:
DjLegolas 2022-01-22 00:33:28 +02:00 committed by Calum Lind
parent 513d5f06e5
commit 2bd095e5bf
No known key found for this signature in database
GPG Key ID: 90597A687B836BA3
9 changed files with 120 additions and 75 deletions

View File

@ -41,7 +41,7 @@ All modules will require the [common](#common) section dependencies.
## Core (deluged daemon)
- [libtorrent] _>= 1.1.1_
- [libtorrent] _>= 1.2.0_
- [GeoIP] or [pygeoip] - Optional: IP address country lookup. (_Debian: `python-geoip`_)
## GTK UI

View File

@ -80,7 +80,7 @@ def convert_lt_files(files):
"""Indexes and decodes files from libtorrent get_files().
Args:
files (list): The libtorrent torrent files.
files (file_storage): The libtorrent torrent files.
Returns:
list of dict: The files.
@ -95,18 +95,18 @@ def convert_lt_files(files):
}
"""
filelist = []
for index, _file in enumerate(files):
for index in range(files.num_files()):
try:
file_path = _file.path.decode('utf8')
file_path = files.file_path(index).decode('utf8')
except AttributeError:
file_path = _file.path
file_path = files.file_path(index)
filelist.append(
{
'index': index,
'path': file_path.replace('\\', '/'),
'size': _file.size,
'offset': _file.offset,
'size': files.file_size(index),
'offset': files.file_offset(index),
}
)
@ -236,7 +236,7 @@ class Torrent:
self.magnet = magnet
self.status = self.handle.status()
self.torrent_info = self.handle.get_torrent_info()
self.torrent_info = self.handle.torrent_file()
self.has_metadata = self.status.has_metadata
self.options = TorrentOptions()
@ -275,6 +275,18 @@ class Torrent:
if log.isEnabledFor(logging.DEBUG):
log.debug('Torrent object created.')
def _set_handle_flags(self, flag: lt.torrent_flags, set_flag: bool):
"""set or unset a flag to the lt handle
Args:
flag (lt.torrent_flags): the flag to set/unset
set_flag (bool): True for setting the flag, False for unsetting it
"""
if set_flag:
self.handle.set_flags(flag)
else:
self.handle.unset_flags(flag)
def on_metadata_received(self):
"""Process the metadata received alert for this torrent"""
self.has_metadata = True
@ -359,7 +371,7 @@ class Torrent:
"""Sets maximum download speed for this torrent.
Args:
m_up_speed (float): Maximum download speed in KiB/s.
m_down_speed (float): Maximum download speed in KiB/s.
"""
self.options['max_download_speed'] = m_down_speed
if m_down_speed < 0:
@ -391,7 +403,7 @@ class Torrent:
return
# A list of priorities for each piece in the torrent
priorities = self.handle.piece_priorities()
priorities = self.handle.get_piece_priorities()
def get_file_piece(idx, byte_offset):
return self.torrent_info.map_file(idx, byte_offset, 0).piece
@ -424,7 +436,10 @@ class Torrent:
sequential (bool): Enable sequential downloading.
"""
self.options['sequential_download'] = sequential
self.handle.set_sequential_download(sequential)
self._set_handle_flags(
flag=lt.torrent_flags.sequential_download,
set_flag=sequential,
)
def set_auto_managed(self, auto_managed):
"""Set auto managed mode, i.e. will be started or queued automatically.
@ -434,7 +449,10 @@ class Torrent:
"""
self.options['auto_managed'] = auto_managed
if not (self.status.paused and not self.status.auto_managed):
self.handle.auto_managed(auto_managed)
self._set_handle_flags(
flag=lt.torrent_flags.auto_managed,
set_flag=auto_managed,
)
self.update_state()
def set_super_seeding(self, super_seeding):
@ -444,7 +462,10 @@ class Torrent:
super_seeding (bool): Enable super seeding.
"""
self.options['super_seeding'] = super_seeding
self.handle.super_seeding(super_seeding)
self._set_handle_flags(
flag=lt.torrent_flags.super_seeding,
set_flag=super_seeding,
)
def set_stop_ratio(self, stop_ratio):
"""The seeding ratio to stop (or remove) the torrent at.
@ -505,7 +526,7 @@ class Torrent:
self.handle.prioritize_files(file_priorities)
else:
log.debug('Unable to set new file priorities.')
file_priorities = self.handle.file_priorities()
file_priorities = self.handle.get_file_priorities()
if 0 in self.options['file_priorities']:
# Previously marked a file 'skip' so check for any 0's now >0.
@ -632,7 +653,10 @@ class Torrent:
elif status_error:
self.state = 'Error'
# auto-manage status will be reverted upon resuming.
self.handle.auto_managed(False)
self._set_handle_flags(
flag=lt.torrent_flags.auto_managed,
set_flag=False,
)
self.set_status_message(decode_bytes(status_error))
elif status.moving_storage:
self.state = 'Moving'
@ -686,7 +710,10 @@ class Torrent:
session can resume.
"""
status = self.handle.status()
self.handle.auto_managed(False)
self._set_handle_flags(
flag=lt.torrent_flags.auto_managed,
set_flag=False,
)
self.forced_error = TorrentError(message, status.paused, restart_to_resume)
if not status.paused:
self.handle.pause()
@ -700,7 +727,10 @@ class Torrent:
log.error('Restart deluge to clear this torrent error')
if not self.forced_error.was_paused and self.options['auto_managed']:
self.handle.auto_managed(True)
self._set_handle_flags(
flag=lt.torrent_flags.auto_managed,
set_flag=True,
)
self.forced_error = None
self.set_status_message('OK')
if update_state:
@ -843,7 +873,7 @@ class Torrent:
def get_file_priorities(self):
"""Return the file priorities"""
if not self.handle.has_metadata():
if not self.handle.status().has_metadata:
return []
if not self.options['file_priorities']:
@ -932,10 +962,10 @@ class Torrent:
if self.has_metadata:
# Use the top-level folder as torrent name.
filename = decode_bytes(self.torrent_info.file_at(0).path)
filename = decode_bytes(self.torrent_info.files().file_path(0))
name = filename.replace('\\', '/', 1).split('/', 1)[0]
else:
name = decode_bytes(self.handle.name())
name = decode_bytes(self.handle.status().name)
if not name:
name = self.torrent_id
@ -1152,7 +1182,10 @@ class Torrent:
"""
# Turn off auto-management so the torrent will not be unpaused by lt queueing
self.handle.auto_managed(False)
self._set_handle_flags(
flag=lt.torrent_flags.auto_managed,
set_flag=False,
)
if self.state == 'Error':
log.debug('Unable to pause torrent while in Error state')
elif self.status.paused:
@ -1187,7 +1220,10 @@ class Torrent:
else:
# Check if torrent was originally being auto-managed.
if self.options['auto_managed']:
self.handle.auto_managed(True)
self._set_handle_flags(
flag=lt.torrent_flags.auto_managed,
set_flag=True,
)
try:
self.handle.resume()
except RuntimeError as ex:

View File

@ -360,10 +360,9 @@ class TorrentManager(component.Component):
if torrent_id in self.prefetching_metadata:
return self.prefetching_metadata[torrent_id].defer
add_torrent_params = {}
add_torrent_params['save_path'] = gettempdir()
add_torrent_params['url'] = magnet.strip().encode('utf8')
add_torrent_params['flags'] = (
add_torrent_params = lt.parse_magnet_uri(magnet)
add_torrent_params.save_path = gettempdir()
add_torrent_params.flags = (
(
LT_DEFAULT_ADD_TORRENT_FLAGS
| lt.add_torrent_params_flags_t.flag_duplicate_is_error
@ -401,7 +400,10 @@ class TorrentManager(component.Component):
metadata = b''
if isinstance(torrent_info, lt.torrent_info):
log.debug('prefetch metadata received')
metadata = torrent_info.metadata()
if VersionSplit(LT_VERSION) < VersionSplit('2.0.0.0'):
metadata = torrent_info.metadata()
else:
metadata = torrent_info.info_section()
return torrent_id, b64encode(metadata)
@ -436,14 +438,10 @@ class TorrentManager(component.Component):
elif magnet:
magnet_info = get_magnet_info(magnet)
if magnet_info:
add_torrent_params['url'] = magnet.strip().encode('utf8')
add_torrent_params['name'] = magnet_info['name']
torrent_id = magnet_info['info_hash']
# Workaround lt 1.2 bug for magnet resume data with no metadata
if resume_data and VersionSplit(LT_VERSION) >= VersionSplit('1.2.10.0'):
add_torrent_params['info_hash'] = bytes(
bytearray.fromhex(torrent_id)
)
add_torrent_params['info_hash'] = bytes(bytearray.fromhex(torrent_id))
else:
raise AddTorrentError(
'Unable to add magnet, invalid magnet info: %s' % magnet
@ -1399,22 +1397,18 @@ class TorrentManager(component.Component):
log.debug(
'Tracker Error Alert: %s [%s]', decode_bytes(alert.message()), error_message
)
if VersionSplit(LT_VERSION) >= VersionSplit('1.2.0.0'):
# libtorrent 1.2 added endpoint struct to each tracker. to prevent false updates
# we will need to verify that at least one endpoint to the errored tracker is working
for tracker in torrent.handle.trackers():
if tracker['url'] == alert.url:
if any(
endpoint['last_error']['value'] == 0
for endpoint in tracker['endpoints']
):
torrent.set_tracker_status('Announce OK')
else:
torrent.set_tracker_status('Error: ' + error_message)
break
else:
# preserve old functionality for libtorrent < 1.2
torrent.set_tracker_status('Error: ' + error_message)
# libtorrent 1.2 added endpoint struct to each tracker. to prevent false updates
# we will need to verify that at least one endpoint to the errored tracker is working
for tracker in torrent.handle.trackers():
if tracker['url'] == alert.url:
if any(
endpoint['last_error']['value'] == 0
for endpoint in tracker['endpoints']
):
torrent.set_tracker_status('Announce OK')
else:
torrent.set_tracker_status('Error: ' + error_message)
break
def on_alert_storage_moved(self, alert):
"""Alert handler for libtorrent storage_moved_alert"""
@ -1488,7 +1482,9 @@ class TorrentManager(component.Component):
return
if torrent_id in self.torrents:
# libtorrent add_torrent expects bencoded resume_data.
self.resume_data[torrent_id] = lt.bencode(alert.resume_data)
self.resume_data[torrent_id] = lt.bencode(
lt.write_resume_data(alert.params)
)
if torrent_id in self.waiting_on_resume_data:
self.waiting_on_resume_data[torrent_id].callback(None)

View File

@ -109,7 +109,7 @@ class TestTorrent(BaseTestCase):
# updates and will return old value. Also need to remove a priority
# value as one file is much smaller than piece size so doesn't show.
await prios_set # Delay to wait for alert from lt
piece_prio = handle.piece_priorities()
piece_prio = handle.get_piece_priorities()
result = all(p in piece_prio for p in [3, 2, 0, 5, 6, 7])
assert result
@ -151,9 +151,9 @@ class TestTorrent(BaseTestCase):
handle = self.session.add_torrent(atp)
self.torrent = Torrent(handle, {})
priorities_original = handle.piece_priorities()
priorities_original = handle.get_piece_priorities()
self.torrent.set_prioritize_first_last_pieces(True)
priorities = handle.piece_priorities()
priorities = handle.get_piece_priorities()
# The length of the list of new priorites is the same as the original
assert len(priorities_original) == len(priorities)
@ -175,7 +175,7 @@ class TestTorrent(BaseTestCase):
self.torrent.set_prioritize_first_last_pieces(True)
# Reset pirorities
self.torrent.set_prioritize_first_last_pieces(False)
priorities = handle.piece_priorities()
priorities = handle.get_piece_priorities()
# Test the priority of the prioritized pieces
for i in priorities:

View File

@ -62,7 +62,12 @@ class Command(BaseCommand):
deferreds = []
ds = client.core.get_session_status(
['num_peers', 'payload_upload_rate', 'payload_download_rate', 'dht_nodes']
[
'peer.num_peers_connected',
'payload_upload_rate',
'payload_download_rate',
'dht.dht_nodes',
]
)
ds.addCallback(on_session_status)
deferreds.append(ds)
@ -92,7 +97,7 @@ class Command(BaseCommand):
'{!info!}Total download: %s'
% fspeed(self.status['payload_download_rate'])
)
self.console.write('{!info!}DHT Nodes: %i' % self.status['dht_nodes'])
self.console.write('{!info!}DHT Nodes: %i' % self.status['dht.dht_nodes'])
if isinstance(self.torrents, int):
if self.torrents == -2:

View File

@ -541,13 +541,13 @@ class TorrentDetail(BaseMode, PopupsHandler):
# Seed/peer info
s = '{{!info!}}{}:{{!green!}} {} {{!input!}}({})'.format(
torrent_data_fields['seeds']['name'],
status['num_seeds'],
status['peer.num_peers_connected'],
status['total_seeds'],
)
row = self.add_string(row, s)
s = '{{!info!}}{}:{{!red!}} {} {{!input!}}({})'.format(
torrent_data_fields['peers']['name'],
status['num_peers'],
status['peer.num_peers_connected'],
status['total_peers'],
)
row = self.add_string(row, s)

View File

@ -36,19 +36,23 @@ class StatusBars(component.Component):
def on_get_session_status(status):
self.upload = deluge.common.fsize(status['payload_upload_rate'])
self.download = deluge.common.fsize(status['payload_download_rate'])
self.connections = status['num_peers']
self.connections = status['peer.num_peers_connected']
if 'dht_nodes' in status:
self.dht = status['dht_nodes']
self.dht = status['dht.dht_nodes']
self.update_statusbars()
def on_get_external_ip(external_ip):
self.external_ip = external_ip
keys = ['num_peers', 'payload_upload_rate', 'payload_download_rate']
keys = [
'peer.num_peers_connected',
'payload_upload_rate',
'payload_download_rate',
]
if self.config['dht']:
keys.append('dht_nodes')
keys.append('dht.dht_nodes')
client.core.get_session_status(keys).addCallback(on_get_session_status)
client.core.get_external_ip().addCallback(on_get_external_ip)

View File

@ -317,18 +317,22 @@ class StatusBar(component.Component):
def send_status_request(self):
# Sends an async request for data from the core
keys = [
'num_peers',
'peer.num_peers_connected',
'upload_rate',
'download_rate',
'payload_upload_rate',
'payload_download_rate',
'net.sent_bytes',
'net.recv_bytes',
'net.sent_payload_bytes',
'net.recv_payload_bytes',
]
if self.dht_status:
keys.append('dht_nodes')
keys.append('dht.dht_nodes')
if not self.health:
keys.append('has_incoming_connections')
keys.append('net.has_incoming_connections')
client.core.get_session_status(keys).addCallback(self._on_get_session_status)
client.core.get_free_space().addCallback(self._on_get_free_space)
@ -367,18 +371,18 @@ class StatusBar(component.Component):
self.upload_protocol_rate = (
status['upload_rate'] - status['payload_upload_rate']
) // 1024
self.num_connections = status['num_peers']
self.num_connections = status['peer.num_peers_connected']
self.update_download_label()
self.update_upload_label()
self.update_traffic_label()
self.update_connections_label()
if 'dht_nodes' in status:
self.dht_nodes = status['dht_nodes']
if 'dht.dht_nodes' in status:
self.dht_nodes = status['dht.dht_nodes']
self.update_dht_label()
if 'has_incoming_connections' in status:
self.health = status['has_incoming_connections']
if 'net.has_incoming_connections' in status:
self.health = status['net.has_incoming_connections']
if self.health:
self.remove_item(self.health_item)

View File

@ -515,7 +515,7 @@ class WebApi(JSONComponent):
return d
def got_stats(stats):
ui_info['stats']['num_connections'] = stats['num_peers']
ui_info['stats']['num_connections'] = stats['peer.num_peers_connected']
ui_info['stats']['upload_rate'] = stats['payload_upload_rate']
ui_info['stats']['download_rate'] = stats['payload_download_rate']
ui_info['stats']['download_protocol_rate'] = (
@ -524,9 +524,9 @@ class WebApi(JSONComponent):
ui_info['stats']['upload_protocol_rate'] = (
stats['upload_rate'] - stats['payload_upload_rate']
)
ui_info['stats']['dht_nodes'] = stats['dht_nodes']
ui_info['stats']['dht_nodes'] = stats['dht.dht_nodes']
ui_info['stats']['has_incoming_connections'] = stats[
'has_incoming_connections'
'net.has_incoming_connections'
]
def got_filters(filters):
@ -552,13 +552,13 @@ class WebApi(JSONComponent):
d3 = client.core.get_session_status(
[
'num_peers',
'peer.num_peers_connected',
'payload_download_rate',
'payload_upload_rate',
'download_rate',
'upload_rate',
'dht_nodes',
'has_incoming_connections',
'dht.dht_nodes',
'net.has_incoming_connections',
]
)
d3.addCallback(got_stats)