refactor: tidy up announcer code (#5945)

This commit is contained in:
Yat Ho 2023-09-02 05:51:58 +08:00 committed by GitHub
parent 45d9e37b2b
commit e39045cf69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 156 additions and 146 deletions

View File

@ -87,7 +87,7 @@ bool tr_announce_list::add(std::string_view announce_url_sv, tr_tracker_tier_t t
tracker.announce = announce_url_sv;
tracker.tier = get_tier(tier, *announce);
tracker.id = next_unique_id();
tracker.host_and_port = fmt::format(FMT_STRING("{:s}:{:d}"), announce->host, announce->port);
tracker.host_and_port = fmt::format("{:s}:{:d}", announce->host, announce->port);
tracker.sitename = announce->sitename;
tracker.query = announce->query;

View File

@ -95,7 +95,7 @@ struct tr_announce_request
tr_sha1_digest_t info_hash;
/* the name to use when deep logging is enabled */
char log_name[128];
std::string log_name;
};
struct tr_announce_response
@ -118,13 +118,13 @@ struct tr_announce_response
int min_interval = 0;
/* how many peers are seeding this torrent */
int seeders = -1;
std::optional<int64_t> seeders;
/* how many peers are downloading this torrent */
int leechers = -1;
std::optional<int64_t> leechers;
/* how many times this torrent has been downloaded */
int downloads = -1;
std::optional<int64_t> downloads;
/* IPv4 peers that we acquired from the tracker */
std::vector<tr_pex> pex;
@ -169,7 +169,7 @@ struct tr_scrape_request
tr_interned_string scrape_url;
/* the name to use when deep logging is enabled */
char log_name[128];
std::string log_name;
/* info hashes of the torrents to scrape */
std::array<tr_sha1_digest_t, TR_MULTISCRAPE_MAX> info_hash;
@ -184,18 +184,18 @@ struct tr_scrape_response_row
tr_sha1_digest_t info_hash;
/* how many peers are seeding this torrent */
int seeders = 0;
std::optional<int64_t> seeders;
/* how many peers are downloading this torrent */
int leechers = 0;
std::optional<int64_t> leechers;
/* how many times this torrent has been downloaded */
int downloads = 0;
std::optional<int64_t> downloads;
/* the number of active downloaders in the swarm.
* this is a BEP 21 extension that some trackers won't support.
* http://www.bittorrent.org/beps/bep_0021.html#tracker-scrapes */
int downloaders = 0;
std::optional<int64_t> downloaders;
};
struct tr_scrape_response

View File

