diff --git a/.github/workflows/unittests.yml b/.github/workflows/unittests.yml index 0047a90f4b..add46cfa8c 100644 --- a/.github/workflows/unittests.yml +++ b/.github/workflows/unittests.yml @@ -50,7 +50,7 @@ jobs: - shell: bash run: | cp /opt/homebrew/opt/libsodium/lib/libsodium.dylib /Library/Frameworks/Python.framework/Versions/3.9/lib/libsodium.dylib - sed -i".backup" 's|libtorrent==1.2.19|https://tribler.org/libtorrent-2.0.11-cp39-cp39-macosx_14_0_arm64.whl|' requirements.txt + sed -i".backup" 's|libtorrent==2.0.9|https://tribler.org/libtorrent-2.0.11-cp39-cp39-macosx_14_0_arm64.whl|' requirements.txt - run: python -m pip install -r requirements.txt - name: Run unit tests run: | diff --git a/build/docker/build.Dockerfile b/build/docker/build.Dockerfile index 050b940428..3050801ab3 100644 --- a/build/docker/build.Dockerfile +++ b/build/docker/build.Dockerfile @@ -1,4 +1,4 @@ -# libtorrent-1.2.19 does not support python 3.11 yet +# libtorrent-2.0.9 does not support python 3.11 yet FROM python:3.10-slim RUN apt-get update \ diff --git a/requirements.txt b/requirements.txt index e50a57f64e..530e2c51f9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,8 +3,9 @@ bitarray configobj ipv8-rust-tunnels -libtorrent==1.2.19 +libtorrent==2.0.9 lz4 +marshmallow==3.23.3 # TODO: support 3.24.0 onward pillow pony pystray diff --git a/src/tribler/core/libtorrent/download_manager/download_manager.py b/src/tribler/core/libtorrent/download_manager/download_manager.py index adb6ff0b41..d60690016c 100644 --- a/src/tribler/core/libtorrent/download_manager/download_manager.py +++ b/src/tribler/core/libtorrent/download_manager/download_manager.py @@ -16,7 +16,7 @@ from copy import deepcopy from pathlib import Path from tempfile import TemporaryDirectory -from typing import TYPE_CHECKING, Any, Awaitable, Callable, Dict, Iterable, List, cast +from typing import TYPE_CHECKING, Any, Callable, cast import libtorrent as lt from configobj import ConfigObj @@ -33,6 +33,8 @@ from tribler.tribler_config import VERSION_SUBDIR if TYPE_CHECKING: + from collections.abc import Awaitable, Iterable + from tribler.core.libtorrent.download_manager.dht_health_manager import DHTHealthManager from tribler.tribler_config import TriblerConfigManager @@ -106,7 +108,7 @@ def __init__(self, config: TriblerConfigManager, notifier: Notifier, self.register_task("Set default upload rate limit", self.set_upload_rate_limit, 0) self.register_task("Set default download rate limit", self.set_download_rate_limit, 0) - self.downloads: Dict[bytes, Download] = {} + self.downloads: dict[bytes, Download] = {} self.checkpoint_directory = (self.state_dir / "dlcheckpoints") self.checkpoints_count = 0 @@ -287,7 +289,8 @@ def create_session(self, hops: int = 0) -> lt.session: # noqa: PLR0915 "enable_upnp": int(self.config.get("libtorrent/upnp")), "enable_dht": int(self.config.get("libtorrent/dht")), "enable_lsd": int(self.config.get("libtorrent/lsd")), - "enable_natpmp": int(self.config.get("libtorrent/natpmp"))} + "enable_natpmp": int(self.config.get("libtorrent/natpmp")), + "allow_i2p_mixed": 1} # Copy construct so we don't modify the default list extensions = list(DEFAULT_LT_EXTENSIONS) @@ -633,13 +636,8 @@ async def start_download_from_uri(self, uri: str, config: DownloadConfig | None if scheme == "magnet": logger.info("Magnet scheme detected") params = lt.parse_magnet_uri(uri) - try: - # libtorrent 1.2.19 - name, infohash = params["name"].encode(), params["info_hash"] # type: ignore[index] # (checker is 2.X) - except TypeError: - # libtorrent 2.0.9 - name = params.name.encode() - infohash = unhexlify(str(params.info_hash)) + name = params.name.encode() + infohash = unhexlify(str(params.info_hash)) logger.info("Name: %s. Infohash: %s", name, infohash) if infohash in self.metainfo_cache: logger.info("Metainfo found in cache") @@ -872,7 +870,7 @@ def get_download(self, infohash: bytes) -> Download | None: """ return self.downloads.get(infohash, None) - def get_downloads(self) -> List[Download]: + def get_downloads(self) -> list[Download]: """ Get a list of all known downloads. """ diff --git a/src/tribler/core/libtorrent/restapi/torrentinfo_endpoint.py b/src/tribler/core/libtorrent/restapi/torrentinfo_endpoint.py index 53a9113b96..01133f515e 100644 --- a/src/tribler/core/libtorrent/restapi/torrentinfo_endpoint.py +++ b/src/tribler/core/libtorrent/restapi/torrentinfo_endpoint.py @@ -6,7 +6,7 @@ from binascii import hexlify, unhexlify from copy import deepcopy from ssl import SSLError -from typing import TYPE_CHECKING, Iterable +from typing import TYPE_CHECKING import libtorrent as lt from aiohttp import ( @@ -36,6 +36,8 @@ ) if TYPE_CHECKING: + from collections.abc import Iterable + from aiohttp.abc import Request from aiohttp.typedefs import LooseHeaders @@ -181,12 +183,7 @@ async def get_torrent_info(self, request: Request) -> RESTResponse: # noqa: C90 if response.startswith(b'magnet'): try: - try: - # libtorrent 1.2.19 - infohash = lt.parse_magnet_uri(uri)["info_hash"] # type: ignore[index] # (checker uses 2.X) - except TypeError: - # libtorrent 2.0.9 - infohash = unhexlify(str(lt.parse_magnet_uri(uri).info_hash)) + infohash = unhexlify(str(lt.parse_magnet_uri(uri).info_hash)) except RuntimeError as e: return RESTResponse( {"error": { @@ -203,12 +200,7 @@ async def get_torrent_info(self, request: Request) -> RESTResponse: # noqa: C90 self._logger.info("magnet scheme detected") try: - try: - # libtorrent 1.2.19 - infohash = lt.parse_magnet_uri(uri)["info_hash"] # type: ignore[index] # (checker uses 2.X) - except TypeError: - # libtorrent 2.0.9 - infohash = unhexlify(str(lt.parse_magnet_uri(uri).info_hash)) + infohash = unhexlify(str(lt.parse_magnet_uri(uri).info_hash)) except RuntimeError as e: return RESTResponse( {"error": { diff --git a/src/tribler/test_unit/core/libtorrent/restapi/test_torrentinfo_endpoint.py b/src/tribler/test_unit/core/libtorrent/restapi/test_torrentinfo_endpoint.py index 8eba5aed63..5f782cc7f6 100644 --- a/src/tribler/test_unit/core/libtorrent/restapi/test_torrentinfo_endpoint.py +++ b/src/tribler/test_unit/core/libtorrent/restapi/test_torrentinfo_endpoint.py @@ -4,6 +4,7 @@ from ssl import SSLError from unittest.mock import AsyncMock, Mock, patch +import libtorrent from aiohttp import ClientConnectorCertificateError, ClientConnectorError, ClientResponseError, ServerConnectionError from ipv8.test.base import TestBase from ipv8.test.REST.rest_base import MockRequest, response_to_json @@ -167,9 +168,10 @@ async def test_get_torrent_info_magnet_no_metainfo(self) -> None: """ self.download_manager.get_metainfo = AsyncMock(return_value=None) request = MockRequest("/api/torrentinfo", query={"hops": 0, "uri": "magnet://"}) + alert = Mock(info_hash=libtorrent.sha1_hash(b"\x01" * 20)) with patch.dict(tribler.core.libtorrent.restapi.torrentinfo_endpoint.__dict__, - {"lt": Mock(parse_magnet_uri=Mock(return_value={"info_hash": b"\x01" * 20}))}): + {"lt": Mock(parse_magnet_uri=Mock(return_value=alert))}): response = await self.endpoint.get_torrent_info(request) response_body_json = await response_to_json(response) @@ -436,13 +438,14 @@ async def test_get_torrent_info_http_redirect_magnet_no_metainfo(self) -> None: """ self.download_manager.get_metainfo = AsyncMock(return_value=None) request = MockRequest("/api/torrentinfo", query={"hops": 0, "uri": "https://127.0.0.1/file"}) + alert = Mock(info_hash=libtorrent.sha1_hash(b"\x01" * 20)) with patch.dict(tribler.core.libtorrent.restapi.torrentinfo_endpoint.__dict__, {"unshorten": mock_unshorten}), \ patch("tribler.core.libtorrent.restapi.torrentinfo_endpoint.query_uri", AsyncMock(return_value=b"magnet://")), \ patch.dict(tribler.core.libtorrent.restapi.torrentinfo_endpoint.__dict__, - {"lt": Mock(parse_magnet_uri=Mock(return_value={"info_hash": b"\x01" * 20}))}): + {"lt": Mock(parse_magnet_uri=Mock(return_value=alert))}): response = await self.endpoint.get_torrent_info(request) response_body_json = await response_to_json(response) @@ -459,13 +462,14 @@ async def test_get_torrent_info_https_redirect_magnet_no_metainfo(self) -> None: """ self.download_manager.get_metainfo = AsyncMock(return_value=None) request = MockRequest("/api/torrentinfo", query={"hops": 0, "uri": "https://127.0.0.1/file"}) + alert = Mock(info_hash=libtorrent.sha1_hash(b"\x01" * 20)) with patch.dict(tribler.core.libtorrent.restapi.torrentinfo_endpoint.__dict__, {"unshorten": mock_unshorten}), \ patch("tribler.core.libtorrent.restapi.torrentinfo_endpoint.query_uri", AsyncMock(return_value=b"magnet://")), \ patch.dict(tribler.core.libtorrent.restapi.torrentinfo_endpoint.__dict__, - {"lt": Mock(parse_magnet_uri=Mock(return_value={"info_hash": b"\x01" * 20}))}): + {"lt": Mock(parse_magnet_uri=Mock(return_value=alert))}): response = await self.endpoint.get_torrent_info(request) response_body_json = await response_to_json(response)