Skip to content

Commit ddb5c59

Browse files
committed
Replace tdef innards with ATP
1 parent d325408 commit ddb5c59

23 files changed

+417
-1282
lines changed

requirements.txt

+2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
-r pyipv8/requirements.txt
22

3+
aiohttp==3.11.16
34
bitarray
45
configobj
56
ipv8-rust-tunnels
67
libtorrent==2.0.11
78
lz4
9+
marshmallow==3.26.1
810
pillow
911
pony
1012
pystray

src/tribler/core/database/orm_bindings/torrent_metadata.py

+6-8
Original file line numberDiff line numberDiff line change
@@ -92,20 +92,18 @@ def tdef_to_metadata_dict(tdef: TorrentDef) -> dict:
9292
tags = "Unknown"
9393

9494
try:
95-
torrent_date = datetime.fromtimestamp(tdef.get_creation_date()) # noqa: DTZ006
95+
creation_time = tdef.torrent_info.creation_date() if tdef.torrent_info else tdef.atp.added_time
96+
torrent_date = datetime.fromtimestamp(creation_time) # noqa: DTZ006
9697
except (ValueError, TypeError):
9798
torrent_date = EPOCH
9899

99-
tracker = tdef.get_tracker()
100-
if not isinstance(tracker, bytes):
101-
tracker = b""
102-
tracker_url = tracker.decode()
100+
tracker_url = tdef.atp.trackers[0] if tdef.atp.trackers else ""
103101
tracker_info = get_uniformed_tracker_url(tracker_url) or ''
104102
return {
105-
"infohash": tdef.get_infohash(),
106-
"title": tdef.get_name_as_unicode()[:300],
103+
"infohash": tdef.infohash,
104+
"title": tdef.name[:300],
107105
"tags": tags[:200],
108-
"size": tdef.get_length(),
106+
"size": tdef.torrent_info.total_size() if tdef.torrent_info else 0,
109107
"torrent_date": max(torrent_date, EPOCH),
110108
"tracker_info": tracker_info,
111109
}

src/tribler/core/libtorrent/download_manager/download.py

+35-33
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import base64
1010
import itertools
1111
import logging
12-
from asyncio import CancelledError, Future, get_running_loop, sleep, wait_for
12+
from asyncio import CancelledError, Future, sleep, wait_for
1313
from binascii import hexlify
1414
from collections import defaultdict
1515
from collections.abc import Callable
@@ -27,7 +27,7 @@
2727
from tribler.core.libtorrent.download_manager.download_state import DownloadState, DownloadStatus
2828
from tribler.core.libtorrent.download_manager.stream import Stream
2929
from tribler.core.libtorrent.torrent_file_tree import TorrentFileTree
30-
from tribler.core.libtorrent.torrentdef import MetainfoDict, TorrentDef, TorrentDefNoMetainfo
30+
from tribler.core.libtorrent.torrentdef import TorrentDef
3131
from tribler.core.libtorrent.torrents import check_handle, get_info_from_handle, require_handle
3232
from tribler.core.notifier import Notification, Notifier
3333
from tribler.tribler_config import TriblerConfigManager
@@ -36,6 +36,7 @@
3636
from collections.abc import Awaitable
3737

3838
from tribler.core.libtorrent.download_manager.download_manager import DownloadManager
39+
from tribler.core.libtorrent.torrentdef import MetainfoDict
3940

4041
Getter = Callable[[Any], Any]
4142

