Skip to content

Commit

Permalink
Allow magnet links to resolve later when adding URIs (#8418)
Browse files Browse the repository at this point in the history
  • Loading branch information
qstokkink authored Jan 28, 2025
2 parents 9578689 + c1e6f7e commit 4d7cd97
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 14 deletions.
32 changes: 28 additions & 4 deletions src/tribler/core/libtorrent/restapi/torrentinfo_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,23 @@ def __init__(self, download_manager: DownloadManager) -> None:
summary="Return metainfo from a torrent found at a provided URI.",
parameters=[{
"in": "query",
"name": "torrent",
"name": "uri",
"description": "URI for which to return torrent information. This URI can either represent "
"a file location, a magnet link or a HTTP(S) url.",
"type": "string",
"required": True
}, {
"in": "query",
"name": "hops",
"description": "The number of anonymization hops to use.",
"type": "number",
"required": False
}, {
"in": "query",
"name": "skipmagnet",
"description": "Don't resolve magnet link metainfo, if you want an immediate response.",
"type": "boolean",
"required": False
}],
responses={
200: {
Expand All @@ -129,6 +141,7 @@ async def get_torrent_info(self, request: Request) -> RESTResponse: # noqa: C90
hops = params.get("hops")
i_hops = 0
p_uri = params.get("uri")
skip_check_metainfo = params.get("skipmagnet", "false") in ["true", "1"]
self._logger.info("URI: %s", p_uri)
if hops:
try:
Expand All @@ -154,6 +167,7 @@ async def get_torrent_info(self, request: Request) -> RESTResponse: # noqa: C90
try:
tdef = await TorrentDef.load(file_path)
metainfo = tdef.metainfo
skip_check_metainfo = False
except (OSError, TypeError, ValueError, RuntimeError):
return RESTResponse({"error": {
"handled": True,
Expand Down Expand Up @@ -192,11 +206,15 @@ async def get_torrent_info(self, request: Request) -> RESTResponse: # noqa: C90
}}, status=HTTP_INTERNAL_SERVER_ERROR
)

metainfo = await self.download_manager.get_metainfo(infohash, timeout=60, hops=i_hops,
url=response.decode())
if skip_check_metainfo:
metainfo = None
else:
metainfo = await self.download_manager.get_metainfo(infohash, timeout=60, hops=i_hops,
url=response.decode())
else:
try:
metainfo = lt.bdecode(response)
skip_check_metainfo = False
except RuntimeError:
return RESTResponse(
{"error": {
Expand All @@ -216,13 +234,19 @@ async def get_torrent_info(self, request: Request) -> RESTResponse: # noqa: C90
"message": f'Error while getting an infohash from magnet: {e.__class__.__name__}: {e}'
}}, status=HTTP_BAD_REQUEST
)
metainfo = await self.download_manager.get_metainfo(infohash, timeout=60, hops=i_hops, url=uri)
if skip_check_metainfo:
metainfo = None
else:
metainfo = await self.download_manager.get_metainfo(infohash, timeout=60, hops=i_hops, url=uri)
else:
return RESTResponse({"error": {
"handled": True,
"message": "invalid uri"
}}, status=HTTP_BAD_REQUEST)

if skip_check_metainfo:
return RESTResponse({"metainfo": "", "download_exists": False, "valid_certificate": True})

if not metainfo:
return RESTResponse({"error": {
"handled": True,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,24 @@ async def test_get_torrent_info_magnet_no_metainfo(self) -> None:
self.assertEqual(0, self.download_manager.get_metainfo.call_args.kwargs["hops"])
self.assertEqual("magnet://", self.download_manager.get_metainfo.call_args.kwargs["url"])

async def test_get_torrent_info_magnet_skip_metainfo(self) -> None:
"""
Test if an empty response is returned when no metainfo is available for a magnet and it is skipped.
"""
self.download_manager.get_metainfo = AsyncMock(side_effect=AssertionError)
request = MockRequest("/api/torrentinfo", query={"hops": 0, "uri": "magnet:", "skipmagnet": "true"})
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=alert))}):
response = await self.endpoint.get_torrent_info(request)
response_body_json = await response_to_json(response)

self.assertEqual(200, response.status)
self.assertEqual("", response_body_json["metainfo"])
self.assertFalse(response_body_json["download_exists"])
self.assertTrue(response_body_json["valid_certificate"])

async def test_get_torrent_info_http_serverconnectionerror(self) -> None:
"""
Test if a graceful error is returned when a ServerConnectionError occurs when loading from an HTTP link.
Expand Down
16 changes: 9 additions & 7 deletions src/tribler/ui/src/components/add-torrent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,15 @@ export function AddTorrent() {
setTorrent(undefined);
setUrlDialogOpen(false);
(async () => {
const response = await triblerService.getMetainfo(uriInput);
if (response === undefined) {
toast.error(`${t("ToastErrorDownloadStart")} ${t("ToastErrorGenNetworkErr")}`);
} else if (isErrorDict(response)){
toast.error(`${t("ToastErrorDownloadStart")} ${response.error.message}`);
} else {
setSaveAsDialogOpen(true);
if (uriInputRef.current !== null) {
const response = await triblerService.getMetainfo(uriInputRef.current.value, true);
if (response === undefined) {
toast.error(`${t("ToastErrorDownloadStart")} ${t("ToastErrorGenNetworkErr")}`);
} else if (isErrorDict(response)){
toast.error(`${t("ToastErrorDownloadStart")} ${response.error.message}`);
} else {
setSaveAsDialogOpen(true);
}
}
})();
}
Expand Down
2 changes: 1 addition & 1 deletion src/tribler/ui/src/dialogs/SaveAs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ export default function SaveAs(props: SaveAsProps & JSX.IntrinsicAttributes & Di
response = await triblerService.getMetainfoFromFile(torrent);
}
else if (uri) {
response = await triblerService.getMetainfo(uri);
response = await triblerService.getMetainfo(uri, false);
}

if (response === undefined) {
Expand Down
4 changes: 2 additions & 2 deletions src/tribler/ui/src/services/tribler.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,9 +228,9 @@ export class TriblerService {

// Torrents / search

async getMetainfo(uri: string): Promise<undefined | ErrorDict | {metainfo: string, download_exists: boolean, valid_certificate: boolean}> {
async getMetainfo(uri: string, skipMagnet: boolean): Promise<undefined | ErrorDict | {metainfo: string, download_exists: boolean, valid_certificate: boolean}> {
try {
return (await this.http.get(`/torrentinfo?uri=${uri}`)).data;
return (await this.http.get(`/torrentinfo?uri=${uri}&skipmagnet=${skipMagnet}`)).data;
} catch (error) {
return formatAxiosError(error as Error | AxiosError);
}
Expand Down

0 comments on commit 4d7cd97

Please sign in to comment.