Add WebAPI for managing torrent webseeds

Closes #18465.
PR #21043.
This commit is contained in:
Thomas Piccirello 2024-08-11 00:58:56 -07:00 committed by GitHub
parent 5afeecbf18
commit ea06eb9fe6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 100 additions and 0 deletions

View file

@ -135,6 +135,8 @@ namespace
using Utils::String::parseInt;
using Utils::String::parseDouble;
const QSet<QString> SUPPORTED_WEB_SEED_SCHEMES {u"http"_s, u"https"_s, u"ftp"_s};
void applyToTorrents(const QStringList &idList, const std::function<void (BitTorrent::Torrent *torrent)> &func)
{
if ((idList.size() == 1) && (idList[0] == u"all"))
@ -252,6 +254,20 @@ namespace
idList << BitTorrent::TorrentID::fromString(hash);
return idList;
}
nonstd::expected<QUrl, QString> validateWebSeedUrl(const QString &urlStr)
{
const QString normalizedUrlStr = QUrl::fromPercentEncoding(urlStr.toLatin1());
const QUrl url {normalizedUrlStr, QUrl::StrictMode};
if (!url.isValid())
return nonstd::make_unexpected(TorrentsController::tr("\"%1\" is not a valid URL").arg(normalizedUrlStr));
if (!SUPPORTED_WEB_SEED_SCHEMES.contains(url.scheme()))
return nonstd::make_unexpected(TorrentsController::tr("URL scheme must be one of [%1]").arg(SUPPORTED_WEB_SEED_SCHEMES.values().join(u", ")));
return url;
}
}
void TorrentsController::countAction()
@ -560,6 +576,84 @@ void TorrentsController::webseedsAction()
setResult(webSeedList);
}
void TorrentsController::addWebSeedsAction()
{
requireParams({u"hash"_s, u"urls"_s});
const QStringList paramUrls = params()[u"urls"_s].split(u'|', Qt::SkipEmptyParts);
const auto id = BitTorrent::TorrentID::fromString(params()[u"hash"_s]);
BitTorrent::Torrent *const torrent = BitTorrent::Session::instance()->getTorrent(id);
if (!torrent)
throw APIError(APIErrorType::NotFound);
QList<QUrl> urls;
urls.reserve(paramUrls.size());
for (const QString &urlStr : paramUrls)
{
const auto result = validateWebSeedUrl(urlStr);
if (!result)
throw APIError(APIErrorType::BadParams, result.error());
urls << result.value();
}
torrent->addUrlSeeds(urls);
}
void TorrentsController::editWebSeedAction()
{
requireParams({u"hash"_s, u"origUrl"_s, u"newUrl"_s});
const auto id = BitTorrent::TorrentID::fromString(params()[u"hash"_s]);
const QString origUrlStr = params()[u"origUrl"_s];
const QString newUrlStr = params()[u"newUrl"_s];
BitTorrent::Torrent *const torrent = BitTorrent::Session::instance()->getTorrent(id);
if (!torrent)
throw APIError(APIErrorType::NotFound);
const auto origUrlResult = validateWebSeedUrl(origUrlStr);
if (!origUrlResult)
throw APIError(APIErrorType::BadParams, origUrlResult.error());
const QUrl origUrl = origUrlResult.value();
const auto newUrlResult = validateWebSeedUrl(newUrlStr);
if (!newUrlResult)
throw APIError(APIErrorType::BadParams, newUrlResult.error());
const QUrl newUrl = newUrlResult.value();
if (newUrl != origUrl)
{
if (!torrent->urlSeeds().contains(origUrl))
throw APIError(APIErrorType::Conflict, tr("\"%1\" is not an existing URL").arg(origUrl.toString()));
torrent->removeUrlSeeds({origUrl});
torrent->addUrlSeeds({newUrl});
}
}
void TorrentsController::removeWebSeedsAction()
{
requireParams({u"hash"_s, u"urls"_s});
const QStringList paramUrls = params()[u"urls"_s].split(u'|', Qt::SkipEmptyParts);
const auto id = BitTorrent::TorrentID::fromString(params()[u"hash"_s]);
BitTorrent::Torrent *const torrent = BitTorrent::Session::instance()->getTorrent(id);
if (!torrent)
throw APIError(APIErrorType::NotFound);
QList<QUrl> urls;
urls.reserve(paramUrls.size());
for (const QString &urlStr : paramUrls)
{
const auto result = validateWebSeedUrl(urlStr);
if (!result)
throw APIError(APIErrorType::BadParams, result.error());
urls << result.value();
}
torrent->removeUrlSeeds(urls);
}
// Returns the files in a torrent in JSON format.
// The return value is a JSON-formatted list of dictionaries.
// The dictionary keys are: