Skip to content

Commit

Permalink
Fix DownloadState.get_ratio()
Browse files Browse the repository at this point in the history
  • Loading branch information
drew2a committed Jan 26, 2024
1 parent 502d393 commit 62febe6
Show file tree
Hide file tree
Showing 11 changed files with 171 additions and 48 deletions.
5 changes: 4 additions & 1 deletion src/tribler/core/components/libtorrent/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,10 @@ def mock_lt_status():
lt_status.download_rate = 43
lt_status.total_upload = 100
lt_status.total_download = 200
lt_status.all_time_upload = 100
lt_status.total_payload_upload = 30
lt_status.total_payload_download = 100
lt_status.all_time_upload = 200
lt_status.all_time_download = 1000
lt_status.total_done = 200
lt_status.list_peers = 10
lt_status.download_payload_rate = 10
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
from tribler.core.utilities.notifier import Notifier
from tribler.core.utilities.osutils import fix_filebasename
from tribler.core.utilities.path_util import Path
from tribler.core.utilities.simpledefs import DOWNLOAD, DownloadStatus
from tribler.core.utilities.simpledefs import DownloadStatus
from tribler.core.utilities.unicode import ensure_unicode, hexlify
from tribler.core.utilities.utilities import bdecode_compat, safe_repr

Expand Down Expand Up @@ -447,7 +447,7 @@ def on_torrent_finished_alert(self, alert: lt.torrent_finished_alert):
self._logger.info(f'On torrent finished alert: {safe_repr(alert)}')
self.update_lt_status(self.handle.status())
self.checkpoint()
downloaded = self.get_state().get_total_transferred(DOWNLOAD)
downloaded = self.get_state().total_download
if downloaded > 0 and self.stream is not None and self.notifier is not None:
name = self.tdef.get_name_as_unicode()
infohash = self.tdef.get_infohash().hex()
Expand All @@ -465,7 +465,7 @@ def _stop_if_finished(self):
seeding_ratio = self.download_defaults.seeding_ratio
seeding_time = self.download_defaults.seeding_time
if (mode == 'never' or
(mode == 'ratio' and state.get_seeding_ratio() >= seeding_ratio) or
(mode == 'ratio' and state.get_all_time_ratio() >= seeding_ratio) or
(mode == 'time' and state.get_seeding_time() >= seeding_time)):
self.stop()

Expand Down Expand Up @@ -510,7 +510,7 @@ def force_recheck(self):
self.handle.resume()
self.handle.force_recheck()

def get_state(self):
def get_state(self) -> DownloadState:
""" Returns a snapshot of the current state of the download
@return DownloadState
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
Author(s): Arno Bakker
"""
import logging
from typing import Optional

from tribler.core.components.libtorrent.utils.libtorrent_helper import libtorrent
from tribler.core.utilities.simpledefs import (
DownloadStatus, UPLOAD,
)
Expand All @@ -31,7 +33,7 @@ class DownloadState:
cf. libtorrent torrent_status
"""

def __init__(self, download, lt_status, error):
def __init__(self, download, lt_status: Optional[libtorrent.torrent_status], error):
"""
Internal constructor.
@param download The download this state belongs too.
Expand Down Expand Up @@ -97,21 +99,73 @@ def get_current_payload_speed(self, direct):
return self.lt_status.upload_payload_rate
return self.lt_status.download_payload_rate

def get_total_transferred(self, direct):
@property
def all_time_upload(self) -> int:
""" Return accumulated upload payload byte counter.
It is saved in and restored from resume data to keep totals across sessions.
"""
Returns the total amount of up or downloaded bytes.
@return The amount in bytes.
if not self.lt_status:
return 0
return self.lt_status.all_time_upload

@property
def all_time_download(self) -> int:
""" Return accumulated download payload byte counter.
It is saved in and restored from resume data to keep totals across sessions.
"""
if not self.lt_status:
return 0
return self.lt_status.all_time_download

@property
def total_upload(self) -> int:
""" Return the number of bytes uploaded to all peers, accumulated, this session only
"""
if not self.lt_status:
return 0
return self.lt_status.total_upload

@property
def total_download(self) -> int:
""" Return the number of bytes downloaded to all peers, accumulated, this session only
"""
if not self.lt_status:
return 0
elif direct == UPLOAD:
return self.lt_status.total_upload
return self.lt_status.total_download

def get_seeding_ratio(self):
if self.lt_status and self.lt_status.total_done > 0:
return self.lt_status.all_time_upload / float(self.lt_status.total_done)
return 0
@property
def total_payload_upload(self) -> int:
"""
Returns the amount of bytes send this session, but only the actual payload data.
@return The amount in bytes.
"""
if not self.lt_status:
return 0
return self.lt_status.total_payload_upload

@property
def total_payload_download(self) -> int:
"""
Returns the amount of bytes received this session, but only the actual payload data.
@return The amount in bytes.
"""
if not self.lt_status:
return 0
return self.lt_status.total_payload_download

def get_session_ratio(self) -> float:
""" Returns the seeding ratio of the download for the current session.
"""
if not self.lt_status or not self.total_payload_download:
return 0
return self.total_payload_upload / self.total_payload_download

def get_all_time_ratio(self) -> float:
""" Returns the accumulated seeding ratio of the download across multiple sessions.
"""
if not self.lt_status or not self.all_time_download:
return 0
return self.all_time_upload / self.all_time_download

def get_seeding_time(self):
return self.lt_status.finished_time if self.lt_status else 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from aiohttp import web
from aiohttp_apispec import docs, json_schema
from ipv8.REST.schema import schema
from ipv8.messaging.anonymization.tunnel import CIRCUIT_ID_PORT, PEER_FLAG_EXIT_BT
from ipv8.messaging.anonymization.tunnel import PEER_FLAG_EXIT_BT
from marshmallow.fields import Boolean, Float, Integer, List, String

from tribler.core.components.libtorrent.download_manager.download import Download, IllegalFileIndex
Expand Down Expand Up @@ -237,9 +237,14 @@ def get_files_info_json_paged(download: Download, view_start: Path, view_size: i
'eta': Integer,
'num_peers': Integer,
'num_seeds': Integer,
'total_up': Integer,
'total_down': Integer,
'ratio': Float,
'total_upload': Integer,
'total_payload_upload': Integer,
'all_time_upload': Integer,
'total_payload_download': Integer,
'total_download': Integer,
'all_time_download': Integer,
'session_ratio': Float,
'all_time_ratio': Float,
'files': String,
'trackers': String,
'hops': Integer,
Expand Down Expand Up @@ -313,7 +318,6 @@ async def get_downloads(self, request):

download_status = get_extended_status(
self.tunnel_community, download) if self.tunnel_community else download.get_state().get_status()

download_json = {
"name": download_name,
"progress": state.get_progress(),
Expand All @@ -328,9 +332,14 @@ async def get_downloads(self, request):
"num_seeds": num_seeds,
"num_connected_peers": num_connected_peers,
"num_connected_seeds": num_connected_seeds,
"total_up": state.get_total_transferred(UPLOAD),
"total_down": state.get_total_transferred(DOWNLOAD),
"ratio": state.get_seeding_ratio(),
"total_upload": state.total_upload,
"total_payload_upload": state.total_payload_upload,
"all_time_upload": state.all_time_upload,
"total_download": state.total_download,
"total_payload_download": state.total_payload_download,
"all_time_download": state.all_time_download,
"session_ratio": state.get_session_ratio(),
"all_time_ratio": state.get_all_time_ratio(),
"trackers": tracker_info,
"hops": download.config.get_hops(),
"anon_download": download.get_anon_mode(),
Expand Down Expand Up @@ -363,7 +372,6 @@ async def get_downloads(self, request):
if 'extended_version' in peer_info:
peer_info['extended_version'] = _safe_extended_peer_info(peer_info['extended_version'])


download_json["peers"] = peer_list

# Add piece information if requested
Expand Down Expand Up @@ -688,7 +696,6 @@ async def collapse_tree_directory(self, request):

return RESTResponse({'path': path})


@docs(
tags=["Libtorrent"],
summary="Expand a tree directory.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -804,7 +804,7 @@ def test_on_torrent_finished_alert(test_download: Download):
test_download.handle = Mock(is_valid=Mock(return_value=True))
test_download.notifier = MagicMock()
test_download.stream = Mock()
test_download.get_state = Mock(return_value=Mock(get_total_transferred=Mock(return_value=1)))
test_download.get_state = Mock(return_value=Mock(total_download=1))

test_download.on_torrent_finished_alert(Mock())

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,12 @@ def test_getters_setters_1(mock_download):
assert download_state.get_progress() == 0
assert download_state.get_error() is None
assert download_state.get_current_speed(UPLOAD) == 0
assert download_state.get_total_transferred(UPLOAD) == 0
assert download_state.total_upload == 0
assert download_state.total_download == 0
assert download_state.total_payload_download == 0
assert download_state.total_payload_upload == 0
assert download_state.all_time_upload == 0
assert download_state.all_time_download == 0
assert download_state.get_num_seeds_peers() == (0, 0)
assert download_state.get_peerlist() == []

Expand All @@ -48,9 +53,17 @@ def test_getters_setters_2(mock_download, mock_lt_status):
assert download_state.get_status() == DownloadStatus.DOWNLOADING
assert download_state.get_current_speed(UPLOAD) == 123
assert download_state.get_current_speed(DOWNLOAD) == 43
assert download_state.get_total_transferred(UPLOAD) == 100
assert download_state.get_total_transferred(DOWNLOAD) == 200
assert download_state.get_seeding_ratio() == 0.5
assert download_state.total_upload == 100
assert download_state.total_download == 200

assert download_state.total_payload_upload == 30
assert download_state.total_payload_download == 100
assert download_state.get_session_ratio() == 0.3

assert download_state.all_time_upload == 200
assert download_state.all_time_download == 1000
assert download_state.get_all_time_ratio() == 0.2

assert download_state.get_eta() == 0.25
assert download_state.get_num_seeds_peers() == (5, 5)
assert download_state.get_pieces_complete() == []
Expand Down
2 changes: 1 addition & 1 deletion src/tribler/gui/debug_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ def on_ipv8_general_stats(self, data):
return
self.window().ipv8_general_tree_widget.clear()
for key, value in data["ipv8_statistics"].items():
if key in ('total_up', 'total_down'):
if key in ('total_upload', 'total_download'):
value = f"{value / (1024.0 * 1024.0):.2f} MB"
elif key == 'session_uptime':
value = f"{str(datetime.timedelta(seconds=int(value)))}"
Expand Down
44 changes: 39 additions & 5 deletions src/tribler/gui/qt_resources/mainwindow.ui
Original file line number Diff line number Diff line change
Expand Up @@ -3486,25 +3486,59 @@ margin-right: 10px;</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLabel" name="download_detail_ratio_label">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_26">
<widget class="QLabel" name="session_ratio_label">
<property name="styleSheet">
<string notr="true">font-weight: bold;</string>
</property>
<property name="text">
<string>Availability</string>
<string>Session ratio</string>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QLabel" name="download_detail_availability_label">
<widget class="QLabel" name="download_detail_session_ratio_label">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLabel" name="download_detail_ratio_label">
<item row="10" column="0">
<widget class="QLabel" name="session_total">
<property name="styleSheet">
<string notr="true">font-weight: bold;</string>
</property>
<property name="text">
<string>Session total</string>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QLabel" name="download_detail_session_total_label">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_26">
<property name="styleSheet">
<string notr="true">font-weight: bold;</string>
</property>
<property name="text">
<string>Availability</string>
</property>
</widget>
</item>
<item row="11" column="1">
<widget class="QLabel" name="download_detail_availability_label">
<property name="text">
<string/>
</property>
Expand Down
20 changes: 16 additions & 4 deletions src/tribler/gui/widgets/downloadsdetailstabwidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

from tribler.core.utilities.simpledefs import DownloadStatus
from tribler.gui.defs import STATUS_STRING
from tribler.gui.network.request_manager import request_manager
from tribler.gui.utilities import compose_magnetlink, connect, copy_to_clipboard, format_size, format_speed, tr
from tribler.gui.widgets.torrentfiletreewidget import PreformattedTorrentFileTreeWidget

Expand Down Expand Up @@ -172,11 +171,24 @@ def update_pages(self, new_download=False):
)
self.window().download_detail_infohash_label.setText(self.current_download['infohash'])
self.window().download_detail_destination_label.setText(self.current_download["destination"])
up = format_size(self.current_download['total_up'])
down = format_size(self.current_download['total_down'])
total_upload = format_size(self.current_download['total_upload'])
total_payload_upload = format_size(self.current_download['total_payload_upload'])
all_time_upload = format_size(self.current_download['all_time_upload'])
all_time_download = format_size(self.current_download['all_time_download'])
total_download = format_size(self.current_download['total_download'])
total_payload_download = format_size(self.current_download['total_payload_download'])
session_ratio = self.current_download['session_ratio']
all_time_ratio = self.current_download['all_time_ratio']
self.window().download_detail_ratio_label.setText(
f"{self.current_download['ratio']:.3f}, up: {up}, down: {down}"
f"{all_time_ratio:.3f}, upload: {all_time_upload}, download: {all_time_download}"
)
self.window().download_detail_session_ratio_label.setText(
f"{session_ratio:.3f}, upload: {total_payload_upload}, download: {total_payload_download}"
)
self.window().download_detail_session_total_label.setText(
f"Upload: {total_upload}, download: {total_download}"
)

self.window().download_detail_availability_label.setText(f"{self.current_download['availability']:.2f}")

if new_download:
Expand Down
Loading

0 comments on commit 62febe6

Please sign in to comment.