refactor: more tr_variant API (#6057)

This commit is contained in:
Charles Kerr 2023-10-02 16:18:35 -05:00 committed by GitHub
parent 917c00e477
commit 32a62d85ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 304 additions and 507 deletions

View File

@ -298,125 +298,220 @@ char const* torrentVerify(tr_session* session, tr_variant* args_in, tr_variant*
// ---
void addLabels(tr_torrent const* tor, tr_variant* list)
namespace make_torrent_field_helpers
{
tr_variantInitList(list, std::size(tor->labels));
for (auto const& label : tor->labels)
[[nodiscard]] auto make_file_wanted_vec(tr_torrent const& tor)
{
auto const n_files = tor.file_count();
auto vec = tr_variant::Vector{};
vec.reserve(n_files);
for (tr_file_index_t idx = 0U; idx != n_files; ++idx)
{
tr_variantListAddQuark(list, label);
vec.emplace_back(tr_torrentFile(&tor, idx).wanted ? 1 : 0);
}
return tr_variant{ std::move(vec) };
}
void addFileStats(tr_torrent const* tor, tr_variant* list)
[[nodiscard]] auto make_labels_vec(tr_torrent const& tor)
{
for (tr_file_index_t i = 0, n = tor->file_count(); i < n; ++i)
auto const n_labels = std::size(tor.labels);
auto labels = tr_variant::Vector{};
labels.reserve(n_labels);
for (auto const& label : tor.labels)
{
auto const file = tr_torrentFile(tor, i);
tr_variant* d = tr_variantListAddDict(list, 3);
tr_variantDictAddInt(d, TR_KEY_bytesCompleted, file.have);
tr_variantDictAddInt(d, TR_KEY_priority, file.priority);
tr_variantDictAddBool(d, TR_KEY_wanted, file.wanted);
labels.emplace_back(tr_variant::unmanaged_string(tr_quark_get_string_view(label)));
}
return tr_variant{ std::move(labels) };
}
void addFiles(tr_torrent const* tor, tr_variant* list)
[[nodiscard]] auto make_file_priorities_vec(tr_torrent const& tor)
{
for (tr_file_index_t i = 0, n = tor->file_count(); i < n; ++i)
auto const n_files = tor.file_count();
auto vec = tr_variant::Vector{};
vec.reserve(n_files);
for (tr_file_index_t idx = 0U; idx != n_files; ++idx)
{
auto const file = tr_torrentFile(tor, i);
tr_variant* d = tr_variantListAddDict(list, 5);
tr_variantDictAddInt(d, TR_KEY_beginPiece, file.beginPiece);
tr_variantDictAddInt(d, TR_KEY_bytesCompleted, file.have);
tr_variantDictAddInt(d, TR_KEY_endPiece, file.endPiece);
tr_variantDictAddInt(d, TR_KEY_length, file.length);
tr_variantDictAddStr(d, TR_KEY_name, file.name);
vec.emplace_back(tr_torrentFile(&tor, idx).priority);
}
return tr_variant{ std::move(vec) };
}
void addWebseeds(tr_torrent const* tor, tr_variant* webseeds)
[[nodiscard]] auto make_file_stats_vec(tr_torrent const& tor)
{
for (size_t i = 0, n = tor->webseed_count(); i < n; ++i)
auto const n_files = tor.file_count();
auto vec = tr_variant::Vector{};
vec.reserve(n_files);
for (tr_file_index_t idx = 0U; idx != n_files; ++idx)
{
tr_variantListAddStr(webseeds, tor->webseed(i));
auto const file = tr_torrentFile(&tor, idx);
auto stats_map = tr_variant::Map{ 3U };
stats_map.try_emplace(TR_KEY_bytesCompleted, file.have);
stats_map.try_emplace(TR_KEY_priority, file.priority);
stats_map.try_emplace(TR_KEY_wanted, file.wanted);
vec.emplace_back(std::move(stats_map));
}
return tr_variant{ std::move(vec) };
}
void addTrackers(tr_torrent const* tor, tr_variant* trackers)
[[nodiscard]] auto make_file_vec(tr_torrent const& tor)
{
for (auto const& tracker : tor->announce_list())
auto const n_files = tor.file_count();
auto vec = tr_variant::Vector{};
vec.reserve(n_files);
for (tr_file_index_t idx = 0U; idx != n_files; ++idx)
{
auto* const d = tr_variantListAddDict(trackers, 5);
tr_variantDictAddQuark(d, TR_KEY_announce, tracker.announce.quark());
tr_variantDictAddInt(d, TR_KEY_id, tracker.id);
tr_variantDictAddQuark(d, TR_KEY_scrape, tracker.scrape.quark());
tr_variantDictAddStrView(d, TR_KEY_sitename, tracker.sitename);
tr_variantDictAddInt(d, TR_KEY_tier, tracker.tier);
auto const file = tr_torrentFile(&tor, idx);
auto file_map = tr_variant::Map{ 5U };
file_map.try_emplace(TR_KEY_beginPiece, file.beginPiece);
file_map.try_emplace(TR_KEY_bytesCompleted, file.have);
file_map.try_emplace(TR_KEY_endPiece, file.endPiece);
file_map.try_emplace(TR_KEY_length, file.length);
file_map.try_emplace(TR_KEY_name, file.name);
vec.emplace_back(std::move(file_map));
}
return tr_variant{ std::move(vec) };
}
void addTrackerStats(tr_tracker_view const& tracker, tr_variant* list)
[[nodiscard]] auto make_webseed_vec(tr_torrent const& tor)
{
auto* const d = tr_variantListAddDict(list, 27);
tr_variantDictAddStr(d, TR_KEY_announce, tracker.announce);
tr_variantDictAddInt(d, TR_KEY_announceState, tracker.announceState);
tr_variantDictAddInt(d, TR_KEY_downloadCount, tracker.downloadCount);
tr_variantDictAddBool(d, TR_KEY_hasAnnounced, tracker.hasAnnounced);
tr_variantDictAddBool(d, TR_KEY_hasScraped, tracker.hasScraped);
tr_variantDictAddStr(d, TR_KEY_host, tracker.host_and_port);
tr_variantDictAddStr(d, TR_KEY_sitename, tracker.sitename);
tr_variantDictAddInt(d, TR_KEY_id, tracker.id);
tr_variantDictAddBool(d, TR_KEY_isBackup, tracker.isBackup);
tr_variantDictAddInt(d, TR_KEY_lastAnnouncePeerCount, tracker.lastAnnouncePeerCount);
tr_variantDictAddStr(d, TR_KEY_lastAnnounceResult, tracker.lastAnnounceResult);
tr_variantDictAddInt(d, TR_KEY_lastAnnounceStartTime, tracker.lastAnnounceStartTime);
tr_variantDictAddBool(d, TR_KEY_lastAnnounceSucceeded, tracker.lastAnnounceSucceeded);
tr_variantDictAddInt(d, TR_KEY_lastAnnounceTime, tracker.lastAnnounceTime);
tr_variantDictAddBool(d, TR_KEY_lastAnnounceTimedOut, tracker.lastAnnounceTimedOut);
tr_variantDictAddStr(d, TR_KEY_lastScrapeResult, tracker.lastScrapeResult);
tr_variantDictAddInt(d, TR_KEY_lastScrapeStartTime, tracker.lastScrapeStartTime);
tr_variantDictAddBool(d, TR_KEY_lastScrapeSucceeded, tracker.lastScrapeSucceeded);
tr_variantDictAddInt(d, TR_KEY_lastScrapeTime, tracker.lastScrapeTime);
tr_variantDictAddBool(d, TR_KEY_lastScrapeTimedOut, tracker.lastScrapeTimedOut);
tr_variantDictAddInt(d, TR_KEY_leecherCount, tracker.leecherCount);
tr_variantDictAddInt(d, TR_KEY_nextAnnounceTime, tracker.nextAnnounceTime);
tr_variantDictAddInt(d, TR_KEY_nextScrapeTime, tracker.nextScrapeTime);
tr_variantDictAddStr(d, TR_KEY_scrape, tracker.scrape);
tr_variantDictAddInt(d, TR_KEY_scrapeState, tracker.scrapeState);
tr_variantDictAddInt(d, TR_KEY_seederCount, tracker.seederCount);
tr_variantDictAddInt(d, TR_KEY_tier, tracker.tier);
}
void addPeers(tr_torrent const* tor, tr_variant* list)
{
auto peer_count = size_t{};
tr_peer_stat* peers = tr_torrentPeers(tor, &peer_count);
tr_variantInitList(list, peer_count);
for (size_t i = 0; i < peer_count; ++i)
auto const n_webseeds = tor.webseed_count();
auto vec = tr_variant::Vector{};
for (size_t idx = 0U; idx != n_webseeds; ++idx)
{
tr_variant* d = tr_variantListAddDict(list, 16);
tr_peer_stat const* peer = peers + i;
tr_variantDictAddStr(d, TR_KEY_address, peer->addr);
tr_variantDictAddStr(d, TR_KEY_clientName, peer->client);
tr_variantDictAddBool(d, TR_KEY_clientIsChoked, peer->clientIsChoked);
tr_variantDictAddBool(d, TR_KEY_clientIsInterested, peer->clientIsInterested);
tr_variantDictAddStr(d, TR_KEY_flagStr, peer->flagStr);
tr_variantDictAddBool(d, TR_KEY_isDownloadingFrom, peer->isDownloadingFrom);
tr_variantDictAddBool(d, TR_KEY_isEncrypted, peer->isEncrypted);
tr_variantDictAddBool(d, TR_KEY_isIncoming, peer->isIncoming);
tr_variantDictAddBool(d, TR_KEY_isUploadingTo, peer->isUploadingTo);
tr_variantDictAddBool(d, TR_KEY_isUTP, peer->isUTP);
tr_variantDictAddBool(d, TR_KEY_peerIsChoked, peer->peerIsChoked);
tr_variantDictAddBool(d, TR_KEY_peerIsInterested, peer->peerIsInterested);
tr_variantDictAddInt(d, TR_KEY_port, peer->port);
tr_variantDictAddReal(d, TR_KEY_progress, peer->progress);
tr_variantDictAddInt(d, TR_KEY_rateToClient, tr_toSpeedBytes(peer->rateToClient_KBps));
tr_variantDictAddInt(d, TR_KEY_rateToPeer, tr_toSpeedBytes(peer->rateToPeer_KBps));
vec.emplace_back(tor.webseed(idx));
}
return tr_variant{ std::move(vec) };
}
[[nodiscard]] auto make_tracker_vec(tr_torrent const& tor)
{
auto const& trackers = tor.announce_list();
auto const n_trackers = std::size(trackers);
auto vec = tr_variant::Vector{};
vec.reserve(n_trackers);
for (auto const& tracker : trackers)
{
auto tracker_map = tr_variant::Map{ 5U };
tracker_map.try_emplace(TR_KEY_announce, tracker.announce.sv());
tracker_map.try_emplace(TR_KEY_id, tracker.id);
tracker_map.try_emplace(TR_KEY_scrape, tracker.scrape.sv());
tracker_map.try_emplace(TR_KEY_sitename, tracker.sitename.sv());
tracker_map.try_emplace(TR_KEY_tier, tracker.tier);
vec.emplace_back(std::move(tracker_map));
}
return tr_variant{ std::move(vec) };
}
[[nodiscard]] auto make_tracker_stats_vec(tr_torrent const& tor)
{
auto const n_trackers = tr_torrentTrackerCount(&tor);
auto vec = tr_variant::Vector{};
vec.reserve(n_trackers);
for (size_t idx = 0U; idx != n_trackers; ++idx)
{
auto const tracker = tr_torrentTracker(&tor, idx);
auto stats_map = tr_variant::Map{ 27U };
stats_map.try_emplace(TR_KEY_announce, tracker.announce);
stats_map.try_emplace(TR_KEY_announceState, tracker.announceState);
stats_map.try_emplace(TR_KEY_downloadCount, tracker.downloadCount);
stats_map.try_emplace(TR_KEY_hasAnnounced, tracker.hasAnnounced);
stats_map.try_emplace(TR_KEY_hasScraped, tracker.hasScraped);
stats_map.try_emplace(TR_KEY_host, tracker.host_and_port);
stats_map.try_emplace(TR_KEY_id, tracker.id);
stats_map.try_emplace(TR_KEY_isBackup, tracker.isBackup);
stats_map.try_emplace(TR_KEY_lastAnnouncePeerCount, tracker.lastAnnouncePeerCount);
stats_map.try_emplace(TR_KEY_lastAnnounceResult, tracker.lastAnnounceResult);
stats_map.try_emplace(TR_KEY_lastAnnounceStartTime, tracker.lastAnnounceStartTime);
stats_map.try_emplace(TR_KEY_lastAnnounceSucceeded, tracker.lastAnnounceSucceeded);
stats_map.try_emplace(TR_KEY_lastAnnounceTime, tracker.lastAnnounceTime);
stats_map.try_emplace(TR_KEY_lastAnnounceTimedOut, tracker.lastAnnounceTimedOut);
stats_map.try_emplace(TR_KEY_lastScrapeResult, tracker.lastScrapeResult);
stats_map.try_emplace(TR_KEY_lastScrapeStartTime, tracker.lastScrapeStartTime);
stats_map.try_emplace(TR_KEY_lastScrapeSucceeded, tracker.lastScrapeSucceeded);
stats_map.try_emplace(TR_KEY_lastScrapeTime, tracker.lastScrapeTime);
stats_map.try_emplace(TR_KEY_lastScrapeTimedOut, tracker.lastScrapeTimedOut);
stats_map.try_emplace(TR_KEY_leecherCount, tracker.leecherCount);
stats_map.try_emplace(TR_KEY_nextAnnounceTime, tracker.nextAnnounceTime);
stats_map.try_emplace(TR_KEY_nextScrapeTime, tracker.nextScrapeTime);
stats_map.try_emplace(TR_KEY_scrape, tracker.scrape);
stats_map.try_emplace(TR_KEY_scrapeState, tracker.scrapeState);
stats_map.try_emplace(TR_KEY_seederCount, tracker.seederCount);
stats_map.try_emplace(TR_KEY_sitename, tracker.sitename);
stats_map.try_emplace(TR_KEY_tier, tracker.tier);
vec.emplace_back(std::move(stats_map));
}
return tr_variant{ std::move(vec) };
}
[[nodiscard]] auto make_peer_vec(tr_torrent const& tor)
{
auto n_peers = size_t{};
auto* const peers = tr_torrentPeers(&tor, &n_peers);
auto peers_vec = tr_variant::Vector{};
peers_vec.reserve(n_peers);
for (size_t idx = 0U; idx != n_peers; ++idx)
{
auto const& peer = peers[idx];
auto peer_map = tr_variant::Map{ 16U };
peer_map.try_emplace(TR_KEY_address, peer.addr);
peer_map.try_emplace(TR_KEY_clientIsChoked, peer.clientIsChoked);
peer_map.try_emplace(TR_KEY_clientIsInterested, peer.clientIsInterested);
peer_map.try_emplace(TR_KEY_clientName, peer.client);
peer_map.try_emplace(TR_KEY_flagStr, peer.flagStr);
peer_map.try_emplace(TR_KEY_isDownloadingFrom, peer.isDownloadingFrom);
peer_map.try_emplace(TR_KEY_isEncrypted, peer.isEncrypted);
peer_map.try_emplace(TR_KEY_isIncoming, peer.isIncoming);
peer_map.try_emplace(TR_KEY_isUTP, peer.isUTP);
peer_map.try_emplace(TR_KEY_isUploadingTo, peer.isUploadingTo);
peer_map.try_emplace(TR_KEY_peerIsChoked, peer.peerIsChoked);
peer_map.try_emplace(TR_KEY_peerIsInterested, peer.peerIsInterested);
peer_map.try_emplace(TR_KEY_port, peer.port);
peer_map.try_emplace(TR_KEY_progress, peer.progress);
peer_map.try_emplace(TR_KEY_rateToClient, tr_toSpeedBytes(peer.rateToClient_KBps));
peer_map.try_emplace(TR_KEY_rateToPeer, tr_toSpeedBytes(peer.rateToPeer_KBps));
peers_vec.emplace_back(std::move(peer_map));
}
tr_torrentPeersFree(peers, n_peers);
return tr_variant{ std::move(peers_vec) };
}
[[nodiscard]] auto make_peer_counts_map(tr_stat const& st)
{
auto const& from = st.peersFrom;
auto from_map = tr_variant::Map{ 7U };
from_map.try_emplace(TR_KEY_fromCache, from[TR_PEER_FROM_RESUME]);
from_map.try_emplace(TR_KEY_fromDht, from[TR_PEER_FROM_DHT]);
from_map.try_emplace(TR_KEY_fromIncoming, from[TR_PEER_FROM_INCOMING]);
from_map.try_emplace(TR_KEY_fromLpd, from[TR_PEER_FROM_LPD]);
from_map.try_emplace(TR_KEY_fromLtep, from[TR_PEER_FROM_LTEP]);
from_map.try_emplace(TR_KEY_fromPex, from[TR_PEER_FROM_PEX]);
from_map.try_emplace(TR_KEY_fromTracker, from[TR_PEER_FROM_TRACKER]);
return tr_variant{ std::move(from_map) };
}
[[nodiscard]] auto make_piece_availability_vec(tr_torrent const& tor)
{
auto const n_pieces = tor.piece_count();
auto vec = tr_variant::Vector{};
vec.reserve(n_pieces);
for (tr_piece_index_t idx = 0U; idx != n_pieces; ++idx)
{
vec.emplace_back(tr_peerMgrPieceAvailability(&tor, idx));
}
return tr_variant{ std::move(vec) };
}
[[nodiscard]] auto make_piece_bitfield(tr_torrent const& tor)
{
if (tor.has_metainfo())
{
auto const bytes = tor.create_piece_bitfield();
return tr_variant{ tr_base64_encode({ reinterpret_cast<char const*>(std::data(bytes)), std::size(bytes) }) };
}
tr_torrentPeersFree(peers, peer_count);
return tr_variant::unmanaged_string(""sv);
}
} // namespace make_torrent_field_helpers
[[nodiscard]] auto constexpr isSupportedTorrentGetField(tr_quark key)
{
@ -506,374 +601,96 @@ void addPeers(tr_torrent const* tor, tr_variant* list)
}
}
void initField(tr_torrent const* const tor, tr_stat const* const st, tr_variant* const initme, tr_quark key)
[[nodiscard]] tr_variant make_torrent_field(tr_torrent const& tor, tr_stat const& st, tr_quark key)
{
using namespace make_torrent_field_helpers;
TR_ASSERT(isSupportedTorrentGetField(key));
// clang-format off
switch (key)
{
case TR_KEY_activityDate:
tr_variantInitInt(initme, st->activityDate);
break;
case TR_KEY_addedDate:
tr_variantInitInt(initme, st->addedDate);
break;
case TR_KEY_availability:
tr_variantInitList(initme, tor->piece_count());
for (tr_piece_index_t piece = 0, n = tor->piece_count(); piece < n; ++piece)
{
tr_variantListAddInt(initme, tr_peerMgrPieceAvailability(tor, piece));
}
break;
case TR_KEY_bandwidthPriority:
tr_variantInitInt(initme, tor->get_priority());
break;
case TR_KEY_comment:
tr_variantInitStr(initme, tor->comment());
break;
case TR_KEY_corruptEver:
tr_variantInitInt(initme, st->corruptEver);
break;
case TR_KEY_creator:
tr_variantInitStrView(initme, tor->creator());
break;
case TR_KEY_dateCreated:
tr_variantInitInt(initme, tor->date_created());
break;
case TR_KEY_desiredAvailable:
tr_variantInitInt(initme, st->desiredAvailable);
break;
case TR_KEY_doneDate:
tr_variantInitInt(initme, st->doneDate);
break;
case TR_KEY_downloadDir:
tr_variantInitStrView(initme, tr_torrentGetDownloadDir(tor));
break;
case TR_KEY_downloadedEver:
tr_variantInitInt(initme, st->downloadedEver);
break;
case TR_KEY_downloadLimit:
tr_variantInitInt(initme, tr_torrentGetSpeedLimit_KBps(tor, TR_DOWN));
break;
case TR_KEY_downloadLimited:
tr_variantInitBool(initme, tor->uses_speed_limit(TR_DOWN));
break;
case TR_KEY_error:
tr_variantInitInt(initme, st->error);
break;
case TR_KEY_errorString:
tr_variantInitStrView(initme, st->errorString);
break;
case TR_KEY_eta:
tr_variantInitInt(initme, st->eta);
break;
case TR_KEY_file_count:
tr_variantInitInt(initme, tor->file_count());
break;
case TR_KEY_files:
tr_variantInitList(initme, tor->file_count());
addFiles(tor, initme);
break;
case TR_KEY_fileStats:
tr_variantInitList(initme, tor->file_count());
addFileStats(tor, initme);
break;
case TR_KEY_group:
tr_variantInitStrView(initme, tor->bandwidth_group().sv());
break;
case TR_KEY_hashString:
tr_variantInitStrView(initme, tor->info_hash_string());
break;
case TR_KEY_haveUnchecked:
tr_variantInitInt(initme, st->haveUnchecked);
break;
case TR_KEY_sequentialDownload:
tr_variantDictAddBool(initme, TR_KEY_sequentialDownload, tor->is_sequential_download());
break;
case TR_KEY_haveValid:
tr_variantInitInt(initme, st->haveValid);
break;
case TR_KEY_honorsSessionLimits:
tr_variantInitBool(initme, tor->uses_session_limits());
break;
case TR_KEY_id:
tr_variantInitInt(initme, st->id);
break;
case TR_KEY_editDate:
tr_variantInitInt(initme, st->editDate);
break;
case TR_KEY_isFinished:
tr_variantInitBool(initme, st->finished);
break;
case TR_KEY_isPrivate:
tr_variantInitBool(initme, tor->is_private());
break;
case TR_KEY_isStalled:
tr_variantInitBool(initme, st->isStalled);
break;
case TR_KEY_labels:
addLabels(tor, initme);
break;
case TR_KEY_leftUntilDone:
tr_variantInitInt(initme, st->leftUntilDone);
break;
case TR_KEY_manualAnnounceTime:
tr_variantInitInt(initme, tr_announcerNextManualAnnounce(tor));
break;
case TR_KEY_maxConnectedPeers:
case TR_KEY_peer_limit:
tr_variantInitInt(initme, tor->peer_limit());
break;
case TR_KEY_magnetLink:
tr_variantInitStr(initme, tor->metainfo_.magnet());
break;
case TR_KEY_metadataPercentComplete:
tr_variantInitReal(initme, st->metadataPercentComplete);
break;
case TR_KEY_name:
tr_variantInitStrView(initme, tr_torrentName(tor));
break;
case TR_KEY_percentComplete:
tr_variantInitReal(initme, st->percentComplete);
break;
case TR_KEY_percentDone:
tr_variantInitReal(initme, st->percentDone);
break;
case TR_KEY_peers:
addPeers(tor, initme);
break;
case TR_KEY_peersConnected:
tr_variantInitInt(initme, st->peersConnected);
break;
case TR_KEY_peersFrom:
{
tr_variantInitDict(initme, 7);
auto const* f = st->peersFrom;
tr_variantDictAddInt(initme, TR_KEY_fromCache, f[TR_PEER_FROM_RESUME]);
tr_variantDictAddInt(initme, TR_KEY_fromDht, f[TR_PEER_FROM_DHT]);
tr_variantDictAddInt(initme, TR_KEY_fromIncoming, f[TR_PEER_FROM_INCOMING]);
tr_variantDictAddInt(initme, TR_KEY_fromLpd, f[TR_PEER_FROM_LPD]);
tr_variantDictAddInt(initme, TR_KEY_fromLtep, f[TR_PEER_FROM_LTEP]);
tr_variantDictAddInt(initme, TR_KEY_fromPex, f[TR_PEER_FROM_PEX]);
tr_variantDictAddInt(initme, TR_KEY_fromTracker, f[TR_PEER_FROM_TRACKER]);
break;
}
case TR_KEY_peersGettingFromUs:
tr_variantInitInt(initme, st->peersGettingFromUs);
break;
case TR_KEY_peersSendingToUs:
tr_variantInitInt(initme, st->peersSendingToUs);
break;
case TR_KEY_pieces:
if (tor->has_metainfo())
{
auto const bytes = tor->create_piece_bitfield();
auto const enc = tr_base64_encode({ reinterpret_cast<char const*>(std::data(bytes)), std::size(bytes) });
tr_variantInitStr(initme, enc);
}
else
{
tr_variantInitStrView(initme, ""sv);
}
break;
case TR_KEY_pieceCount:
tr_variantInitInt(initme, tor->piece_count());
break;
case TR_KEY_pieceSize:
tr_variantInitInt(initme, tor->piece_size());
break;
case TR_KEY_primary_mime_type:
tr_variantInitStrView(initme, tor->primary_mime_type());
break;
case TR_KEY_priorities:
{
auto const n = tor->file_count();
tr_variantInitList(initme, n);
for (tr_file_index_t i = 0; i < n; ++i)
{
tr_variantListAddInt(initme, tr_torrentFile(tor, i).priority);
}
}
break;
case TR_KEY_queuePosition:
tr_variantInitInt(initme, st->queuePosition);
break;
case TR_KEY_etaIdle:
tr_variantInitInt(initme, st->etaIdle);
break;
case TR_KEY_rateDownload:
tr_variantInitInt(initme, tr_toSpeedBytes(st->pieceDownloadSpeed_KBps));
break;
case TR_KEY_rateUpload:
tr_variantInitInt(initme, tr_toSpeedBytes(st->pieceUploadSpeed_KBps));
break;
case TR_KEY_recheckProgress:
tr_variantInitReal(initme, st->recheckProgress);
break;
case TR_KEY_seedIdleLimit:
tr_variantInitInt(initme, tor->idle_limit_minutes());
break;
case TR_KEY_seedIdleMode:
tr_variantInitInt(initme, tor->idle_limit_mode());
break;
case TR_KEY_seedRatioLimit:
tr_variantInitReal(initme, tr_torrentGetRatioLimit(tor));
break;
case TR_KEY_seedRatioMode:
tr_variantInitInt(initme, tr_torrentGetRatioMode(tor));
break;
case TR_KEY_sizeWhenDone:
tr_variantInitInt(initme, st->sizeWhenDone);
break;
case TR_KEY_source:
tr_variantInitStrView(initme, tor->source());
break;
case TR_KEY_startDate:
tr_variantInitInt(initme, st->startDate);
break;
case TR_KEY_status:
tr_variantInitInt(initme, st->activity);
break;
case TR_KEY_secondsDownloading:
tr_variantInitInt(initme, st->secondsDownloading);
break;
case TR_KEY_secondsSeeding:
tr_variantInitInt(initme, st->secondsSeeding);
break;
case TR_KEY_trackers:
tr_variantInitList(initme, tor->tracker_count());
addTrackers(tor, initme);
break;
case TR_KEY_trackerList:
tr_variantInitStr(initme, tor->tracker_list());
break;
case TR_KEY_trackerStats:
{
auto const n = tr_torrentTrackerCount(tor);
tr_variantInitList(initme, n);
for (size_t i = 0; i < n; ++i)
{
auto const& tracker = tr_torrentTracker(tor, i);
addTrackerStats(tracker, initme);
}
break;
}
case TR_KEY_torrentFile:
tr_variantInitStr(initme, tor->torrent_file());
break;
case TR_KEY_totalSize:
tr_variantInitInt(initme, tor->total_size());
break;
case TR_KEY_uploadedEver:
tr_variantInitInt(initme, st->uploadedEver);
break;
case TR_KEY_uploadLimit:
tr_variantInitInt(initme, tr_torrentGetSpeedLimit_KBps(tor, TR_UP));
break;
case TR_KEY_uploadLimited:
tr_variantInitBool(initme, tor->uses_speed_limit(TR_UP));
break;
case TR_KEY_uploadRatio:
tr_variantInitReal(initme, st->ratio);
break;
case TR_KEY_wanted:
{
auto const n = tor->file_count();
tr_variantInitList(initme, n);
for (tr_file_index_t i = 0; i < n; ++i)
{
tr_variantListAddInt(initme, tr_torrentFile(tor, i).wanted ? 1 : 0);
}
}
break;
case TR_KEY_webseeds:
tr_variantInitList(initme, tor->webseed_count());
addWebseeds(tor, initme);
break;
case TR_KEY_webseedsSendingToUs:
tr_variantInitInt(initme, st->webseedsSendingToUs);
break;
default:
break;
case TR_KEY_activityDate: return st.activityDate;
case TR_KEY_addedDate: return st.addedDate;
case TR_KEY_availability: return make_piece_availability_vec(tor);
case TR_KEY_bandwidthPriority: return tor.get_priority();
case TR_KEY_comment: return tor.comment();
case TR_KEY_corruptEver: return st.corruptEver;
case TR_KEY_creator: return tor.creator();
case TR_KEY_dateCreated: return tor.date_created();
case TR_KEY_desiredAvailable: return st.desiredAvailable;
case TR_KEY_doneDate: return st.doneDate;
case TR_KEY_downloadDir: return tor.download_dir().sv();
case TR_KEY_downloadLimit: return tr_torrentGetSpeedLimit_KBps(&tor, TR_DOWN);
case TR_KEY_downloadLimited: return tor.uses_speed_limit(TR_DOWN);
case TR_KEY_downloadedEver: return st.downloadedEver;
case TR_KEY_editDate: return st.editDate;
case TR_KEY_error: return st.error;
case TR_KEY_errorString: return st.errorString;
case TR_KEY_eta: return st.eta;
case TR_KEY_etaIdle: return st.etaIdle;
case TR_KEY_fileStats: return make_file_stats_vec(tor);
case TR_KEY_file_count: return tor.file_count();
case TR_KEY_files: return make_file_vec(tor);
case TR_KEY_group: return tor.bandwidth_group().sv();
case TR_KEY_hashString: return tor.info_hash_string().sv();
case TR_KEY_haveUnchecked: return st.haveUnchecked;
case TR_KEY_haveValid: return st.haveValid;
case TR_KEY_honorsSessionLimits: return tor.uses_session_limits();
case TR_KEY_id: return st.id;
case TR_KEY_isFinished: return st.finished;
case TR_KEY_isPrivate: return tor.is_private();
case TR_KEY_isStalled: return st.isStalled;
case TR_KEY_labels: return make_labels_vec(tor);
case TR_KEY_leftUntilDone: return st.leftUntilDone;
case TR_KEY_magnetLink: return tor.metainfo_.magnet();
case TR_KEY_manualAnnounceTime: return tr_announcerNextManualAnnounce(&tor);
case TR_KEY_maxConnectedPeers: return tor.peer_limit();
case TR_KEY_metadataPercentComplete: return st.metadataPercentComplete;
case TR_KEY_name: return tor.name();
case TR_KEY_peer_limit: return tor.peer_limit();
case TR_KEY_peers: return make_peer_vec(tor);
case TR_KEY_peersConnected: return st.peersConnected;
case TR_KEY_peersFrom: return make_peer_counts_map(st);
case TR_KEY_peersGettingFromUs: return st.peersGettingFromUs;
case TR_KEY_peersSendingToUs: return st.peersSendingToUs;
case TR_KEY_percentComplete: return st.percentComplete;
case TR_KEY_percentDone: return st.percentDone;
case TR_KEY_pieceCount: return tor.piece_count();
case TR_KEY_pieceSize: return tor.piece_size();
case TR_KEY_pieces: return make_piece_bitfield(tor);
case TR_KEY_primary_mime_type: return tor.primary_mime_type();
case TR_KEY_priorities: return make_file_priorities_vec(tor);
case TR_KEY_queuePosition: return st.queuePosition;
case TR_KEY_rateDownload: return tr_toSpeedBytes(st.pieceDownloadSpeed_KBps);
case TR_KEY_rateUpload: return tr_toSpeedBytes(st.pieceUploadSpeed_KBps);
case TR_KEY_recheckProgress: return st.recheckProgress;
case TR_KEY_secondsDownloading: return st.secondsDownloading;
case TR_KEY_secondsSeeding: return st.secondsSeeding;
case TR_KEY_seedIdleLimit: return tor.idle_limit_minutes();
case TR_KEY_seedIdleMode: return tor.idle_limit_mode();
case TR_KEY_seedRatioLimit: return tr_torrentGetRatioLimit(&tor);
case TR_KEY_seedRatioMode: return tr_torrentGetRatioMode(&tor);
case TR_KEY_sequentialDownload: return tor.is_sequential_download();
case TR_KEY_sizeWhenDone: return st.sizeWhenDone;
case TR_KEY_source: return tor.source();
case TR_KEY_startDate: return st.startDate;
case TR_KEY_status: return st.activity;
case TR_KEY_torrentFile: return tor.torrent_file();
case TR_KEY_totalSize: return tor.total_size();
case TR_KEY_trackerList: return tor.tracker_list();
case TR_KEY_trackerStats: return make_tracker_stats_vec(tor);
case TR_KEY_trackers: return make_tracker_vec(tor);
case TR_KEY_uploadLimit: return tr_torrentGetSpeedLimit_KBps(&tor, TR_UP);
case TR_KEY_uploadLimited: return tor.uses_speed_limit(TR_UP);
case TR_KEY_uploadRatio: return st.ratio;
case TR_KEY_uploadedEver: return st.uploadedEver;
case TR_KEY_wanted: return make_file_wanted_vec(tor);
case TR_KEY_webseeds: return make_webseed_vec(tor);
case TR_KEY_webseedsSendingToUs: return st.webseedsSendingToUs;
default: return tr_variant{};
}
// clang-format on
}
void addTorrentInfo(tr_torrent* tor, TrFormat format, tr_variant* entry, tr_quark const* fields, size_t field_count)
@ -895,7 +712,7 @@ void addTorrentInfo(tr_torrent* tor, TrFormat format, tr_variant* entry, tr_quar
{
tr_variant* child = format == TrFormat::Table ? tr_variantListAdd(entry) : tr_variantDictAdd(entry, fields[i]);
initField(tor, st, child, fields[i]);
*child = make_torrent_field(*tor, *st, fields[i]);
}
}
}
@ -2590,26 +2407,23 @@ void tr_rpc_request_exec_json(
* - values that are all-digits or commas are number lists
* - all other values are strings
*/
void tr_rpc_parse_list_str(tr_variant* setme, std::string_view str)
tr_variant tr_rpc_parse_list_str(std::string_view str)
{
auto const values = tr_num_parse_range(str);
auto const value_count = std::size(values);
auto const n_values = std::size(values);
if (value_count == 0)
if (n_values == 0)
{
tr_variantInitStr(setme, str);
return { str };
}
else if (value_count == 1)
{
tr_variantInitInt(setme, values[0]);
}
else
{
tr_variantInitList(setme, value_count);
for (auto const& value : values)
{
tr_variantListAddInt(setme, value);
}
if (n_values == 1)
{
return { values[0] };
}
auto num_vec = tr_variant::Vector{};
num_vec.reserve(n_values);
std::copy_n(std::cbegin(values), n_values, std::back_inserter(num_vec));
return { std::move(num_vec) };
}

View File

@ -19,4 +19,4 @@ void tr_rpc_request_exec_json(
tr_rpc_response_func callback,
void* callback_user_data);
void tr_rpc_parse_list_str(tr_variant* setme, std::string_view str);
tr_variant tr_rpc_parse_list_str(std::string_view str);

View File

@ -32,30 +32,26 @@ TEST_F(RpcTest, list)
{
auto i = int64_t{};
auto sv = std::string_view{};
tr_variant top;
tr_rpc_parse_list_str(&top, "12"sv);
auto top = tr_rpc_parse_list_str("12"sv);
EXPECT_TRUE(top.holds_alternative<int64_t>());
EXPECT_TRUE(tr_variantGetInt(&top, &i));
EXPECT_EQ(12, i);
top.clear();
tr_rpc_parse_list_str(&top, "6,7"sv);
top = tr_rpc_parse_list_str("6,7"sv);
EXPECT_TRUE(top.holds_alternative<tr_variant::Vector>());
EXPECT_EQ(2U, tr_variantListSize(&top));
EXPECT_TRUE(tr_variantGetInt(tr_variantListChild(&top, 0), &i));
EXPECT_EQ(6, i);
EXPECT_TRUE(tr_variantGetInt(tr_variantListChild(&top, 1), &i));
EXPECT_EQ(7, i);
top.clear();
tr_rpc_parse_list_str(&top, "asdf"sv);
top = tr_rpc_parse_list_str("asdf"sv);
EXPECT_TRUE(top.holds_alternative<std::string_view>());
EXPECT_TRUE(tr_variantGetStrView(&top, &sv));
EXPECT_EQ("asdf"sv, sv);
top.clear();
tr_rpc_parse_list_str(&top, "1,3-5"sv);
top = tr_rpc_parse_list_str("1,3-5"sv);
EXPECT_TRUE(top.holds_alternative<tr_variant::Vector>());
EXPECT_EQ(4U, tr_variantListSize(&top));
EXPECT_TRUE(tr_variantGetInt(tr_variantListChild(&top, 0), &i));

View File

@ -347,48 +347,35 @@ class SessionTest : public SandboxedTest
private:
std::shared_ptr<tr_variant> settings_;
tr_session* sessionInit(tr_variant* settings)
tr_session* sessionInit(tr_variant& settings)
{
ensureFormattersInited();
auto* const settings_map = settings.get_if<tr_variant::Map>();
EXPECT_NE(settings_map, nullptr);
// download dir
auto sv = "Downloads"sv;
auto q = TR_KEY_download_dir;
(void)tr_variantDictFindStrView(settings, q, &sv);
auto const download_dir = tr_pathbuf{ sandboxDir(), '/', sv };
auto key = TR_KEY_download_dir;
auto val = settings_map->value_if<std::string_view>(key).value_or("Downloads"sv);
auto const download_dir = tr_pathbuf{ sandboxDir(), '/', val };
tr_sys_dir_create(download_dir, TR_SYS_DIR_CREATE_PARENTS, 0700);
tr_variantDictAddStr(settings, q, download_dir);
(*settings_map)[key] = download_dir.sv();
// incomplete dir
sv = "Incomplete"sv;
q = TR_KEY_incomplete_dir;
(void)tr_variantDictFindStrView(settings, q, &sv);
tr_variantDictAddStr(settings, q, tr_pathbuf{ sandboxDir(), '/', sv });
key = TR_KEY_incomplete_dir;
val = settings_map->value_if<std::string_view>(key).value_or("Incomplete"sv);
auto const incomplete_dir = tr_pathbuf{ sandboxDir(), '/', val };
(*settings_map)[key] = incomplete_dir.sv();
// blocklists
tr_sys_dir_create(tr_pathbuf{ sandboxDir(), "/blocklists" }, TR_SYS_DIR_CREATE_PARENTS, 0700);
// fill in any missing settings
settings_map->try_emplace(TR_KEY_port_forwarding_enabled, false);
settings_map->try_emplace(TR_KEY_dht_enabled, false);
settings_map->try_emplace(TR_KEY_message_level, verbose ? TR_LOG_DEBUG : TR_LOG_ERROR);
q = TR_KEY_port_forwarding_enabled;
if (tr_variantDictFind(settings, q) == nullptr)
{
tr_variantDictAddBool(settings, q, false);
}
q = TR_KEY_dht_enabled;
if (tr_variantDictFind(settings, q) == nullptr)
{
tr_variantDictAddBool(settings, q, false);
}
q = TR_KEY_message_level;
if (tr_variantDictFind(settings, q) == nullptr)
{
tr_variantDictAddInt(settings, q, verbose ? TR_LOG_DEBUG : TR_LOG_ERROR);
}
return tr_sessionInit(sandboxDir().data(), !verbose, *settings);
return tr_sessionInit(sandboxDir().data(), !verbose, settings);
}
void sessionClose(tr_session* session)
@ -534,7 +521,7 @@ protected:
verified_cv_.notify_one();
};
session_ = sessionInit(settings());
session_ = sessionInit(*settings());
session_->verifier_->add_callback(callback);
}

View File

@ -603,7 +603,7 @@ static void addIdArg(tr_variant* args, std::string_view id_str, std::string_view
if (is_num || is_list)
{
tr_rpc_parse_list_str(tr_variantDictAdd(args, TR_KEY_ids), id_str);
*tr_variantDictAdd(args, TR_KEY_ids) = tr_rpc_parse_list_str(id_str);
}
else
{