@@ -162,15 +163,15 @@ def __init__(self, # noqa: PLR0913
162163
elif config is None:
163164
self.config = DownloadConfig.from_defaults(TriblerConfigManager())
164165

165-
self._logger.debug("Setup: %s", hexlify(self.tdef.get_infohash()).decode())
166+
self._logger.debug("Setup: %s", hexlify(self.tdef.infohash).decode())
166167

167168
self.checkpoint()
168169

169170
def __str__(self) -> str:
170171
"""
171172
Convert this download to a human-readable string.
172173
"""
173-
return (f"Download(name={self.tdef.get_name()}, "
174+
return (f"Download(name={self.tdef.name}, "
174175
f"hops={self.config.get_hops():d}, "
175176
f"checkpoint_disabled={self.checkpoint_disabled:d})")
176177

@@ -282,7 +283,7 @@ def get_atp(self) -> dict:
282283
atp["flags"] = cast("int", atp["flags"]) | lt.add_torrent_params_flags_t.flag_upload_mode
283284

284285
resume_data = self.config.get_engineresumedata()
285-
if not isinstance(self.tdef, TorrentDefNoMetainfo):
286+
if self.tdef.torrent_info is not None:
286287
metainfo = self.tdef.get_metainfo()
287288
torrentinfo = lt.torrent_info(metainfo)
288289

@@ -295,8 +296,8 @@ def get_atp(self) -> dict:
295296
resume_data[b"save_path"] = str(self.state_dir / save_path)
296297
atp["resume_data"] = lt.bencode(resume_data)
297298
else:
298-
atp["url"] = self.tdef.get_url() or "magnet:?xt=urn:btih:" + hexlify(self.tdef.get_infohash()).decode()
299-
atp["name"] = self.tdef.get_name_as_unicode()
299+
atp["url"] = self.tdef.atp.url or "magnet:?xt=urn:btih:" + hexlify(self.tdef.infohash).decode()
300+
atp["name"] = self.tdef.atp.name
300301

301302
return atp
302303

@@ -307,7 +308,7 @@ def on_add_torrent_alert(self, alert: lt.add_torrent_alert) -> None:
307308
self._logger.info("On add torrent alert: %s", repr(alert))
308309

309310
if hasattr(alert, "error") and alert.error.value():
310-
self._logger.error("Failed to add torrent (%s)", self.tdef.get_name_as_unicode())
311+
self._logger.error("Failed to add torrent (%s)", self.tdef.name)
311312
raise RuntimeError(alert.error.message())
312313
if not alert.handle.is_valid():
313314
self._logger.error("Received invalid torrent handle")
@@ -405,11 +406,11 @@ def on_state_changed_alert(self, alert: lt.state_changed_alert) -> None:
405406
self.update_lt_status(self.handle.status())
406407

407408
enable = alert.state == lt.torrent_status.seeding and self.config.get_hops() > 0
408-
self._logger.debug("Setting IP filter for %s to %s", hexlify(self.tdef.get_infohash()), enable)
409+
self._logger.debug("Setting IP filter for %s to %s", hexlify(self.tdef.infohash), enable)
409410
self.apply_ip_filter(enable)
410411

411412
# On a rare occasion we don't get a metadata_received_alert. If this is the case, post an alert manually.
412-
if alert.state == lt.torrent_status.downloading and isinstance(self.tdef, TorrentDefNoMetainfo):
413+
if alert.state == lt.torrent_status.downloading and self.tdef.torrent_info is None:
413414
self.post_alert("metadata_received_alert")
414415

415416
def on_save_resume_data_alert(self, alert: lt.save_resume_data_alert) -> None:
@@ -429,22 +430,22 @@ def on_save_resume_data_alert(self, alert: lt.save_resume_data_alert) -> None:
429430
save_path = Path(resume_data[b"save_path"].decode()).absolute()
430431
resume_data[b"save_path"] = str(save_path)
431432

432-
if not isinstance(self.tdef, TorrentDefNoMetainfo):
433+
if self.tdef.torrent_info is not None:
433434
self.config.set_metainfo(self.tdef.get_metainfo())
434435
else:
435436
self.config.set_metainfo({
436-
"infohash": self.tdef.get_infohash(),
437-
"name": self.tdef.get_name_as_unicode(),
438-
"url": self.tdef.get_url()
437+
"infohash": self.tdef.infohash,
438+
"name": self.tdef.name,
439+
"url": self.tdef.atp.url
439440
})
440441
self.config.set_engineresumedata(resume_data)
441442

442443
# Save it to file
443444
# Note resume_data[b"info-hash"] can be b"\x00" * 32, so we use the tdef.
444-
basename = hexlify(self.tdef.get_infohash()).decode() + ".conf"
445+
basename = hexlify(self.tdef.infohash).decode() + ".conf"
445446
Path(self.download_manager.get_checkpoint_dir()).mkdir(parents=True, exist_ok=True)
446447
filename = self.download_manager.get_checkpoint_dir() / basename
447-
self.config.config["download_defaults"]["name"] = self.tdef.get_name_as_unicode() # store name (for debugging)
448+
self.config.config["download_defaults"]["name"] = self.tdef.name # store name (for debugging)
448449
try:
449450
self.config.write(filename)
450451
except OSError as e:
@@ -533,7 +534,8 @@ def on_metadata_received_alert(self, alert: lt.metadata_received_alert) -> None:
533534
self.set_def(TorrentDef.load_from_dict(metadata))
534535
with suppress(RuntimeError):
535536
# Try to load the torrent info in the background if we have a loop.
536-
get_running_loop().run_in_executor(None, self.tdef.load_torrent_info)
537+
self.register_anonymous_task(f"Load torrent info for {self.tdef.infohash.hex()}",
538+
self.tdef.load_torrent_info)
537539
except ValueError as ve:
538540
self._logger.exception(ve)
539541
return
@@ -573,7 +575,7 @@ def on_torrent_removed_alert(self, alert: lt.torrent_removed_alert) -> None:
573575
"""
574576
self._logger.info("On torrent remove alert: %s", repr(alert))
575577

576-
self._logger.debug("Removing %s", self.tdef.get_name())
578+
self._logger.debug("Removing %s", self.tdef.name)
577579
self.handle = None
578580

579581
def on_torrent_checked_alert(self, alert: lt.torrent_checked_alert) -> None:
@@ -600,8 +602,8 @@ def on_torrent_finished_alert(self, alert: lt.torrent_finished_alert) -> None:
600602
self.checkpoint()
601603
downloaded = self.get_state().total_download
602604
if downloaded > 0 and self.notifier is not None:
603-
name = self.tdef.get_name_as_unicode()
604-
infohash = self.tdef.get_infohash().hex()
605+
name = self.tdef.name
606+
infohash = self.tdef.infohash.hex()
605607
self.notifier.notify(Notification.torrent_finished, infohash=infohash, name=name, hidden=self.hidden)
606608

607609
if self.config.get_completed_dir() and self.config.get_completed_dir() != self.config.get_dest_dir():
@@ -619,7 +621,7 @@ def update_lt_status(self, lt_status: lt.torrent_status) -> None:
619621
# Notify the GUI if the status has changed
620622
if self.notifier and not self.hidden and state.get_status() != old_status:
621623
self.notifier.notify(Notification.torrent_status_changed,
622-
infohash=hexlify(self.tdef.get_infohash()).decode(),
624+
infohash=hexlify(self.tdef.infohash).decode(),
623625
status=state.get_status().name)
624626

625627
if state.get_status() == DownloadStatus.SEEDING:
@@ -639,7 +641,7 @@ def set_selected_files(self, selected_files: list[int] | None = None, prio: int
639641
"""
640642
if not force and self.stream is not None:
641643
return None
642-
if not isinstance(self.tdef, TorrentDefNoMetainfo) and not self.get_share_mode():
644+
if self.tdef.torrent_info is not None and not self.get_share_mode():
643645
if selected_files is None:
644646
selected_files = self.config.get_selected_files()
645647
else:
@@ -667,7 +669,7 @@ def move_storage(self, new_dir: Path) -> bool:
667669
"""
668670
Move the output files to a different location.
669671
"""
670-
if not isinstance(self.tdef, TorrentDefNoMetainfo):
672+
if self.tdef.torrent_info is not None:
671673
self.handle = cast("lt.torrent_handle", self.handle)
672674
self.handle.move_storage(str(new_dir))
673675
self.config.set_dest_dir(new_dir)
@@ -679,7 +681,7 @@ def force_recheck(self) -> None:
679681
"""
680682
Force libtorrent to validate the files.
681683
"""
682-
if not isinstance(self.tdef, TorrentDefNoMetainfo):
684+
if self.tdef.torrent_info is not None:
683685
self.handle = cast("lt.torrent_handle", self.handle)
684686
if self.get_state().get_status() == DownloadStatus.STOPPED:
685687
self.pause_after_next_hashcheck = True
@@ -813,7 +815,7 @@ def get_tracker_status(self) -> dict[str, tuple[int, str]]:
813815
pex_peers += 1
814816

815817
ltsession = self.download_manager.get_session(self.config.get_hops()).result()
816-
public = self.tdef and not self.tdef.is_private()
818+
public = not (self.tdef and self.tdef.torrent_info and self.tdef.atp.ti.priv())
817819

818820
result = self.tracker_status.copy()
819821
result["[DHT]"] = (dht_peers, "Working" if ltsession.is_dht_running() and public else "Disabled")
@@ -841,7 +843,7 @@ def stop(self, user_stopped: bool | None = None) -> Awaitable[None]:
841843
"""
842844
Stop downloading the download.
843845
"""
844-
self._logger.debug("Stopping %s", self.tdef.get_name())
846+
self._logger.debug("Stopping %s", self.tdef.name)
845847
if self.stream is not None:
846848
self.stream.close()
847849
if user_stopped is not None:
@@ -855,7 +857,7 @@ def resume(self) -> None:
855857
"""
856858
Resume downloading the download.
857859
"""
858-
self._logger.debug("Resuming %s", self.tdef.get_name())
860+
self._logger.debug("Resuming %s", self.tdef.name)
859861

860862
self.config.set_user_stopped(False)
861863

@@ -867,7 +869,7 @@ def get_content_dest(self) -> Path:
867869
"""
868870
Returns the file to which the downloaded content is saved.
869871
"""
870-
return self.config.get_dest_dir() / self.tdef.get_name_as_unicode()
872+
return self.config.get_dest_dir() / self.tdef.name
871873

872874
def checkpoint(self) -> Awaitable[None]:
873875
"""
@@ -884,15 +886,15 @@ def checkpoint(self) -> Awaitable[None]:
884886
if not self.handle or not self.handle.is_valid():
885887
# Libtorrent hasn't received or initialized this download yet
886888
# 1. Check if we have data for this infohash already (don't overwrite it if we do!)
887-
basename = hexlify(self.tdef.get_infohash()).decode() + ".conf"
889+
basename = hexlify(self.tdef.infohash).decode() + ".conf"
888890
filename = Path(self.download_manager.get_checkpoint_dir() / basename)
889891
if not filename.is_file():
890892
# 2. If there is no saved data for this infohash, checkpoint it without data so we do not
891893
# lose it when we crash or restart before the download becomes known.
892894
resume_data = self.config.get_engineresumedata() or {
893895
b"file-format": b"libtorrent resume file",
894896
b"file-version": 1,
895-
b"info-hash": self.tdef.get_infohash()
897+
b"info-hash": self.tdef.infohash
896898
}
897899
self.post_alert("save_resume_data_alert", {"resume_data": resume_data})
898900
return succeed(None)
@@ -902,10 +904,10 @@ def set_def(self, tdef: TorrentDef) -> None:
902904
"""
903905
Set the torrent definition for this download.
904906
"""
905-
if (isinstance(self.tdef, TorrentDefNoMetainfo) and not isinstance(tdef, TorrentDefNoMetainfo)
906-
and len(self.tdef.infohash) != 20):
907+
if (self.tdef.torrent_info is None and tdef.torrent_info is not None
908+
and len(self.tdef.atp.info_hash.to_bytes()) != 20):
907909
# We store SHA-1 conf files. v2 torrents start with SHA-256 infohashes.
908-
basename = hexlify(self.tdef.get_infohash()).decode() + ".conf"
910+
basename = hexlify(self.tdef.atp.info_hash.to_bytes()).decode() + ".conf"
909911
Path(self.download_manager.get_checkpoint_dir() / basename).unlink(missing_ok=True)
910912
self.tdef = tdef
911913

0 commit comments

Comments
 (0)