Skip to content

Commit

Permalink
Merge #119: Refactor: rename peer.updated field in torrent detail end…
Browse files Browse the repository at this point in the history
…point

e1b84f6 refactor: [#61] extract struct ApiClient for API testing (Jose Celano)
bc3d246 feat(api): in torrent endpoint rename field  to (Jose Celano)
7e03714 refactor: [#61] use StatsResource in API stats endpoint (Jose Celano)
b974ce0 refactor: [#61] use TorrentListItemResource in torrent list API endpoint (Jose Celano)
284c91b test: [#61] add e2e test for torrent list API endpoint (Jose Celano)
7298701 refactor: [#61] extract converter from TorrentPeer to TorrentPeerResource (Jose Celano)
801dfe6 refactor: [#61] use TorrentResource in torrent info API endpoint (Jose Celano)
ea92ceb test: [#61] add e2e test to API torrent info endpoint before refactoring (Jose Celano)

Pull request description:

  TODO:

  - [x] Add an e2e test before refactoring.
  - [x] Refactor the API endpoint to use the resource `TorrentResource` like `AuthKeyResource`.
  - [x] Refactor endpoint ` /api/torrents?offset=:u32&limit=:u32` to use `TorrentResource`.
  - [x] Add a new field (`updated_milliseconds_ago`) to the JSON response keeping the old one for backwards compatibility.

ACKs for top commit:
  josecelano:
    ACK e1b84f6
  da2ce7:
    ACK e1b84f6

Tree-SHA512: be96ae16aa4214e600d6679f35a47ec3b95132ee8243352a11f7aca579a2a000843591556b8279abd073a9cb1079d32b961ee3c71892d4d925fcd202be2826a8
  • Loading branch information
josecelano committed Nov 29, 2022
2 parents 8ac31a9 + e1b84f6 commit 4d788d2
Show file tree
Hide file tree
Showing 8 changed files with 366 additions and 82 deletions.
6 changes: 4 additions & 2 deletions src/api/resources/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
//! WIP. Not all endpoints have their resource structs.
//!
//! - [x] AuthKeys
//! - [ ] ...
//! - [ ] ...
//! - [ ] TorrentResource, TorrentListItemResource, TorrentPeerResource, PeerIdResource
//! - [ ] StatsResource
//! - [ ] ...
pub mod auth_key_resource;
pub mod stats_resource;
pub mod torrent_resource;
21 changes: 21 additions & 0 deletions src/api/resources/stats_resource.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct StatsResource {
pub torrents: u32,
pub seeders: u32,
pub completed: u32,
pub leechers: u32,
pub tcp4_connections_handled: u32,
pub tcp4_announces_handled: u32,
pub tcp4_scrapes_handled: u32,
pub tcp6_connections_handled: u32,
pub tcp6_announces_handled: u32,
pub tcp6_scrapes_handled: u32,
pub udp4_connections_handled: u32,
pub udp4_announces_handled: u32,
pub udp4_scrapes_handled: u32,
pub udp6_connections_handled: u32,
pub udp6_announces_handled: u32,
pub udp6_scrapes_handled: u32,
}
67 changes: 67 additions & 0 deletions src/api/resources/torrent_resource.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use serde::{Deserialize, Serialize};

use crate::peer::TorrentPeer;
use crate::PeerId;

#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct TorrentResource {
pub info_hash: String,
pub seeders: u32,
pub completed: u32,
pub leechers: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub peers: Option<Vec<TorrentPeerResource>>,
}

#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct TorrentListItemResource {
pub info_hash: String,
pub seeders: u32,
pub completed: u32,
pub leechers: u32,
// todo: this is always None. Remove field from endpoint?
pub peers: Option<Vec<TorrentPeerResource>>,
}

#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct TorrentPeerResource {
pub peer_id: PeerIdResource,
pub peer_addr: String,
#[deprecated(since = "2.0.0", note = "please use `updated_milliseconds_ago` instead")]
pub updated: u128,
pub updated_milliseconds_ago: u128,
pub uploaded: i64,
pub downloaded: i64,
pub left: i64,
pub event: String,
}

#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct PeerIdResource {
pub id: Option<String>,
pub client: Option<String>,
}

impl From<PeerId> for PeerIdResource {
fn from(peer_id: PeerId) -> Self {
PeerIdResource {
id: peer_id.get_id(),
client: peer_id.get_client_name().map(|client_name| client_name.to_string()),
}
}
}

impl From<TorrentPeer> for TorrentPeerResource {
fn from(peer: TorrentPeer) -> Self {
TorrentPeerResource {
peer_id: PeerIdResource::from(peer.peer_id),
peer_addr: peer.peer_addr.to_string(),
updated: peer.updated.as_millis(),
updated_milliseconds_ago: peer.updated.as_millis(),
uploaded: peer.uploaded.0,
downloaded: peer.downloaded.0,
left: peer.left.0,
event: format!("{:?}", peer.event),
}
}
}
47 changes: 10 additions & 37 deletions src/api/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ use serde::{Deserialize, Serialize};
use warp::{filters, reply, serve, Filter};

use super::resources::auth_key_resource::AuthKeyResource;
use crate::peer::TorrentPeer;
use super::resources::stats_resource::StatsResource;
use super::resources::torrent_resource::{TorrentListItemResource, TorrentPeerResource, TorrentResource};
use crate::protocol::common::*;
use crate::tracker::TorrentTracker;

Expand All @@ -18,36 +19,6 @@ struct TorrentInfoQuery {
limit: Option<u32>,
}

#[derive(Serialize)]
struct Torrent<'a> {
info_hash: &'a InfoHash,
seeders: u32,
completed: u32,
leechers: u32,
#[serde(skip_serializing_if = "Option::is_none")]
peers: Option<Vec<&'a TorrentPeer>>,
}

#[derive(Serialize)]
struct Stats {
torrents: u32,
seeders: u32,
completed: u32,
leechers: u32,
tcp4_connections_handled: u32,
tcp4_announces_handled: u32,
tcp4_scrapes_handled: u32,
tcp6_connections_handled: u32,
tcp6_announces_handled: u32,
tcp6_scrapes_handled: u32,
udp4_connections_handled: u32,
udp4_announces_handled: u32,
udp4_scrapes_handled: u32,
udp6_connections_handled: u32,
udp6_announces_handled: u32,
udp6_scrapes_handled: u32,
}

#[derive(Serialize, Debug)]
#[serde(tag = "status", rename_all = "snake_case")]
enum ActionStatus<'a> {
Expand Down Expand Up @@ -109,8 +80,8 @@ pub fn start(socket_addr: SocketAddr, tracker: Arc<TorrentTracker>) -> impl warp
.iter()
.map(|(info_hash, torrent_entry)| {
let (seeders, completed, leechers) = torrent_entry.get_stats();
Torrent {
info_hash,
TorrentListItemResource {
info_hash: info_hash.to_string(),
seeders,
completed,
leechers,
Expand All @@ -132,7 +103,7 @@ pub fn start(socket_addr: SocketAddr, tracker: Arc<TorrentTracker>) -> impl warp
.and(filters::path::end())
.map(move || api_stats.clone())
.and_then(|tracker: Arc<TorrentTracker>| async move {
let mut results = Stats {
let mut results = StatsResource {
torrents: 0,
seeders: 0,
completed: 0,
Expand Down Expand Up @@ -206,12 +177,14 @@ pub fn start(socket_addr: SocketAddr, tracker: Arc<TorrentTracker>) -> impl warp

let peers = torrent_entry.get_peers(None);

Ok(reply::json(&Torrent {
info_hash: &info_hash,
let peer_resources = peers.iter().map(|peer| TorrentPeerResource::from(**peer)).collect();

Ok(reply::json(&TorrentResource {
info_hash: info_hash.to_string(),
seeders,
completed,
leechers,
peers: Some(peers),
peers: Some(peer_resources),
}))
});

Expand Down
19 changes: 11 additions & 8 deletions src/protocol/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ impl<'v> serde::de::Visitor<'v> for InfoHashVisitor {
}
}

#[derive(PartialEq, Eq, Hash, Clone, Debug, PartialOrd, Ord)]
#[derive(PartialEq, Eq, Hash, Clone, Debug, PartialOrd, Ord, Copy)]
pub struct PeerId(pub [u8; 20]);

impl std::fmt::Display for PeerId {
Expand All @@ -232,6 +232,14 @@ impl std::fmt::Display for PeerId {
}

impl PeerId {
pub fn get_id(&self) -> Option<String> {
let buff_size = self.0.len() * 2;
let mut tmp: Vec<u8> = vec![0; buff_size];
binascii::bin2hex(&self.0, &mut tmp).unwrap();

std::str::from_utf8(&tmp).ok().map(|id| id.to_string())
}

pub fn get_client_name(&self) -> Option<&'static str> {
if self.0[0] == b'M' {
return Some("BitTorrent");
Expand Down Expand Up @@ -316,19 +324,14 @@ impl Serialize for PeerId {
where
S: serde::Serializer,
{
let buff_size = self.0.len() * 2;
let mut tmp: Vec<u8> = vec![0; buff_size];
binascii::bin2hex(&self.0, &mut tmp).unwrap();
let id = std::str::from_utf8(&tmp).ok();

#[derive(Serialize)]
struct PeerIdInfo<'a> {
id: Option<&'a str>,
id: Option<String>,
client: Option<&'a str>,
}

let obj = PeerIdInfo {
id,
id: self.get_id(),
client: self.get_client_name(),
};
obj.serialize(serializer)
Expand Down
2 changes: 1 addition & 1 deletion src/tracker/peer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::protocol::clock::{DefaultClock, DurationSinceUnixEpoch, Time};
use crate::protocol::common::{AnnounceEventDef, NumberOfBytesDef, PeerId};
use crate::protocol::utils::ser_unix_time_value;

#[derive(PartialEq, Eq, Debug, Clone, Serialize)]
#[derive(PartialEq, Eq, Debug, Clone, Serialize, Copy)]
pub struct TorrentPeer {
pub peer_id: PeerId,
pub peer_addr: SocketAddr,
Expand Down
4 changes: 2 additions & 2 deletions src/tracker/torrent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,15 @@ impl TorrentEntry {
let _ = self.peers.remove(&peer.peer_id);
}
AnnounceEvent::Completed => {
let peer_old = self.peers.insert(peer.peer_id.clone(), peer.clone());
let peer_old = self.peers.insert(peer.peer_id, *peer);
// Don't count if peer was not previously known
if peer_old.is_some() {
self.completed += 1;
did_torrent_stats_change = true;
}
}
_ => {
let _ = self.peers.insert(peer.peer_id.clone(), peer.clone());
let _ = self.peers.insert(peer.peer_id, *peer);
}
}

Expand Down
Loading

0 comments on commit 4d788d2

Please sign in to comment.