@ -371,15 +371,15 @@ void tr_announcerParseHttpAnnounceResponse(tr_announce_response& response, std::
}
else if (key == "complete"sv)
{
response_.seeders = static_cast<int>(value);
response_.seeders = value;
}
else if (key == "incomplete"sv)
{
response_.leechers = static_cast<int>(value);
response_.leechers = value;
}
else if (key == "downloaded"sv)
{
response_.downloads = static_cast<int>(value);
response_.downloads = value;
}
else if (key == "port"sv)
{
@ -548,9 +548,6 @@ void tr_tracker_http_scrape(tr_session const* session, tr_scrape_request const&
for (int i = 0; i < response.row_count; ++i)
{
response.rows[i].info_hash = request.info_hash[i];
response.rows[i].seeders = -1;
response.rows[i].leechers = -1;
response.rows[i].downloads = -1;
}
auto scrape_url = tr_pathbuf{};
@ -610,19 +607,19 @@ void tr_announcerParseHttpScrapeResponse(tr_scrape_response& response, std::stri
{
if (auto const key = currentKey(); row_ && key == "complete"sv)
{
response_.rows[*row_].seeders = static_cast<int>(value);
response_.rows[*row_].seeders = value;
}
else if (row_ && key == "downloaded"sv)
{
response_.rows[*row_].downloads = static_cast<int>(value);
response_.rows[*row_].downloads = value;
}
else if (row_ && key == "incomplete"sv)
{
response_.rows[*row_].leechers = static_cast<int>(value);
response_.rows[*row_].leechers = value;
}
else if (row_ && key == "downloaders"sv)
{
response_.rows[*row_].downloaders = static_cast<int>(value);
response_.rows[*row_].downloaders = value;
}
else if (key == "min_request_interval"sv)
{

View File

@ -88,9 +88,6 @@ struct tau_scrape_request
this->response.row_count = in.info_hash_count;
for (int i = 0; i < this->response.row_count; ++i)
{
this->response.rows[i].seeders = -1;
this->response.rows[i].leechers = -1;
this->response.rows[i].downloads = -1;
this->response.rows[i].info_hash = in.info_hash[i];
}
@ -133,13 +130,8 @@ struct tau_scrape_request
if (action == TAU_ACTION_SCRAPE)
{
for (int i = 0; i < response.row_count; ++i)
for (int i = 0; i < response.row_count && std::size(buf) >= sizeof(uint32_t) * 3U; ++i)
{
if (std::size(buf) < sizeof(uint32_t) * 3)
{
break;
}
auto& row = response.rows[i];
row.seeders = buf.to_uint32();
row.downloads = buf.to_uint32();
@ -183,9 +175,6 @@ struct tau_announce_request
// https://www.bittorrent.org/beps/bep_0015.html sets key size at 32 bits
static_assert(sizeof(tr_announce_request::key) * CHAR_BIT == 32);
response.seeders = -1;
response.leechers = -1;
response.downloads = -1;
response.info_hash = in.info_hash;
// build the payload
@ -657,11 +646,11 @@ public:
// is it a response to one of this tracker's announces?
if (auto& reqs = tracker.announces; !std::empty(reqs))
{
auto it = std::find_if(
std::begin(reqs),
std::end(reqs),
[&transaction_id](auto const& req) { return req.transaction_id == transaction_id; });
if (it != std::end(reqs))
if (auto it = std::find_if(
std::begin(reqs),
std::end(reqs),
[&transaction_id](auto const& req) { return req.transaction_id == transaction_id; });
it != std::end(reqs))
{
logtrace(tracker.key, fmt::format("{} is an announce request!", transaction_id));
auto req = *it;
@ -674,11 +663,11 @@ public:
// is it a response to one of this tracker's scrapes?
if (auto& reqs = tracker.scrapes; !std::empty(reqs))
{
auto it = std::find_if(
std::begin(reqs),
std::end(reqs),
[&transaction_id](auto const& req) { return req.transaction_id == transaction_id; });
if (it != std::end(reqs))
if (auto it = std::find_if(
std::begin(reqs),
std::end(reqs),
[&transaction_id](auto const& req) { return req.transaction_id == transaction_id; });
it != std::end(reqs))
{
logtrace(tracker.key, fmt::format("{} is a scrape request!", transaction_id));
auto req = *it;

View File

@ -295,6 +295,66 @@ struct tr_tracker
}
}
[[nodiscard]] constexpr auto seeder_count() const noexcept
{
return seeder_count_;
}
constexpr bool set_seeder_count(std::optional<int64_t> seeder_count_in) noexcept
{
if (seeder_count_in >= 0)
{
seeder_count_ = seeder_count_in;
return true;
}
return false;
}
[[nodiscard]] constexpr auto leecher_count() const noexcept
{
return leecher_count_;
}
constexpr bool set_leecher_count(std::optional<int64_t> leecher_count_in) noexcept
{
if (leecher_count_in >= 0)
{
leecher_count_ = leecher_count_in;
return true;
}
return false;
}
[[nodiscard]] constexpr auto download_count() const noexcept
{
return download_count_;
}
constexpr bool set_download_count(std::optional<int64_t> download_count_in) noexcept
{
if (download_count_in >= 0)
{
download_count_ = download_count_in;
return true;
}
return false;
}
[[nodiscard]] constexpr auto downloader_count() const noexcept
{
return downloader_count_;
}
constexpr bool set_downloader_count(std::optional<int64_t> downloader_count_in) noexcept
{
if (downloader_count_in >= 0)
{
downloader_count_ = downloader_count_in;
return true;
}
return false;
}
tr_interned_string const host_and_port;
tr_interned_string const announce_url;
std::string_view const sitename;
@ -302,14 +362,15 @@ struct tr_tracker
std::string tracker_id;
int seeder_count = -1;
int leecher_count = -1;
int download_count = -1;
int downloader_count = -1;
int consecutive_failures = 0;
tr_tracker_id_t const id;
private:
std::optional<int64_t> seeder_count_;
std::optional<int64_t> leecher_count_;
std::optional<int64_t> download_count_;
std::optional<int64_t> downloader_count_;
};
// format: `${host}:${port}`
@ -378,7 +439,7 @@ struct tr_tier
{
auto const* const tracker = currentTracker();
return tracker == nullptr ? 0 : tracker->downloader_count + tracker->leecher_count;
return tracker == nullptr ? 0 : tracker->downloader_count().value_or(-1) + tracker->leecher_count().value_or(-1);
}
tr_tracker* useNextTracker()
@ -424,17 +485,9 @@ struct tr_tier
[[nodiscard]] std::string buildLogName() const
{
auto buf = std::array<char, 512>{};
buildLogName(std::data(buf), std::size(buf));
return std::string{ std::data(buf) };
}
void buildLogName(char* buf, size_t buflen) const
{
auto const* const torrent_name = tr_torrentName(tor);
auto const* const current_tracker = currentTracker();
auto const host_and_port_sv = current_tracker == nullptr ? "?"sv : current_tracker->host_and_port.sv();
*fmt::format_to_n(buf, buflen - 1, FMT_STRING("{:s} at {:s}"), torrent_name, host_and_port_sv).out = '\0';
return fmt::format("{:s} at {:s}", tor->name(), host_and_port_sv);
}
[[nodiscard]] bool canManualAnnounce() const
@ -669,7 +722,7 @@ void publishError(tr_tier* tier, std::string_view msg)
publishMessage(tier, msg, tr_tracker_event::Type::Error);
}
void publishPeerCounts(tr_tier* tier, int seeders, int leechers)
void publishPeerCounts(tr_tier* tier, std::optional<int64_t> seeders, std::optional<int64_t> leechers)
{
if (tier->tor->torrent_announcer->callback != nullptr)
{
@ -677,28 +730,22 @@ void publishPeerCounts(tr_tier* tier, int seeders, int leechers)
e.type = tr_tracker_event::Type::Counts;
e.seeders = seeders;
e.leechers = leechers;
tr_logAddDebugTier(tier, fmt::format("peer counts: {} seeders, {} leechers.", seeders, leechers));
tr_logAddDebugTier(
tier,
fmt::format("peer counts: {} seeders, {} leechers.", seeders.value_or(-1), leechers.value_or(-1)));
tier->tor->torrent_announcer->callback(*tier->tor, &e);
}
}
void publishPeersPex(tr_tier* tier, int seeders, int leechers, std::vector<tr_pex> const& pex)
void publishPeersPex(tr_tier* tier, std::vector<tr_pex> const& pex)
{
if (tier->tor->torrent_announcer->callback != nullptr)
{
auto e = tr_tracker_event{};
e.type = tr_tracker_event::Type::Peers;
e.seeders = seeders;
e.leechers = leechers;
e.pex = pex;
tr_logAddDebugTier(
tier,
fmt::format(
"tracker knows of {} seeders and {} leechers and gave a list of {} peers.",
seeders,
leechers,
std::size(pex)));
tr_logAddDebugTier(tier, fmt::format("tracker gave a list of {} peers.", std::size(pex)));
tier->tor->torrent_announcer->callback(*tier->tor, &e);
}
@ -909,7 +956,7 @@ void on_announce_error(tr_tier* tier, char const* err, tr_announce_event e)
req.numwant = event == TR_ANNOUNCE_EVENT_STOPPED ? 0 : Numwant;
req.key = tor->announce_key();
req.partial_seed = tor->is_partial_seed();
tier->buildLogName(req.log_name, sizeof(req.log_name));
req.log_name = tier->buildLogName();
return req;
}
@ -977,9 +1024,9 @@ void tr_announcer_impl::onAnnounceDone(
"warn:{}",
response.did_connect,
response.did_timeout,
response.seeders,
response.leechers,
response.downloads,
response.seeders.value_or(-1),
response.leechers.value_or(-1),
response.downloads.value_or(-1),
response.interval,
response.min_interval,
(!std::empty(response.tracker_id) ? response.tracker_id.c_str() : "none"),
@ -1023,9 +1070,7 @@ void tr_announcer_impl::onAnnounceDone(
else
{
auto const is_stopped = event == TR_ANNOUNCE_EVENT_STOPPED;
auto leechers = int{};
auto scrape_fields = int{};
auto seeders = int{};
auto scrape_fields = uint8_t{};
publishErrorClear(tier);
@ -1034,21 +1079,18 @@ void tr_announcer_impl::onAnnounceDone(
{
tracker->consecutive_failures = 0;
if (response.seeders >= 0)
if (tracker->set_seeder_count(response.seeders))
{
tracker->seeder_count = seeders = response.seeders;
++scrape_fields;
}
if (response.leechers >= 0)
if (tracker->set_leecher_count(response.leechers))
{
tracker->leecher_count = leechers = response.leechers;
++scrape_fields;
}
if (response.downloads >= 0)
if (tracker->set_download_count(response.downloads))
{
tracker->download_count = response.downloads;
++scrape_fields;
}
@ -1081,25 +1123,21 @@ void tr_announcer_impl::onAnnounceDone(
if (!std::empty(response.pex))
{
publishPeersPex(tier, seeders, leechers, response.pex);
publishPeersPex(tier, response.pex);
}
if (!std::empty(response.pex6))
{
publishPeersPex(tier, seeders, leechers, response.pex6);
publishPeersPex(tier, response.pex6);
}
/* Only publish leechers if it was actually returned during the announce */
if (response.leechers >= 0)
{
publishPeerCounts(tier, seeders, leechers);
}
publishPeerCounts(tier, response.seeders, response.leechers);
tier->isRunning = is_running_on_success;
/* if the tracker included scrape fields in its announce response,
then a separate scrape isn't needed */
if (scrape_fields >= 3 || (scrape_fields >= 1 && tracker->scrape_info == nullptr))
if (scrape_fields >= 3U || (scrape_fields >= 1U && tracker->scrape_info == nullptr))
{
tr_logAddTraceTier(
tier,
@ -1322,10 +1360,10 @@ void tr_announcer_impl::onScrapeDone(tr_scrape_response const& response)
response.scrape_url.sv(),
response.did_connect,
response.did_timeout,
row.seeders,
row.leechers,
row.downloads,
row.downloaders,
row.seeders.value_or(-1),
row.leechers.value_or(-1),
row.downloads.value_or(-1),
row.downloaders.value_or(-1),
response.min_request_interval,
std::empty(response.errmsg) ? "none"sv : response.errmsg));
@ -1355,29 +1393,15 @@ void tr_announcer_impl::onScrapeDone(tr_scrape_response const& response)
if (tr_tracker* const tracker = tier->currentTracker(); tracker != nullptr)
{
if (row.seeders >= 0)
{
tracker->seeder_count = row.seeders;
}
tracker->set_seeder_count(row.seeders);
tracker->set_leecher_count(row.leechers);
tracker->set_download_count(row.downloads);
tracker->set_downloader_count(row.downloaders);
if (row.leechers >= 0)
{
tracker->leecher_count = row.leechers;
}
if (row.downloads >= 0)
{
tracker->download_count = row.downloads;
}
tracker->downloader_count = row.downloaders;
tracker->consecutive_failures = 0;
}
if (row.seeders >= 0 && row.leechers >= 0 && row.downloads >= 0)
{
publishPeerCounts(tier, row.seeders, row.leechers);
}
publishPeerCounts(tier, row.seeders, row.leechers);
}
}
@ -1438,7 +1462,7 @@ void multiscrape(tr_announcer_impl* announcer, std::vector<tr_tier*> const& tier
{
auto* const req = &requests[request_count];
req->scrape_url = scrape_info->scrape_url;
tier->buildLogName(req->log_name, sizeof(req->log_name));
req->log_name = tier->buildLogName();
req->info_hash[req->info_hash_count] = tier->tor->info_hash();
++req->info_hash_count;
@ -1628,9 +1652,9 @@ namespace tracker_view_helpers
view.tier = tier_index;
view.isBackup = &tracker != tier.currentTracker();
view.lastScrapeStartTime = tier.lastScrapeStartTime;
view.seederCount = tracker.seeder_count;
view.leecherCount = tracker.leecher_count;
view.downloadCount = tracker.download_count;
view.seederCount = tracker.seeder_count().value_or(-1);
view.leecherCount = tracker.leecher_count().value_or(-1);
view.downloadCount = tracker.download_count().value_or(-1);
if (view.isBackup)
{
@ -1769,10 +1793,10 @@ void tr_announcer_impl::resetTorrent(tr_torrent* tor)
tr_tracker const* old_tracker = nullptr;
if (older->findTracker(new_tracker.announce_url, &old_tier, &old_tracker))
{
new_tracker.seeder_count = old_tracker->seeder_count;
new_tracker.leecher_count = old_tracker->leecher_count;
new_tracker.download_count = old_tracker->download_count;
new_tracker.downloader_count = old_tracker->downloader_count;
new_tracker.set_seeder_count(old_tracker->seeder_count());
new_tracker.set_leecher_count(old_tracker->leecher_count());
new_tracker.set_download_count(old_tracker->download_count());
new_tracker.set_downloader_count(old_tracker->downloader_count());
new_tier.announce_events = old_tier->announce_events;
new_tier.announce_event_priority = old_tier->announce_event_priority;

View File

@ -61,8 +61,8 @@ struct tr_tracker_event
std::vector<tr_pex> pex;
// for Peers and Counts events
int leechers;
int seeders;
std::optional<int64_t> leechers;
std::optional<int64_t> seeders;
};
using tr_tracker_callback = std::function<void(tr_torrent&, tr_tracker_event const*)>;

View File

@ -301,9 +301,9 @@ TEST_F(AnnouncerTest, parseHttpScrapeResponseMultiWithMissing)
EXPECT_EQ(2, response.rows[0].leechers);
EXPECT_EQ(3, response.rows[0].downloads);
EXPECT_EQ(0, response.rows[1].seeders);
EXPECT_EQ(0, response.rows[1].leechers);
EXPECT_EQ(0, response.rows[1].downloads);
EXPECT_EQ(std::nullopt, response.rows[1].seeders);
EXPECT_EQ(std::nullopt, response.rows[1].leechers);
EXPECT_EQ(std::nullopt, response.rows[1].downloads);
EXPECT_EQ(7, response.rows[2].seeders);
EXPECT_EQ(8, response.rows[2].leechers);

View File

@ -162,7 +162,7 @@ protected:
response.rows[0].seeders = 1;
response.rows[0].leechers = 2;
response.rows[0].downloads = 3;
response.rows[0].downloaders = 0;
response.rows[0].downloaders = std::nullopt;
response.scrape_url = DefaultScrapeUrl;
response.min_request_interval = 0;
@ -353,9 +353,9 @@ TEST_F(AnnouncerUdpTest, canScrape)
auto buf = MessageBuffer{};
buf.add_uint32(ScrapeAction);
buf.add_uint32(scrape_transaction_id);
buf.add_uint32(expected_response.rows[0].seeders);
buf.add_uint32(expected_response.rows[0].downloads);
buf.add_uint32(expected_response.rows[0].leechers);
buf.add_uint32(expected_response.rows[0].seeders.value_or(-1));
buf.add_uint32(expected_response.rows[0].downloads.value_or(-1));
buf.add_uint32(expected_response.rows[0].leechers.value_or(-1));
auto response_size = std::size(buf);
auto arr = std::array<uint8_t, 256>{};
buf.to_buf(std::data(arr), response_size);
@ -408,8 +408,8 @@ TEST_F(AnnouncerUdpTest, canMultiScrape)
expected_response.did_connect = true;
expected_response.did_timeout = false;
expected_response.row_count = 2;
expected_response.rows[0] = { tr_rand_obj<tr_sha1_digest_t>(), 1, 2, 3, 0 };
expected_response.rows[1] = { tr_rand_obj<tr_sha1_digest_t>(), 4, 5, 6, 0 };
expected_response.rows[0] = { tr_rand_obj<tr_sha1_digest_t>(), 1, 2, 3, std::nullopt };
expected_response.rows[1] = { tr_rand_obj<tr_sha1_digest_t>(), 4, 5, 6, std::nullopt };
expected_response.scrape_url = DefaultScrapeUrl;
expected_response.min_request_interval = 0;
@ -432,9 +432,9 @@ TEST_F(AnnouncerUdpTest, canMultiScrape)
buf.add_uint32(scrape_transaction_id);
for (int i = 0; i < expected_response.row_count; ++i)
{
buf.add_uint32(expected_response.rows[i].seeders);
buf.add_uint32(expected_response.rows[i].downloads);
buf.add_uint32(expected_response.rows[i].leechers);
buf.add_uint32(expected_response.rows[i].seeders.value_or(-1));
buf.add_uint32(expected_response.rows[i].downloads.value_or(-1));
buf.add_uint32(expected_response.rows[i].leechers.value_or(-1));
}
auto response_size = std::size(buf);
auto arr = std::array<uint8_t, 256>{};
@ -455,10 +455,10 @@ TEST_F(AnnouncerUdpTest, canHandleScrapeError)
expected_response.did_timeout = false;
expected_response.row_count = 1;
expected_response.rows[0].info_hash = tr_rand_obj<tr_sha1_digest_t>();
expected_response.rows[0].seeders = -1;
expected_response.rows[0].leechers = -1;
expected_response.rows[0].downloads = -1;
expected_response.rows[0].downloaders = 0;
expected_response.rows[0].seeders = std::nullopt;
expected_response.rows[0].leechers = std::nullopt;
expected_response.rows[0].downloads = std::nullopt;
expected_response.rows[0].downloaders = std::nullopt;
expected_response.scrape_url = DefaultScrapeUrl;
expected_response.min_request_interval = 0;
expected_response.errmsg = "Unrecognized info-hash";
@ -505,10 +505,10 @@ TEST_F(AnnouncerUdpTest, canHandleConnectError)
expected_response.did_timeout = false;
expected_response.row_count = 1;
expected_response.rows[0].info_hash = tr_rand_obj<tr_sha1_digest_t>();
expected_response.rows[0].seeders = -1; // -1 here & on next lines means error
expected_response.rows[0].leechers = -1;
expected_response.rows[0].downloads = -1;
expected_response.rows[0].downloaders = 0;
expected_response.rows[0].seeders = std::nullopt; // empty optional here & on next lines means error
expected_response.rows[0].leechers = std::nullopt;
expected_response.rows[0].downloads = std::nullopt;
expected_response.rows[0].downloaders = std::nullopt;
expected_response.scrape_url = DefaultScrapeUrl;
expected_response.min_request_interval = 0;
expected_response.errmsg = "Unable to Connect";
@ -616,7 +616,7 @@ TEST_F(AnnouncerUdpTest, canAnnounce)
expected_response.min_interval = 0; // not specified in UDP announce
expected_response.seeders = Seeders;
expected_response.leechers = Leechers;
expected_response.downloads = -1; // not specified in UDP announce
expected_response.downloads = std::nullopt; // not specified in UDP announce
expected_response.pex = std::vector<tr_pex>{ tr_pex{ addresses[0] }, tr_pex{ addresses[1] }, tr_pex{ addresses[2] } };
expected_response.pex6 = {};
expected_response.errmsg = {};
@ -646,8 +646,8 @@ TEST_F(AnnouncerUdpTest, canAnnounce)
buf.add_uint32(AnnounceAction);
buf.add_uint32(udp_ann_req.transaction_id);
buf.add_uint32(expected_response.interval);
buf.add_uint32(expected_response.leechers);
buf.add_uint32(expected_response.seeders);
buf.add_uint32(expected_response.leechers.value_or(-1));
buf.add_uint32(expected_response.seeders.value_or(-1));
for (auto const& [addr, port] : addresses)
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access)