parent
e7272fc340
commit
60ef1abadf
|
@ -205,6 +205,7 @@
|
|||
A29DF8B90DB2544C00D04E5A /* resume.cc in Sources */ = {isa = PBXBuildFile; fileRef = A29DF8B60DB2544C00D04E5A /* resume.cc */; };
|
||||
A29DF8BA0DB2544C00D04E5A /* resume.h in Headers */ = {isa = PBXBuildFile; fileRef = A29DF8B70DB2544C00D04E5A /* resume.h */; };
|
||||
A29DF8BB0DB2544C00D04E5A /* torrent.h in Headers */ = {isa = PBXBuildFile; fileRef = A29DF8B80DB2544C00D04E5A /* torrent.h */; };
|
||||
2B9BA6C508B488FE586A0AB2 /* torrents.h in Sources */ = {isa = PBXBuildFile; fileRef = 2B9BA6C508B488FE586A0AB3 /* torrents.h */; };
|
||||
A29DF8BE0DB2545F00D04E5A /* verify.h in Headers */ = {isa = PBXBuildFile; fileRef = A2D22A110D65EED100007D5F /* verify.h */; };
|
||||
A29E653613F1603100048D71 /* evutil_rand.c in Sources */ = {isa = PBXBuildFile; fileRef = A29E653513F1603100048D71 /* evutil_rand.c */; };
|
||||
A2A1CB7A0BF29D5500AE959F /* PeerProgressIndicatorCell.mm in Sources */ = {isa = PBXBuildFile; fileRef = A2A1CB780BF29D5500AE959F /* PeerProgressIndicatorCell.mm */; };
|
||||
|
@ -308,6 +309,7 @@
|
|||
BEFC1E2D0C07861A00B0BB3C /* upnp.cc in Sources */ = {isa = PBXBuildFile; fileRef = BEFC1DF40C07861A00B0BB3C /* upnp.cc */; };
|
||||
BEFC1E2F0C07861A00B0BB3C /* session.cc in Sources */ = {isa = PBXBuildFile; fileRef = BEFC1DF60C07861A00B0BB3C /* session.cc */; };
|
||||
BEFC1E320C07861A00B0BB3C /* torrent.cc in Sources */ = {isa = PBXBuildFile; fileRef = BEFC1DF90C07861A00B0BB3C /* torrent.cc */; };
|
||||
2B9BA6C508B488FE586A0AB0 /* torrents.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2B9BA6C508B488FE586A0AB1 /* torrents.cc */; };
|
||||
BEFC1E350C07861A00B0BB3C /* port-forwarding.h in Headers */ = {isa = PBXBuildFile; fileRef = BEFC1DFC0C07861A00B0BB3C /* port-forwarding.h */; };
|
||||
BEFC1E360C07861A00B0BB3C /* port-forwarding.cc in Sources */ = {isa = PBXBuildFile; fileRef = BEFC1DFD0C07861A00B0BB3C /* port-forwarding.cc */; };
|
||||
BEFC1E3B0C07861A00B0BB3C /* platform.h in Headers */ = {isa = PBXBuildFile; fileRef = BEFC1E020C07861A00B0BB3C /* platform.h */; };
|
||||
|
@ -886,6 +888,7 @@
|
|||
A29DF8B60DB2544C00D04E5A /* resume.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = resume.cc; sourceTree = "<group>"; };
|
||||
A29DF8B70DB2544C00D04E5A /* resume.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = resume.h; sourceTree = "<group>"; };
|
||||
A29DF8B80DB2544C00D04E5A /* torrent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = torrent.h; sourceTree = "<group>"; };
|
||||
2B9BA6C508B488FE586A0AB3 /* torrents.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = torrents.h; sourceTree = "<group>"; };
|
||||
A29E653513F1603100048D71 /* evutil_rand.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = evutil_rand.c; sourceTree = "<group>"; };
|
||||
A29EBE520DC01FC9006CEE80 /* web.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = web.cc; sourceTree = "<group>"; };
|
||||
A29EBE530DC01FC9006CEE80 /* web.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = web.h; sourceTree = "<group>"; };
|
||||
|
@ -1032,6 +1035,7 @@
|
|||
BEFC1DF50C07861A00B0BB3C /* transmission.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = transmission.h; sourceTree = "<group>"; };
|
||||
BEFC1DF60C07861A00B0BB3C /* session.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = session.cc; sourceTree = "<group>"; };
|
||||
BEFC1DF90C07861A00B0BB3C /* torrent.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = torrent.cc; sourceTree = "<group>"; };
|
||||
2B9BA6C508B488FE586A0AB1 /* torrents.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = torrents.cc; sourceTree = "<group>"; };
|
||||
BEFC1DFC0C07861A00B0BB3C /* port-forwarding.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "port-forwarding.h"; sourceTree = "<group>"; };
|
||||
BEFC1DFD0C07861A00B0BB3C /* port-forwarding.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "port-forwarding.cc"; sourceTree = "<group>"; };
|
||||
BEFC1E020C07861A00B0BB3C /* platform.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = platform.h; sourceTree = "<group>"; };
|
||||
|
@ -1552,6 +1556,7 @@
|
|||
A29DF8B60DB2544C00D04E5A /* resume.cc */,
|
||||
A29DF8B70DB2544C00D04E5A /* resume.h */,
|
||||
A29DF8B80DB2544C00D04E5A /* torrent.h */,
|
||||
2B9BA6C508B488FE586A0AB3 /* torrents.h */,
|
||||
C1033E031A3279B800EF44D8 /* crypto-utils-fallback.cc */,
|
||||
C1033E041A3279B800EF44D8 /* crypto-utils-ccrypto.cc */,
|
||||
C1033E051A3279B800EF44D8 /* crypto-utils.cc */,
|
||||
|
@ -1598,6 +1603,7 @@
|
|||
A23F29A0132A447400E9A83B /* announcer-http.cc */,
|
||||
A2AA9BE0132CAC8D00FA131E /* announcer-udp.cc */,
|
||||
BEFC1DF90C07861A00B0BB3C /* torrent.cc */,
|
||||
2B9BA6C508B488FE586A0AB1 /* torrents.cc */,
|
||||
BEFC1DFC0C07861A00B0BB3C /* port-forwarding.h */,
|
||||
BEFC1DFD0C07861A00B0BB3C /* port-forwarding.cc */,
|
||||
A21FBBA90EDA78C300BC3C51 /* bandwidth.h */,
|
||||
|
@ -2085,6 +2091,7 @@
|
|||
C17740D6273A002C00E455D2 /* web-utils.h in Headers */,
|
||||
A29DF8BA0DB2544C00D04E5A /* resume.h in Headers */,
|
||||
A29DF8BB0DB2544C00D04E5A /* torrent.h in Headers */,
|
||||
2B9BA6C508B488FE586A0AB2 /* torrents.h in Headers */,
|
||||
A29DF8BE0DB2545F00D04E5A /* verify.h in Headers */,
|
||||
C1FEE57B1C3223CC00D62832 /* watchdir.h in Headers */,
|
||||
A2AAB6650DE0D08B00E04DDA /* blocklist.h in Headers */,
|
||||
|
@ -2760,6 +2767,7 @@
|
|||
ED8A16402735A8AA000D61F9 /* peer-mgr-active-requests.cc in Sources */,
|
||||
BEFC1E2F0C07861A00B0BB3C /* session.cc in Sources */,
|
||||
BEFC1E320C07861A00B0BB3C /* torrent.cc in Sources */,
|
||||
2B9BA6C508B488FE586A0AB0 /* torrents.cc in Sources */,
|
||||
BEFC1E360C07861A00B0BB3C /* port-forwarding.cc in Sources */,
|
||||
BEFC1E3C0C07861A00B0BB3C /* platform.cc in Sources */,
|
||||
BEFC1E460C07861A00B0BB3C /* net.cc in Sources */,
|
||||
|
|
|
@ -60,6 +60,7 @@ set(PROJECT_FILES
|
|||
torrent-magnet.cc
|
||||
torrent-metainfo.cc
|
||||
torrent.cc
|
||||
torrents.cc
|
||||
tr-assert.cc
|
||||
tr-assert.mm
|
||||
tr-dht.cc
|
||||
|
@ -194,6 +195,7 @@ set(${PROJECT_NAME}_PRIVATE_HEADERS
|
|||
torrent-magnet.h
|
||||
torrent-metainfo.h
|
||||
torrent.h
|
||||
torrents.h
|
||||
tr-dht.h
|
||||
tr-lpd.h
|
||||
tr-udp.h
|
||||
|
|
|
@ -598,7 +598,7 @@ static tr_tier* getTier(tr_announcer* announcer, tr_sha1_digest_t const& info_ha
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
auto* const tor = announcer->session->getTorrent(info_hash);
|
||||
auto* const tor = announcer->session->torrents().get(info_hash);
|
||||
if (tor == nullptr || tor->torrent_announcer == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
|
@ -1305,7 +1305,7 @@ static void on_scrape_done(tr_scrape_response const* response, void* vsession)
|
|||
for (int i = 0; i < response->row_count; ++i)
|
||||
{
|
||||
auto const& row = response->rows[i];
|
||||
auto* const tor = session->getTorrent(row.info_hash);
|
||||
auto* const tor = session->torrents().get(row.info_hash);
|
||||
|
||||
if (tor != nullptr)
|
||||
{
|
||||
|
@ -1535,7 +1535,7 @@ static void scrapeAndAnnounceMore(tr_announcer* announcer)
|
|||
/* build a list of tiers that need to be announced */
|
||||
auto announce_me = std::vector<tr_tier*>{};
|
||||
auto scrape_me = std::vector<tr_tier*>{};
|
||||
for (auto* tor : announcer->session->torrents)
|
||||
for (auto* const tor : announcer->session->torrents())
|
||||
{
|
||||
for (auto& tier : tor->torrent_announcer->tiers)
|
||||
{
|
||||
|
|
|
@ -175,7 +175,7 @@ static void setReadState(tr_handshake* handshake, handshake_state_t state)
|
|||
static bool buildHandshakeMessage(tr_handshake* handshake, uint8_t* buf)
|
||||
{
|
||||
auto const torrent_hash = tr_cryptoGetTorrentHash(handshake->crypto);
|
||||
auto* const tor = torrent_hash ? handshake->session->getTorrent(*torrent_hash) : nullptr;
|
||||
auto* const tor = torrent_hash ? handshake->session->torrents().get(*torrent_hash) : nullptr;
|
||||
bool const success = tor != nullptr;
|
||||
|
||||
if (success)
|
||||
|
@ -257,7 +257,7 @@ static handshake_parse_err_t parseHandshake(tr_handshake* handshake, struct evbu
|
|||
/* peer id */
|
||||
dbgmsg(handshake, "peer-id is [%" TR_PRIsv "]", TR_PRIsv_ARG(peer_id));
|
||||
|
||||
if (auto* const tor = handshake->session->getTorrent(hash); peer_id == tr_torrentGetPeerId(tor))
|
||||
if (auto* const tor = handshake->session->torrents().get(hash); peer_id == tr_torrentGetPeerId(tor))
|
||||
{
|
||||
dbgmsg(handshake, "streuth! we've connected to ourselves.");
|
||||
return HANDSHAKE_PEER_IS_SELF;
|
||||
|
@ -647,7 +647,7 @@ static ReadState readHandshake(tr_handshake* handshake, struct evbuffer* inbuf)
|
|||
|
||||
if (tr_peerIoIsIncoming(handshake->io))
|
||||
{
|
||||
if (!handshake->session->contains(hash))
|
||||
if (!handshake->session->torrents().contains(hash))
|
||||
{
|
||||
dbgmsg(handshake, "peer is trying to connect to us for a torrent we don't have.");
|
||||
return tr_handshakeDone(handshake, false);
|
||||
|
@ -703,7 +703,7 @@ static ReadState readPeerId(tr_handshake* handshake, struct evbuffer* inbuf)
|
|||
|
||||
// if we've somehow connected to ourselves, don't keep the connection
|
||||
auto const hash = tr_peerIoGetTorrentHash(handshake->io);
|
||||
auto* const tor = hash ? handshake->session->getTorrent(*hash) : nullptr;
|
||||
auto* const tor = hash ? handshake->session->torrents().get(*hash) : nullptr;
|
||||
bool const connected_to_self = peer_id == tr_torrentGetPeerId(tor);
|
||||
|
||||
return tr_handshakeDone(handshake, !connected_to_self);
|
||||
|
@ -1134,7 +1134,7 @@ static void gotError(tr_peerIo* io, short what, void* vhandshake)
|
|||
/* This peer probably doesn't speak uTP. */
|
||||
|
||||
auto const hash = tr_peerIoGetTorrentHash(io);
|
||||
auto* const tor = hash ? handshake->session->getTorrent(*hash) : nullptr;
|
||||
auto* const tor = hash ? handshake->session->torrents().get(*hash) : nullptr;
|
||||
|
||||
/* Don't mark a peer as non-uTP unless it's really a connect failure. */
|
||||
if ((errcode == ETIMEDOUT || errcode == ECONNREFUSED) && tr_isTorrent(tor))
|
||||
|
|
|
@ -294,7 +294,7 @@ tr_address const* tr_peerAddress(tr_peer const* peer)
|
|||
|
||||
static tr_swarm* getExistingSwarm(tr_peerMgr* manager, tr_sha1_digest_t const& hash)
|
||||
{
|
||||
tr_torrent* tor = manager->session->getTorrent(hash);
|
||||
auto* const tor = manager->session->torrents().get(hash);
|
||||
|
||||
return tor == nullptr ? nullptr : tor->swarm;
|
||||
}
|
||||
|
@ -414,7 +414,7 @@ void tr_peerMgrOnBlocklistChanged(tr_peerMgr* mgr)
|
|||
{
|
||||
/* we cache whether or not a peer is blocklisted...
|
||||
since the blocklist has changed, erase that cached value */
|
||||
for (auto* tor : mgr->session->torrents)
|
||||
for (auto* const tor : mgr->session->torrents())
|
||||
{
|
||||
tr_swarm* s = tor->swarm;
|
||||
|
||||
|
@ -657,7 +657,7 @@ static void refillUpkeep(evutil_socket_t /*fd*/, short /*what*/, void* vmgr)
|
|||
auto* mgr = static_cast<tr_peerMgr*>(vmgr);
|
||||
auto const lock = mgr->unique_lock();
|
||||
|
||||
auto& torrents = mgr->session->torrents;
|
||||
auto& torrents = mgr->session->torrents();
|
||||
std::for_each(std::begin(torrents), std::end(torrents), [](auto* tor) { tr_swarmCancelOldRequests(tor->swarm); });
|
||||
|
||||
tr_timerAddMsec(mgr->refillUpkeepTimer, RefillUpkeepPeriodMsec);
|
||||
|
@ -2224,7 +2224,7 @@ static void rechokePulse(evutil_socket_t /*fd*/, short /*what*/, void* vmgr)
|
|||
auto const lock = mgr->unique_lock();
|
||||
uint64_t const now = tr_time_msec();
|
||||
|
||||
for (auto* tor : mgr->session->torrents)
|
||||
for (auto* const tor : mgr->session->torrents())
|
||||
{
|
||||
if (tor->isRunning)
|
||||
{
|
||||
|
@ -2479,9 +2479,10 @@ static void enforceTorrentPeerLimit(tr_swarm* s)
|
|||
static void enforceSessionPeerLimit(tr_session* session)
|
||||
{
|
||||
// do we have too many peers?
|
||||
auto const& torrents = session->torrents();
|
||||
size_t const n_peers = std::accumulate(
|
||||
std::begin(session->torrents),
|
||||
std::end(session->torrents),
|
||||
std::begin(torrents),
|
||||
std::end(torrents),
|
||||
size_t{},
|
||||
[](size_t sum, tr_torrent const* tor) { return sum + tr_ptrArraySize(&tor->swarm->peers); });
|
||||
size_t const max = tr_sessionGetPeerLimit(session);
|
||||
|
@ -2493,7 +2494,7 @@ static void enforceSessionPeerLimit(tr_session* session)
|
|||
// make a list of all the peers
|
||||
auto peers = std::vector<tr_peer*>{};
|
||||
peers.reserve(n_peers);
|
||||
for (auto* tor : session->torrents)
|
||||
for (auto* const tor : session->torrents())
|
||||
{
|
||||
size_t const n = tr_ptrArraySize(&tor->swarm->peers);
|
||||
auto** base = (tr_peer**)tr_ptrArrayBase(&tor->swarm->peers);
|
||||
|
@ -2513,7 +2514,7 @@ static void reconnectPulse(evutil_socket_t /*fd*/, short /*what*/, void* vmgr)
|
|||
time_t const now_sec = tr_time();
|
||||
|
||||
// remove crappy peers
|
||||
for (auto* tor : mgr->session->torrents)
|
||||
for (auto* const tor : mgr->session->torrents())
|
||||
{
|
||||
if (!tor->swarm->isRunning)
|
||||
{
|
||||
|
@ -2526,7 +2527,7 @@ static void reconnectPulse(evutil_socket_t /*fd*/, short /*what*/, void* vmgr)
|
|||
}
|
||||
|
||||
// if we're over the per-torrent peer limits, cull some peers
|
||||
for (auto* tor : mgr->session->torrents)
|
||||
for (auto* const tor : mgr->session->torrents())
|
||||
{
|
||||
if (tor->isRunning)
|
||||
{
|
||||
|
@ -2550,7 +2551,7 @@ static void reconnectPulse(evutil_socket_t /*fd*/, short /*what*/, void* vmgr)
|
|||
|
||||
static void pumpAllPeers(tr_peerMgr* mgr)
|
||||
{
|
||||
for (auto* tor : mgr->session->torrents)
|
||||
for (auto* const tor : mgr->session->torrents())
|
||||
{
|
||||
tr_swarm* s = tor->swarm;
|
||||
|
||||
|
@ -2595,7 +2596,7 @@ static void bandwidthPulse(evutil_socket_t /*fd*/, short /*what*/, void* vmgr)
|
|||
session->bandwidth->allocate(TR_DOWN, BandwidthPeriodMsec);
|
||||
|
||||
/* torrent upkeep */
|
||||
for (auto* tor : session->torrents)
|
||||
for (auto* const tor : session->torrents())
|
||||
{
|
||||
/* possibly stop torrents that have seeded enough */
|
||||
tr_torrentCheckSeedLimit(tor);
|
||||
|
@ -2693,7 +2694,7 @@ static void atomPulse(evutil_socket_t /*fd*/, short /*what*/, void* vmgr)
|
|||
auto* mgr = static_cast<tr_peerMgr*>(vmgr);
|
||||
auto const lock = mgr->unique_lock();
|
||||
|
||||
for (auto* tor : mgr->session->torrents)
|
||||
for (auto* const tor : mgr->session->torrents())
|
||||
{
|
||||
tr_swarm* s = tor->swarm;
|
||||
int const maxAtomCount = getMaxAtomCount(tor);
|
||||
|
@ -2920,7 +2921,7 @@ static std::vector<peer_candidate> getPeerCandidates(tr_session* session, size_t
|
|||
/* count how many peers and atoms we've got */
|
||||
int atomCount = 0;
|
||||
int peerCount = 0;
|
||||
for (auto const* tor : session->torrents)
|
||||
for (auto const* tor : session->torrents())
|
||||
{
|
||||
atomCount += tr_ptrArraySize(&tor->swarm->pool);
|
||||
peerCount += tr_ptrArraySize(&tor->swarm->peers);
|
||||
|
@ -2936,7 +2937,7 @@ static std::vector<peer_candidate> getPeerCandidates(tr_session* session, size_t
|
|||
candidates.reserve(atomCount);
|
||||
|
||||
/* populate the candidate array */
|
||||
for (auto* tor : session->torrents)
|
||||
for (auto* tor : session->torrents())
|
||||
{
|
||||
if (!tor->swarm->isRunning)
|
||||
{
|
||||
|
|
|
@ -133,7 +133,7 @@ static auto getTorrents(tr_session* session, tr_variant* args)
|
|||
}
|
||||
else if (tr_variantGetStrView(node, &sv))
|
||||
{
|
||||
tor = session->getTorrent(sv);
|
||||
tor = session->torrents().get(sv);
|
||||
}
|
||||
|
||||
if (tor != nullptr)
|
||||
|
@ -155,16 +155,16 @@ static auto getTorrents(tr_session* session, tr_variant* args)
|
|||
{
|
||||
time_t const cutoff = tr_time() - RecentlyActiveSeconds;
|
||||
|
||||
torrents.reserve(std::size(session->torrents));
|
||||
torrents.reserve(std::size(session->torrents()));
|
||||
std::copy_if(
|
||||
std::begin(session->torrents),
|
||||
std::end(session->torrents),
|
||||
std::begin(session->torrents()),
|
||||
std::end(session->torrents()),
|
||||
std::back_inserter(torrents),
|
||||
[&cutoff](auto const* tor) { return tor->anyDate >= cutoff; });
|
||||
}
|
||||
else
|
||||
{
|
||||
auto* const tor = session->getTorrent(sv);
|
||||
auto* const tor = session->torrents().get(sv);
|
||||
if (tor != nullptr)
|
||||
{
|
||||
torrents.push_back(tor);
|
||||
|
@ -173,8 +173,8 @@ static auto getTorrents(tr_session* session, tr_variant* args)
|
|||
}
|
||||
else // all of them
|
||||
{
|
||||
torrents.reserve(std::size(session->torrents));
|
||||
std::copy(std::begin(session->torrents), std::end(session->torrents), std::back_inserter(torrents));
|
||||
torrents.reserve(std::size(session->torrents()));
|
||||
std::copy(std::begin(session->torrents()), std::end(session->torrents()), std::back_inserter(torrents));
|
||||
}
|
||||
|
||||
return torrents;
|
||||
|
@ -1977,11 +1977,9 @@ static char const* sessionStats(
|
|||
auto currentStats = tr_session_stats{};
|
||||
auto cumulativeStats = tr_session_stats{};
|
||||
|
||||
int const total = std::size(session->torrents);
|
||||
int const running = std::count_if(
|
||||
std::begin(session->torrents),
|
||||
std::end(session->torrents),
|
||||
[](auto const* tor) { return tor->isRunning; });
|
||||
auto const& torrents = session->torrents();
|
||||
int const total = std::size(torrents);
|
||||
int const running = std::count_if(std::begin(torrents), std::end(torrents), [](auto const* tor) { return tor->isRunning; });
|
||||
|
||||
tr_sessionGetStats(session, ¤tStats);
|
||||
tr_sessionGetCumulativeStats(session, &cumulativeStats);
|
||||
|
|
|
@ -144,17 +144,17 @@ std::optional<std::string> tr_session::WebMediator::publicAddress() const
|
|||
unsigned int tr_session::WebMediator::clamp(int torrent_id, unsigned int byte_count) const
|
||||
{
|
||||
auto const lock = session_->unique_lock();
|
||||
auto const it = session_->torrentsById.find(torrent_id);
|
||||
return it == std::end(session_->torrentsById) ? 0U : it->second->bandwidth->clamp(TR_DOWN, byte_count);
|
||||
auto const* const tor = session_->torrents().get(torrent_id);
|
||||
return tor == nullptr ? 0U : tor->bandwidth->clamp(TR_DOWN, byte_count);
|
||||
}
|
||||
|
||||
void tr_session::WebMediator::notifyBandwidthConsumed(int torrent_id, size_t byte_count)
|
||||
{
|
||||
auto const lock = session_->unique_lock();
|
||||
auto const it = session_->torrentsById.find(torrent_id);
|
||||
if (it != std::end(session_->torrentsById))
|
||||
auto const* const tor = session_->torrents().get(torrent_id);
|
||||
if (tor != nullptr)
|
||||
{
|
||||
it->second->bandwidth->notifyBandwidthConsumed(TR_DOWN, byte_count, true, tr_time_msec());
|
||||
tor->bandwidth->notifyBandwidthConsumed(TR_DOWN, byte_count, true, tr_time_msec());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -574,7 +574,7 @@ static void onSaveTimer(evutil_socket_t /*fd*/, short /*what*/, void* vsession)
|
|||
tr_logAddError("Error while flushing completed pieces from cache");
|
||||
}
|
||||
|
||||
for (auto* tor : session->torrents)
|
||||
for (auto* const tor : session->torrents())
|
||||
{
|
||||
tr_torrentSave(tor);
|
||||
}
|
||||
|
@ -671,7 +671,7 @@ static void onNowTimer(evutil_socket_t /*fd*/, short /*what*/, void* vsession)
|
|||
// TODO: this seems a little silly. Why do we increment this
|
||||
// every second instead of computing the value as needed by
|
||||
// subtracting the current time from a start time?
|
||||
for (auto* tor : session->torrents)
|
||||
for (auto* const tor : session->torrents())
|
||||
{
|
||||
if (tor->isRunning)
|
||||
{
|
||||
|
@ -1233,7 +1233,7 @@ static void peerPortChanged(void* vsession)
|
|||
open_incoming_peer_port(session);
|
||||
tr_sharedPortChanged(session);
|
||||
|
||||
for (auto* tor : session->torrents)
|
||||
for (auto* const tor : session->torrents())
|
||||
{
|
||||
tr_torrentChangeMyPort(tor);
|
||||
}
|
||||
|
@ -1805,17 +1805,16 @@ double tr_sessionGetRawSpeed_KBps(tr_session const* session, tr_direction dir)
|
|||
|
||||
int tr_sessionCountTorrents(tr_session const* session)
|
||||
{
|
||||
return tr_isSession(session) ? std::size(session->torrents) : 0;
|
||||
return tr_isSession(session) ? std::size(session->torrents()) : 0;
|
||||
}
|
||||
|
||||
std::vector<tr_torrent*> tr_sessionGetTorrents(tr_session* session)
|
||||
{
|
||||
TR_ASSERT(tr_isSession(session));
|
||||
|
||||
auto const& src = session->torrents;
|
||||
auto const n = std::size(src);
|
||||
auto const n = std::size(session->torrents());
|
||||
auto torrents = std::vector<tr_torrent*>{ n };
|
||||
std::copy(std::begin(src), std::end(src), std::begin(torrents));
|
||||
std::copy(std::begin(session->torrents()), std::end(session->torrents()), std::begin(torrents));
|
||||
return torrents;
|
||||
}
|
||||
|
||||
|
@ -2275,7 +2274,7 @@ void tr_session::setDefaultTrackers(std::string_view trackers)
|
|||
// if the list changed, update all the public torrents
|
||||
if (default_trackers_ != oldval)
|
||||
{
|
||||
for (auto* tor : torrents)
|
||||
for (auto* const tor : torrents())
|
||||
{
|
||||
if (tor->isPublic())
|
||||
{
|
||||
|
@ -2808,7 +2807,7 @@ std::vector<tr_torrent*> tr_sessionGetNextQueuedTorrents(tr_session* session, tr
|
|||
// build an array of the candidates
|
||||
auto candidates = std::vector<tr_torrent*>{};
|
||||
candidates.reserve(tr_sessionCountTorrents(session));
|
||||
for (auto* tor : session->torrents)
|
||||
for (auto* const tor : session->torrents())
|
||||
{
|
||||
if (tor->isQueued() && (direction == tor->queueDirection()))
|
||||
{
|
||||
|
@ -2846,7 +2845,7 @@ int tr_sessionCountQueueFreeSlots(tr_session* session, tr_direction dir)
|
|||
bool const stalled_enabled = tr_sessionGetQueueStalledEnabled(session);
|
||||
int const stalled_if_idle_for_n_seconds = tr_sessionGetQueueStalledMinutes(session) * 60;
|
||||
time_t const now = tr_time();
|
||||
for (auto const* tor : session->torrents)
|
||||
for (auto const* const tor : session->torrents())
|
||||
{
|
||||
/* is it the right activity? */
|
||||
if (activity != tr_torrentGetActivity(tor))
|
||||
|
@ -2875,23 +2874,3 @@ int tr_sessionCountQueueFreeSlots(tr_session* session, tr_direction dir)
|
|||
|
||||
return max - active_count;
|
||||
}
|
||||
|
||||
void tr_sessionAddTorrent(tr_session* session, tr_torrent* tor)
|
||||
{
|
||||
session->torrents.insert(tor);
|
||||
session->torrentsById.insert_or_assign(tor->uniqueId, tor);
|
||||
session->torrentsByHash.insert_or_assign(tor->infoHash(), tor);
|
||||
}
|
||||
|
||||
void tr_sessionRemoveTorrent(tr_session* session, tr_torrent* tor)
|
||||
{
|
||||
session->torrents.erase(tor);
|
||||
session->torrentsById.erase(tor->uniqueId);
|
||||
session->torrentsByHash.erase(tor->infoHash());
|
||||
}
|
||||
|
||||
tr_torrent* tr_session::getTorrent(std::string_view info_dict_hash_string)
|
||||
{
|
||||
auto const info_hash = tr_sha1_from_string(info_dict_hash_string);
|
||||
return info_hash ? this->getTorrent(*info_hash) : nullptr;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "announce-list.h"
|
||||
#include "net.h" // tr_socket_t
|
||||
#include "quark.h"
|
||||
#include "torrents.h"
|
||||
#include "web.h"
|
||||
|
||||
enum tr_auto_switch_state_t
|
||||
|
@ -108,6 +109,16 @@ struct tr_turtle_info
|
|||
struct tr_session
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] auto const& torrents() const
|
||||
{
|
||||
return torrents_;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto& torrents()
|
||||
{
|
||||
return torrents_;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto unique_lock() const
|
||||
{
|
||||
return std::unique_lock(session_mutex_);
|
||||
|
@ -118,27 +129,6 @@ public:
|
|||
return is_closing_;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto const* getTorrent(tr_sha1_digest_t const& info_dict_hash) const
|
||||
{
|
||||
auto& src = this->torrentsByHash;
|
||||
auto it = src.find(info_dict_hash);
|
||||
return it == std::end(src) ? nullptr : it->second;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto* getTorrent(tr_sha1_digest_t const& info_dict_hash)
|
||||
{
|
||||
auto& src = this->torrentsByHash;
|
||||
auto it = src.find(info_dict_hash);
|
||||
return it == std::end(src) ? nullptr : it->second;
|
||||
}
|
||||
|
||||
[[nodiscard]] tr_torrent* getTorrent(std::string_view info_dict_hash_string);
|
||||
|
||||
[[nodiscard]] auto contains(tr_sha1_digest_t const& info_dict_hash) const
|
||||
{
|
||||
return getTorrent(info_dict_hash) != nullptr;
|
||||
}
|
||||
|
||||
// download dir
|
||||
|
||||
std::string const& downloadDir() const
|
||||
|
@ -348,10 +338,6 @@ public:
|
|||
tr_port randomPortLow;
|
||||
tr_port randomPortHigh;
|
||||
|
||||
std::unordered_set<tr_torrent*> torrents;
|
||||
std::map<int, tr_torrent*> torrentsById;
|
||||
std::map<tr_sha1_digest_t, tr_torrent*> torrentsByHash;
|
||||
|
||||
std::string config_dir;
|
||||
std::string resume_dir;
|
||||
std::string torrent_dir;
|
||||
|
@ -423,6 +409,8 @@ public:
|
|||
private:
|
||||
static std::recursive_mutex session_mutex_;
|
||||
|
||||
tr_torrents torrents_;
|
||||
|
||||
std::array<std::string, TR_SCRIPT_N_TYPES> scripts_;
|
||||
std::string blocklist_url_;
|
||||
std::string download_dir_;
|
||||
|
@ -492,6 +480,3 @@ bool tr_sessionGetActiveSpeedLimit_Bps(tr_session const* session, tr_direction d
|
|||
std::vector<tr_torrent*> tr_sessionGetNextQueuedTorrents(tr_session* session, tr_direction dir, size_t numwanted);
|
||||
|
||||
int tr_sessionCountQueueFreeSlots(tr_session* session, tr_direction);
|
||||
|
||||
void tr_sessionAddTorrent(tr_session* session, tr_torrent* tor);
|
||||
void tr_sessionRemoveTorrent(tr_session* session, tr_torrent* tor);
|
||||
|
|
|
@ -88,14 +88,12 @@ int tr_torrentId(tr_torrent const* tor)
|
|||
|
||||
tr_torrent* tr_torrentFindFromId(tr_session* session, int id)
|
||||
{
|
||||
auto& src = session->torrentsById;
|
||||
auto it = src.find(id);
|
||||
return it == std::end(src) ? nullptr : it->second;
|
||||
return session->torrents().get(id);
|
||||
}
|
||||
|
||||
tr_torrent* tr_torrentFindFromHash(tr_session* session, tr_sha1_digest_t const* hash)
|
||||
{
|
||||
return hash == nullptr ? nullptr : session->getTorrent(*hash);
|
||||
return hash == nullptr ? nullptr : session->torrents().get(*hash);
|
||||
}
|
||||
|
||||
tr_torrent* tr_torrentFindFromMetainfo(tr_session* session, tr_torrent_metainfo const* metainfo)
|
||||
|
@ -105,18 +103,17 @@ tr_torrent* tr_torrentFindFromMetainfo(tr_session* session, tr_torrent_metainfo
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
return tr_torrentFindFromHash(session, &metainfo->infoHash());
|
||||
return session->torrents().get(metainfo->infoHash());
|
||||
}
|
||||
|
||||
tr_torrent* tr_torrentFindFromMagnetLink(tr_session* session, char const* magnet_link)
|
||||
{
|
||||
auto mm = tr_magnet_metainfo{};
|
||||
return mm.parseMagnet(magnet_link != nullptr ? magnet_link : "") ? session->getTorrent(mm.infoHash()) : nullptr;
|
||||
return magnet_link == nullptr ? nullptr : session->torrents().get(magnet_link);
|
||||
}
|
||||
|
||||
tr_torrent* tr_torrentFindFromObfuscatedHash(tr_session* session, tr_sha1_digest_t const& obfuscated_hash)
|
||||
{
|
||||
for (auto* tor : session->torrents)
|
||||
for (auto* const tor : session->torrents())
|
||||
{
|
||||
if (tor->obfuscated_hash == obfuscated_hash)
|
||||
{
|
||||
|
@ -675,14 +672,12 @@ static void refreshCurrentDir(tr_torrent* tor);
|
|||
|
||||
static void torrentInit(tr_torrent* tor, tr_ctor const* ctor)
|
||||
{
|
||||
static auto next_unique_id = int{ 1 };
|
||||
auto const lock = tor->unique_lock();
|
||||
|
||||
tr_session* session = tr_ctorGetSession(ctor);
|
||||
TR_ASSERT(session != nullptr);
|
||||
|
||||
tor->session = session;
|
||||
tor->uniqueId = next_unique_id++;
|
||||
tor->queuePosition = tr_sessionCountTorrents(session);
|
||||
|
||||
torrentInitFromInfoDict(tor);
|
||||
|
@ -765,7 +760,7 @@ static void torrentInit(tr_torrent* tor, tr_ctor const* ctor)
|
|||
tr_torrentSetIdleLimit(tor, tr_sessionGetIdleLimit(tor->session));
|
||||
}
|
||||
|
||||
tr_sessionAddTorrent(session, tor);
|
||||
tor->uniqueId = session->torrents().add(tor);
|
||||
|
||||
// if we don't have a local .torrent or .magnet file already, assume the torrent is new
|
||||
auto const filename = tor->hasMetadata() ? tor->torrentFile() : tor->magnetFile();
|
||||
|
@ -845,7 +840,7 @@ tr_torrent* tr_torrentNew(tr_ctor* ctor, tr_torrent** setme_duplicate_of)
|
|||
}
|
||||
|
||||
// is it a duplicate?
|
||||
if (auto* const duplicate_of = session->getTorrent(metainfo.infoHash()); duplicate_of != nullptr)
|
||||
if (auto* const duplicate_of = session->torrents().get(metainfo.infoHash()); duplicate_of != nullptr)
|
||||
{
|
||||
if (setme_duplicate_of != nullptr)
|
||||
{
|
||||
|
@ -1298,13 +1293,13 @@ static void freeTorrent(tr_torrent* tor)
|
|||
|
||||
tr_announcerRemoveTorrent(session->announcer, tor);
|
||||
|
||||
tr_sessionRemoveTorrent(session, tor);
|
||||
session->torrents().remove(tor, tr_time());
|
||||
|
||||
if (!session->isClosing())
|
||||
{
|
||||
// "so you die, captain, and we all move up in rank."
|
||||
// resequence the queue positions
|
||||
for (auto* t : session->torrents)
|
||||
for (auto* t : session->torrents())
|
||||
{
|
||||
if (t->queuePosition > tor->queuePosition)
|
||||
{
|
||||
|
@ -2768,7 +2763,7 @@ void tr_torrentSetQueuePosition(tr_torrent* tor, int pos)
|
|||
|
||||
tor->queuePosition = -1;
|
||||
|
||||
for (auto* walk : tor->session->torrents)
|
||||
for (auto* const walk : tor->session->torrents())
|
||||
{
|
||||
if ((old_pos < pos) && (old_pos <= walk->queuePosition) && (walk->queuePosition <= pos))
|
||||
{
|
||||
|
|
|
@ -0,0 +1,141 @@
|
|||
// This file Copyright © 2022 Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0), GPLv3 (SPDX: GPL-3.0),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
||||
#include <set>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "transmission.h"
|
||||
|
||||
#include "magnet-metainfo.h"
|
||||
#include "torrent.h"
|
||||
#include "torrents.h"
|
||||
#include "tr-assert.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct CompareTorrentByHash
|
||||
{
|
||||
bool operator()(tr_sha1_digest_t const& a, tr_sha1_digest_t const& b) const
|
||||
{
|
||||
return a < b;
|
||||
}
|
||||
|
||||
bool operator()(tr_torrent const* a, tr_torrent const* b) const
|
||||
{
|
||||
return (*this)(a->infoHash(), b->infoHash());
|
||||
}
|
||||
|
||||
bool operator()(tr_torrent const* a, tr_sha1_digest_t const& b) const
|
||||
{
|
||||
return (*this)(a->infoHash(), b);
|
||||
}
|
||||
|
||||
bool operator()(tr_sha1_digest_t const& a, tr_torrent const* b) const
|
||||
{
|
||||
return (*this)(a, b->infoHash());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
tr_torrents::tr_torrents()
|
||||
// Insert an empty pointer at by_id_[0] to ensure that the first added
|
||||
// torrent doesn't get an ID of 0; ie, that every torrent has a positive
|
||||
// ID number. This constraint isn't needed by libtransmission code but
|
||||
// the ID is exported in the RPC API to 3rd party clients that may be
|
||||
// testing for >0 as a validity check.
|
||||
: by_id_{ nullptr }
|
||||
{
|
||||
}
|
||||
|
||||
tr_torrent const* tr_torrents::get(int id) const
|
||||
{
|
||||
TR_ASSERT(0 <= id);
|
||||
TR_ASSERT(static_cast<size_t>(id) < std::size(by_id_));
|
||||
if (static_cast<size_t>(id) >= std::size(by_id_))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto const* tor = by_id_.at(id);
|
||||
TR_ASSERT(tor == nullptr || tor->uniqueId == id);
|
||||
TR_ASSERT(removed_.count(id) == (tor == nullptr ? 1 : 0));
|
||||
return tor;
|
||||
}
|
||||
|
||||
tr_torrent* tr_torrents::get(int id)
|
||||
{
|
||||
TR_ASSERT(0 <= id);
|
||||
TR_ASSERT(static_cast<size_t>(id) < std::size(by_id_));
|
||||
if (static_cast<size_t>(id) >= std::size(by_id_))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto* tor = by_id_.at(id);
|
||||
TR_ASSERT(tor == nullptr || tor->uniqueId == id);
|
||||
TR_ASSERT(removed_.count(id) == (tor == nullptr ? 1 : 0));
|
||||
return tor;
|
||||
}
|
||||
|
||||
tr_torrent const* tr_torrents::get(std::string_view magnet_link) const
|
||||
{
|
||||
auto magnet = tr_magnet_metainfo{};
|
||||
return magnet.parseMagnet(magnet_link) ? get(magnet.infoHash()) : nullptr;
|
||||
}
|
||||
|
||||
tr_torrent* tr_torrents::get(std::string_view magnet_link)
|
||||
{
|
||||
auto magnet = tr_magnet_metainfo{};
|
||||
return magnet.parseMagnet(magnet_link) ? get(magnet.infoHash()) : nullptr;
|
||||
}
|
||||
|
||||
tr_torrent* tr_torrents::get(tr_sha1_digest_t const& hash)
|
||||
{
|
||||
auto [begin, end] = std::equal_range(std::begin(by_hash_), std::end(by_hash_), hash, CompareTorrentByHash{});
|
||||
return begin == end ? nullptr : *begin;
|
||||
}
|
||||
|
||||
tr_torrent const* tr_torrents::get(tr_sha1_digest_t const& hash) const
|
||||
{
|
||||
auto [begin, end] = std::equal_range(std::cbegin(by_hash_), std::cend(by_hash_), hash, CompareTorrentByHash{});
|
||||
return begin == end ? nullptr : *begin;
|
||||
}
|
||||
|
||||
int tr_torrents::add(tr_torrent* tor)
|
||||
{
|
||||
int const id = static_cast<int>(std::size(by_id_));
|
||||
by_id_.push_back(tor);
|
||||
by_hash_.insert(std::lower_bound(std::begin(by_hash_), std::end(by_hash_), tor, CompareTorrentByHash{}), tor);
|
||||
return id;
|
||||
}
|
||||
|
||||
void tr_torrents::remove(tr_torrent const* tor, time_t timestamp)
|
||||
{
|
||||
TR_ASSERT(tor != nullptr);
|
||||
TR_ASSERT(get(tor->uniqueId) == tor);
|
||||
|
||||
by_id_[tor->uniqueId] = nullptr;
|
||||
auto const [begin, end] = std::equal_range(std::begin(by_hash_), std::end(by_hash_), tor, CompareTorrentByHash{});
|
||||
by_hash_.erase(begin, end);
|
||||
removed_.insert_or_assign(tor->uniqueId, timestamp);
|
||||
}
|
||||
|
||||
std::set<int> tr_torrents::removedSince(time_t timestamp) const
|
||||
{
|
||||
auto ret = std::set<int>{};
|
||||
|
||||
for (auto const& [id, removed_at] : removed_)
|
||||
{
|
||||
if (removed_at >= timestamp)
|
||||
{
|
||||
ret.insert(id);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
// This file Copyright © 2022 Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0), GPLv3 (SPDX: GPL-3.0),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __TRANSMISSION__
|
||||
#error only libtransmission should #include this header.
|
||||
#endif
|
||||
|
||||
#include <ctime>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "transmission.h"
|
||||
|
||||
#include "torrent-metainfo.h"
|
||||
|
||||
struct tr_torrent;
|
||||
struct tr_torrent_metainfo;
|
||||
|
||||
// A helper class to manage tracking sets of tr_torrent objects.
|
||||
class tr_torrents
|
||||
{
|
||||
public:
|
||||
tr_torrents();
|
||||
|
||||
// returns a fast lookup id for `tor`
|
||||
[[nodiscard]] int add(tr_torrent* tor);
|
||||
|
||||
void remove(tr_torrent const* tor, time_t current_time);
|
||||
|
||||
// O(1)
|
||||
[[nodiscard]] tr_torrent* get(int id);
|
||||
[[nodiscard]] tr_torrent const* get(int id) const;
|
||||
|
||||
// O(log n)
|
||||
[[nodiscard]] tr_torrent const* get(tr_sha1_digest_t const& hash) const;
|
||||
[[nodiscard]] tr_torrent* get(tr_sha1_digest_t const& hash);
|
||||
|
||||
[[nodiscard]] tr_torrent const* get(tr_torrent_metainfo const& metainfo) const
|
||||
{
|
||||
return get(metainfo.infoHash());
|
||||
}
|
||||
|
||||
[[nodiscard]] tr_torrent* get(tr_torrent_metainfo const& metainfo)
|
||||
{
|
||||
return get(metainfo.infoHash());
|
||||
}
|
||||
|
||||
// These convenience functions use get(tr_sha1_digest_t const&)
|
||||
// after parsing the magnet link to get the info hash. If you have
|
||||
// the info hash already, use get() instead to avoid excess parsing.
|
||||
[[nodiscard]] tr_torrent const* get(std::string_view magnet_link) const;
|
||||
[[nodiscard]] tr_torrent* get(std::string_view magnet_link);
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] bool contains(T const& key) const
|
||||
{
|
||||
return get(key) != nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::set<int> removedSince(time_t) const;
|
||||
|
||||
[[nodiscard]] auto cbegin() const
|
||||
{
|
||||
return std::cbegin(by_hash_);
|
||||
}
|
||||
[[nodiscard]] auto begin() const
|
||||
{
|
||||
return cbegin();
|
||||
}
|
||||
[[nodiscard]] auto begin()
|
||||
{
|
||||
return std::begin(by_hash_);
|
||||
}
|
||||
|
||||
[[nodiscard]] auto cend() const
|
||||
{
|
||||
return std::cend(by_hash_);
|
||||
}
|
||||
|
||||
[[nodiscard]] auto end() const
|
||||
{
|
||||
return cend();
|
||||
}
|
||||
|
||||
[[nodiscard]] auto end()
|
||||
{
|
||||
return std::end(by_hash_);
|
||||
}
|
||||
|
||||
[[nodiscard]] auto size() const
|
||||
{
|
||||
return std::size(by_hash_);
|
||||
}
|
||||
|
||||
[[nodiscard]] auto empty() const
|
||||
{
|
||||
return std::empty(by_hash_);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<tr_torrent*> by_hash_;
|
||||
|
||||
// This is a lookup table where by_id_[id]->uniqueId == id.
|
||||
// There is a small tradeoff here -- lookup is O(1) at the cost
|
||||
// of a wasted slot in the lookup table whenever a torrent is
|
||||
// removed. This improves speed for all use cases at the cost of
|
||||
// wasting a small amount of memory in uncommon use cases, e.g. a
|
||||
// long-lived session where thousands of torrents are removed
|
||||
std::vector<tr_torrent*> by_id_;
|
||||
|
||||
std::map<int, time_t> removed_;
|
||||
};
|
|
@ -600,7 +600,7 @@ static void callback(void* /*ignore*/, int event, unsigned char const* info_hash
|
|||
auto hash = tr_sha1_digest_t{};
|
||||
std::copy_n(reinterpret_cast<std::byte const*>(info_hash), std::size(hash), std::data(hash));
|
||||
auto const lock = session_->unique_lock();
|
||||
tr_torrent* const tor = session_->getTorrent(hash);
|
||||
auto* const tor = session_->torrents().get(hash);
|
||||
|
||||
if (event == DHT_EVENT_VALUES || event == DHT_EVENT_VALUES6)
|
||||
{
|
||||
|
@ -700,7 +700,7 @@ void tr_dhtUpkeep(tr_session* session)
|
|||
{
|
||||
time_t const now = tr_time();
|
||||
|
||||
for (auto* tor : session->torrents)
|
||||
for (auto* const tor : session->torrents())
|
||||
{
|
||||
if (!tor->isRunning || !tor->allowsDht())
|
||||
{
|
||||
|
|
|
@ -533,7 +533,7 @@ static int tr_lpdConsiderAnnounce(tr_pex* peer, char const* const msg)
|
|||
return res;
|
||||
}
|
||||
|
||||
tor = session->getTorrent(hashString);
|
||||
tor = session->torrents().get(hashString);
|
||||
|
||||
if (tr_isTorrent(tor) && tor->allowsLpd())
|
||||
{
|
||||
|
@ -576,7 +576,7 @@ static int tr_lpdAnnounceMore(time_t const now, int const interval)
|
|||
|
||||
if (tr_sessionAllowsLPD(session))
|
||||
{
|
||||
for (auto* tor : session->torrents)
|
||||
for (auto* const tor : session->torrents())
|
||||
{
|
||||
int announcePrio = 0;
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ add_executable(libtransmission-test
|
|||
subprocess-test.cc
|
||||
test-fixtures.h
|
||||
torrent-metainfo-test.cc
|
||||
torrents-test.cc
|
||||
utils-test.cc
|
||||
variant-test.cc
|
||||
watchdir-test.cc
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,122 @@
|
|||
// This file Copyright (C) 2022 Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0), GPLv3 (SPDX: GPL-3.0),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
||||
#include "transmission.h"
|
||||
|
||||
#include "torrent.h"
|
||||
#include "torrents.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <set>
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
using TorrentsTest = ::testing::Test;
|
||||
|
||||
TEST_F(TorrentsTest, simpleTests)
|
||||
{
|
||||
auto constexpr* const TorrentFile = LIBTRANSMISSION_TEST_ASSETS_DIR "/Android-x86 8.1 r6 iso.torrent";
|
||||
auto tm = tr_torrent_metainfo{};
|
||||
EXPECT_TRUE(tm.parseTorrentFile(TorrentFile));
|
||||
auto* tor = new tr_torrent(std::move(tm));
|
||||
EXPECT_NE(nullptr, tor);
|
||||
|
||||
auto torrents = tr_torrents{};
|
||||
EXPECT_TRUE(std::empty(torrents));
|
||||
EXPECT_EQ(0U, std::size(torrents));
|
||||
|
||||
auto const id = torrents.add(tor);
|
||||
EXPECT_GT(id, 0);
|
||||
tor->uniqueId = id;
|
||||
|
||||
EXPECT_TRUE(std::empty(torrents.removedSince(0)));
|
||||
EXPECT_FALSE(std::empty(torrents));
|
||||
EXPECT_EQ(1U, std::size(torrents));
|
||||
|
||||
EXPECT_EQ(tor, torrents.get(id));
|
||||
EXPECT_EQ(tor, torrents.get(tor->infoHash()));
|
||||
EXPECT_EQ(tor, torrents.get(tor->magnet()));
|
||||
|
||||
tm = tr_torrent_metainfo{};
|
||||
EXPECT_TRUE(tm.parseTorrentFile(TorrentFile));
|
||||
EXPECT_EQ(tor, torrents.get(tm));
|
||||
|
||||
// cleanup
|
||||
torrents.remove(tor, time(nullptr));
|
||||
delete tor;
|
||||
}
|
||||
|
||||
TEST_F(TorrentsTest, rangedLoop)
|
||||
{
|
||||
auto constexpr Filenames = std::array<std::string_view, 4>{ "Android-x86 8.1 r6 iso.torrent"sv,
|
||||
"debian-11.2.0-amd64-DVD-1.iso.torrent"sv,
|
||||
"ubuntu-18.04.6-desktop-amd64.iso.torrent"sv,
|
||||
"ubuntu-20.04.4-desktop-amd64.iso.torrent"sv };
|
||||
|
||||
auto torrents = tr_torrents{};
|
||||
auto torrents_set = std::set<tr_torrent const*>{};
|
||||
|
||||
for (auto const& name : Filenames)
|
||||
{
|
||||
auto const path = tr_strvJoin(LIBTRANSMISSION_TEST_ASSETS_DIR, "/"sv, name);
|
||||
auto tm = tr_torrent_metainfo{};
|
||||
EXPECT_TRUE(tm.parseTorrentFile(path));
|
||||
auto* const tor = new tr_torrent(std::move(tm));
|
||||
tor->uniqueId = torrents.add(tor);
|
||||
EXPECT_EQ(tor, torrents.get(tor->uniqueId));
|
||||
torrents_set.insert(tor);
|
||||
}
|
||||
|
||||
for (auto const* tor : torrents)
|
||||
{
|
||||
EXPECT_EQ(1U, torrents_set.erase(tor));
|
||||
}
|
||||
EXPECT_EQ(0U, std::size(torrents_set));
|
||||
EXPECT_EQ(0U, std::size(torrents_set));
|
||||
}
|
||||
|
||||
TEST_F(TorrentsTest, removedSince)
|
||||
{
|
||||
auto constexpr Filenames = std::array<std::string_view, 4>{ "Android-x86 8.1 r6 iso.torrent"sv,
|
||||
"debian-11.2.0-amd64-DVD-1.iso.torrent"sv,
|
||||
"ubuntu-18.04.6-desktop-amd64.iso.torrent"sv,
|
||||
"ubuntu-20.04.4-desktop-amd64.iso.torrent"sv };
|
||||
|
||||
auto torrents = tr_torrents{};
|
||||
auto torrents_v = std::vector<tr_torrent const*>{};
|
||||
torrents_v.reserve(std::size(Filenames));
|
||||
|
||||
// setup: add the torrents
|
||||
for (auto const& name : Filenames)
|
||||
{
|
||||
auto const path = tr_strvJoin(LIBTRANSMISSION_TEST_ASSETS_DIR, "/"sv, name);
|
||||
auto tm = tr_torrent_metainfo{};
|
||||
auto* const tor = new tr_torrent(std::move(tm));
|
||||
tor->uniqueId = torrents.add(tor);
|
||||
torrents_v.push_back(tor);
|
||||
}
|
||||
|
||||
// setup: remove them at the given timestamp
|
||||
auto constexpr TimeRemoved = std::array<time_t, 4>{ 100, 200, 200, 300 };
|
||||
for (size_t i = 0; i < 4; ++i)
|
||||
{
|
||||
auto* const tor = torrents_v[i];
|
||||
EXPECT_EQ(tor, torrents.get(tor->uniqueId));
|
||||
torrents.remove(torrents_v[i], TimeRemoved[i]);
|
||||
EXPECT_EQ(nullptr, torrents.get(tor->uniqueId));
|
||||
}
|
||||
|
||||
auto remove = std::set<int>{};
|
||||
remove = { torrents_v[3]->uniqueId };
|
||||
EXPECT_EQ(remove, torrents.removedSince(300));
|
||||
EXPECT_EQ(remove, torrents.removedSince(201));
|
||||
remove = { torrents_v[1]->uniqueId, torrents_v[2]->uniqueId, torrents_v[3]->uniqueId };
|
||||
EXPECT_EQ(remove, torrents.removedSince(200));
|
||||
remove = { torrents_v[0]->uniqueId, torrents_v[1]->uniqueId, torrents_v[2]->uniqueId, torrents_v[3]->uniqueId };
|
||||
EXPECT_EQ(remove, torrents.removedSince(50));
|
||||
}
|
Loading…
Reference in New Issue