collect and return unload/download rate stats

This commit is contained in:
orignal
2026-08-18 20:53:38 -04:00
parent 2b37acc525
commit 4f138ac630
3 changed files with 79 additions and 8 deletions
+58 -1
View File
@@ -305,6 +305,7 @@ namespace torrents
m_Length (0), m_PieceLength (0), m_Interval (MIN_TRACKER_REQUESTS_INTERVAL),
m_NextTrackerRequestTime (0), m_IsComplete (false), m_Uploaded (0)
{
ResetStats ();
ParseDictionary (buf, [this](std::string_view key, std::string_view buf)->size_t
{
if (key == "announce")
@@ -662,7 +663,9 @@ namespace torrents
i2p::client::I2PServiceHandler (owner), m_Stream (stream), m_ReceiveBufferOffset (0),
m_IsHandshakeSent (false), m_IsEstablished (false), m_IsChoked (true), m_IsRemoteChoked (true),
m_IsInterested (false), m_IsRemoteInterested (false), m_LastReceiveTime (0), m_LastSendTime (0),
m_NumRequests (0), m_NumPieces (0), m_LastRequestedPieceIndex (-1)
m_NumRequests (0), m_NumPieces (0), m_LastRequestedPieceIndex (-1),
m_DownloadRate (0), m_UploadRate (0), m_LastBlockDownloadTimestamp (0),
m_LastBlockUploadTimestamp (0), m_ReceivedSinceLastTimestamp (0)
{
}
@@ -1124,6 +1127,24 @@ namespace torrents
}
if (m_NumRequests > 0) m_NumRequests--;
RequestNextBlocks ();
// update stats
auto ts = i2p::util::GetMonotonicMilliseconds ();
if (m_LastBlockDownloadTimestamp)
{
m_ReceivedSinceLastTimestamp += REQUEST_BLOCK_SIZE;
auto delta = ts - m_LastBlockDownloadTimestamp;
if (delta >= BANDWIDTH_RATE_SAMPLING_INTERVAL)
{
if (m_DownloadRate)
m_DownloadRate = (m_DownloadRate + m_ReceivedSinceLastTimestamp*1000/delta)/2;
else
m_DownloadRate = m_ReceivedSinceLastTimestamp*1000/delta;
m_LastBlockDownloadTimestamp = ts;
m_ReceivedSinceLastTimestamp = 0;
}
}
else
m_LastBlockDownloadTimestamp = ts;
}
void PeerConnection::SendPieceMsg (uint32_t index, uint32_t offset, const uint8_t * data, size_t len)
@@ -1154,6 +1175,20 @@ namespace torrents
s->m_IsRemoteChoked = false;
s->SendUnchokeMsg ();
}
// update status
auto ts = i2p::util::GetMonotonicMilliseconds ();
if (s->m_LastBlockUploadTimestamp)
{
auto delta = ts - s->m_LastBlockUploadTimestamp;
if (delta)
{
if (s->m_UploadRate)
s->m_UploadRate = (s->m_UploadRate + REQUEST_BLOCK_SIZE*1000/delta)/2;
else
s->m_UploadRate = REQUEST_BLOCK_SIZE*1000/delta;
}
}
s->m_LastBlockUploadTimestamp = ts;
}
else
s->Terminate ();
@@ -1910,6 +1945,7 @@ namespace torrents
{
auto ts = i2p::util::GetMonotonicSeconds ();
for (auto it: m_Torrents)
{
if (!it.second->IsComplete ())
{
if (it.second->UpdateStatus (ts))
@@ -1917,6 +1953,8 @@ namespace torrents
else
UpdatePeersPerPiece (it.second);
}
}
UpdateStats ();
ScheduleStatusUpdate ();
}
}
@@ -1990,5 +2028,24 @@ namespace torrents
}
});
}
void TorrentsTunnel::UpdateStats ()
{
for (auto it: m_Torrents)
it.second->ResetStats ();
IterateHandlers ([](std::shared_ptr<i2p::client::I2PServiceHandler> handler) mutable
{
if (handler)
{
auto conn = std::static_pointer_cast<PeerConnection>(handler);
auto torrent = conn->GetTorrent ();
if (torrent)
{
torrent->SetDownloadRate (torrent->GetDownloadRate () + conn->GetDownloadRate ());
torrent->SetUploadRate (torrent->GetUploadRate () + conn->GetUploadRate ());
}
}
});
}
}
}
+17 -1
View File
@@ -53,6 +53,7 @@ namespace torrents
constexpr int PIECE_INACTIVITY_TIMEOUT = 60; // in seconds
constexpr int TORRENTS_STATUS_UPDATE_INTERVAL = 25; // in seconds
constexpr int HANDSHAKE_RECEIVE_TIMEOUT = 20; // in seconds
constexpr int BANDWIDTH_RATE_SAMPLING_INTERVAL = 20; // in milliseconds
constexpr size_t HANDSHAKE_MSG_LENGTH = 68;
constexpr size_t INTERESTED_MSG_LENGTH = 5;
@@ -196,6 +197,12 @@ namespace torrents
void ApplyPeerRemoteBitfield (const boost::dynamic_bitset<>& peerRemoteBitfield);
bool HasIncompletePieces (const boost::dynamic_bitset<>& peerRemoteBitfield) const; // if remote bitfie;d has incomplete pieces
void ResetStats () { m_DownloadRate = 0; m_UploadRate = 0; }
uint64_t GetDownloadRate () const { return m_DownloadRate; }
void SetDownloadRate (uint64_t downloadRate) { m_DownloadRate = downloadRate; }
uint64_t GetUploadRate () const { return m_UploadRate; }
void SetUploadRate (uint64_t uploadRate) { m_UploadRate = uploadRate; }
private:
size_t ParsePieces (std::string_view buf);
@@ -216,6 +223,8 @@ namespace torrents
bool m_IsComplete;
std::list<std::pair<std::filesystem::path, size_t> > m_Files; // list of (path, length)
size_t m_Uploaded;
// stats
uint64_t m_DownloadRate, m_UploadRate; // B/sec
};
class TorrentsTunnel;
@@ -247,6 +256,9 @@ namespace torrents
int GetLastRequestedPieceIndex () const { return m_LastRequestedPieceIndex; }
const boost::dynamic_bitset<>& GetRemoteBitfield () const { return m_RemoteBitfield;} ;
uint64_t GetDownloadRate () const { return m_DownloadRate; }
uint64_t GetUploadRate () const { return m_UploadRate; }
private:
void Terminate ();
@@ -281,7 +293,6 @@ namespace torrents
bool RequestNextBlock ();
void RequestNextBlock (uint32_t index, uint32_t offset, uint32_t len);
bool RequestNextBlocks ();
bool SendRequestedBlock (const RequestedBlock& requestedBlock);
private:
@@ -299,6 +310,10 @@ namespace torrents
std::list<RequestedBlock> m_IncomingRequestsQueue;
int m_LastRequestedPieceIndex;
std::unique_ptr<boost::asio::steady_timer> m_HandshakeReceiveTimer;
// stats
uint64_t m_DownloadRate, m_UploadRate; // B/sec
uint64_t m_LastBlockDownloadTimestamp, m_LastBlockUploadTimestamp; // monotonic milliseconds
size_t m_ReceivedSinceLastTimestamp; // bytes
};
class TorrentsTunnel final: public i2p::client::I2PService
@@ -365,6 +380,7 @@ namespace torrents
void ConnectToPeer (std::shared_ptr<Torrent> torrent, const i2p::data::IdentHash& peer);
size_t ConnectToPeers (std::shared_ptr<Torrent> torrent);
void UpdatePeersPerPiece (std::shared_ptr<Torrent> torrent);
void UpdateStats ();
private:
+4 -6
View File
@@ -152,9 +152,7 @@ namespace torrents
{
auto arguments = jsonRequest.at ("arguments").as_object ();
bool deleteFiles = false;
if (arguments.contains ("delete_local_data")) // for transmission >= 4.1
deleteFiles = arguments.at ("delete_local_data").as_bool ();
else if (arguments.contains ("delete-local-data")) // for transmission < 4.1
if (arguments.contains ("delete-local-data"))
deleteFiles = arguments.at ("delete-local-data").as_bool ();
std::vector<int> torrentIds;
if (arguments.contains ("ids"))
@@ -204,9 +202,9 @@ namespace torrents
t["is_finished"] = torrent->IsComplete ();
t["size_when_done"] = torrent->GetLength ();
t["left_until_done"] = torrent->GetLeft ();
t["eta"] = 1; // TODO
t["rate_download"] = 1000; // B/s TODO:
t["rate_upload"] = 0; // B/s TODO:
t["eta"] = 600; // TODO
t["rate_download"] = torrent->GetDownloadRate ();
t["rate_upload"] = torrent->GetUploadRate ();
t["upload_ratio"] = 1; // TODO:
if (torrentsRequested)
{