Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added download callbacks for hash checking and metadata #8449

Merged
merged 3 commits into from
Feb 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions src/tribler/core/libtorrent/download_manager/download.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,12 @@ def __init__(self, # noqa: PLR0913
self.future_finished = self.wait_for_alert("torrent_finished_alert")
self.future_metainfo = self.wait_for_alert("metadata_received_alert", lambda a: self.tdef.get_metainfo())

if self.download_manager.config.get("libtorrent/check_after_complete"):
self.register_task("Recheck torrent after finish", self._recheck_after_finish)

if config and config.get_stop_after_metainfo():
self.stop_after_metainfo()

alert_handlers = {"tracker_reply_alert": self.on_tracker_reply_alert,
"tracker_error_alert": self.on_tracker_error_alert,
"tracker_warning_alert": self.on_tracker_warning_alert,
Expand Down Expand Up @@ -173,6 +179,25 @@ def __repr__(self) -> str:
"""
return self.__str__()

async def _recheck_after_finish(self) -> None:
"""
Wait for the torrent to finish downloading, then recheck.

Note: a finished recheck causes a ``torrent_finished_alert``: hooking into that causes an infinite loop!
"""
await self.future_finished
self.force_recheck()

@task
async def stop_after_metainfo(self) -> None:
"""
Wait for the metadata to be received, then stop.
"""
self.config.set_stop_after_metainfo(True) # Persist between restarts
await self.future_metainfo
await self.stop()
self.config.set_stop_after_metainfo(False) # We succeeded without shutdown: no longer persist

def add_stream(self) -> None:
"""
Initialize a stream for this download.
Expand Down
14 changes: 14 additions & 0 deletions src/tribler/core/libtorrent/download_manager/download_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class DownloadConfigDefaultsSection(TypedDict):
add_download_to_channel: bool
saveas: str | None
completed_dir: str | None
stop_after_metainfo: bool


class StateConfigSection(TypedDict):
Expand Down Expand Up @@ -78,6 +79,7 @@ def write(self) -> None: ... # noqa: D102
add_download_to_channel = boolean(default=False)
saveas = string(default=None)
completed_dir = string(default=None)
stop_after_metainfo = boolean(default=False)

[state]
metainfo = string(default='ZGU=')
Expand Down Expand Up @@ -312,3 +314,15 @@ def get_engineresumedata(self) -> dict | None:
Get the engine resume data dict for this download or None if it cannot be decoded.
"""
return _to_dict(self.config["state"]["engineresumedata"])

def set_stop_after_metainfo(self, value: bool) -> None:
"""
Set the download to stop after receiving the metainfo.
"""
self.config["download_defaults"]["stop_after_metainfo"] = value

def get_stop_after_metainfo(self) -> bool:
"""
Get whether the download should stop after receiving the metainfo.
"""
return self.config["download_defaults"].get("stop_after_metainfo", False)
25 changes: 17 additions & 8 deletions src/tribler/core/libtorrent/restapi/downloads_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,22 +394,29 @@ def _get_default_trackers(self) -> list[bytes]:
summary="Start a download from a provided URI.",
parameters=[{
"in": "query",
"name": "get_peers",
"description": "Flag indicating whether or not to include peers",
"type": "boolean",
"name": "anon_hops",
"description": "Number of hops for the anonymous download. No hops is equivalent to a plain download",
"type": "integer",
"required": False
},
{
"in": "query",
"name": "get_pieces",
"description": "Flag indicating whether or not to include pieces",
"name": "safe_seeding",
"description": "Whether the seeding of the download should be anonymous or not",
"type": "boolean",
"required": False
},
{
"in": "query",
"name": "get_files",
"description": "Flag indicating whether or not to include files",
"name": "destination",
"description": "The download destination path of the torrent",
"type": "string",
"required": False
},
{
"in": "query",
"name": "only_metadata",
"description": "Stop the download after the metadata has been received",
"type": "boolean",
"required": False
}],
Expand All @@ -423,7 +430,7 @@ def _get_default_trackers(self) -> list[bytes]:
@json_schema(schema(AddDownloadRequest={
"anon_hops": (Integer, "Number of hops for the anonymous download. No hops is equivalent to a plain download"),
"safe_seeding": (Boolean, "Whether the seeding of the download should be anonymous or not"),
"destination": (String, "the download destination path of the torrent"),
"destination": (String, "The download destination path of the torrent"),
"uri*": (String, "The URI of the torrent file that should be downloaded. This URI can either represent a file "
"location, a magnet link or a HTTP(S) url."),
}))
Expand Down Expand Up @@ -471,6 +478,8 @@ async def add_download(self, request: Request) -> RESTResponse: # noqa: C901, P
if self.download_manager.config.get("libtorrent/download_defaults/trackers_file"):
await download.get_handle() # We can only add trackers to a valid handle, wait for it.
download.add_trackers(self._get_default_trackers())
if params.get("only_metadata", "false") != "false":
download.stop_after_metainfo()
except Exception as e:
return RESTResponse({"error": {
"handled": True,
Expand Down
Loading