mirror of
https://github.com/YGGverse/aquatic.git
synced 2026-03-31 17:55:36 +00:00
aquatic_http: add hand-written ScrapeResponse serialization
This commit is contained in:
parent
17385c92ad
commit
84facea0ca
4 changed files with 94 additions and 26 deletions
4
TODO.md
4
TODO.md
|
|
@ -9,14 +9,12 @@
|
||||||
and maybe run scripts should be adjusted
|
and maybe run scripts should be adjusted
|
||||||
|
|
||||||
## aquatic_http
|
## aquatic_http
|
||||||
* scape response to bytes: does bendy encode info hashes here? I think it
|
|
||||||
should
|
|
||||||
* faster Request creation (splitn functions) using memchr, possibly
|
* faster Request creation (splitn functions) using memchr, possibly
|
||||||
iterate over several bytes (& and =)
|
iterate over several bytes (& and =)
|
||||||
* test torrent transfer with real clients
|
* test torrent transfer with real clients
|
||||||
* test tls
|
* test tls
|
||||||
* current serialized byte strings valid
|
* current serialized byte strings valid
|
||||||
* scrape: does it work with multiple hashes?
|
* scrape: does it work (serialization etc), and with multiple hashes?
|
||||||
* compact=0 should result in error response
|
* compact=0 should result in error response
|
||||||
* tests of request parsing
|
* tests of request parsing
|
||||||
* tests of response serialization (against data known to be good would be nice)
|
* tests of response serialization (against data known to be good would be nice)
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
|
use std::collections::BTreeMap;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::vec::Drain;
|
use std::vec::Drain;
|
||||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hashbrown::HashMap;
|
|
||||||
use parking_lot::MutexGuard;
|
use parking_lot::MutexGuard;
|
||||||
use rand::{Rng, SeedableRng, rngs::SmallRng};
|
use rand::{Rng, SeedableRng, rngs::SmallRng};
|
||||||
|
|
||||||
|
|
@ -258,7 +258,7 @@ pub fn handle_scrape_requests(
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut response = ScrapeResponse {
|
let mut response = ScrapeResponse {
|
||||||
files: HashMap::with_capacity(num_to_take),
|
files: BTreeMap::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let peer_ip = convert_ipv4_mapped_ipv4(
|
let peer_ip = convert_ipv4_mapped_ipv4(
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ pub struct PeerId(
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Serialize)]
|
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct InfoHash(
|
pub struct InfoHash(
|
||||||
#[serde(
|
#[serde(
|
||||||
|
|
@ -54,3 +54,18 @@ impl FromStr for AnnounceEvent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
impl quickcheck::Arbitrary for InfoHash {
|
||||||
|
fn arbitrary<G: quickcheck::Gen>(g: &mut G) -> Self {
|
||||||
|
let mut arr = [b'x'; 20];
|
||||||
|
|
||||||
|
arr[0] = u8::arbitrary(g);
|
||||||
|
arr[1] = u8::arbitrary(g);
|
||||||
|
arr[18] = u8::arbitrary(g);
|
||||||
|
arr[19] = u8::arbitrary(g);
|
||||||
|
|
||||||
|
Self(arr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||||
|
|
||||||
use hashbrown::HashMap;
|
use std::collections::BTreeMap;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::common::*;
|
use super::common::*;
|
||||||
|
|
@ -101,13 +101,42 @@ impl AnnounceResponse {
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct ScrapeResponse {
|
pub struct ScrapeResponse {
|
||||||
pub files: HashMap<InfoHash, ScrapeStatistics>,
|
/// BTreeMap instead of HashMap since keys need to be serialized in order
|
||||||
|
pub files: BTreeMap<InfoHash, ScrapeStatistics>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl ScrapeResponse {
|
impl ScrapeResponse {
|
||||||
fn to_bytes(&self) -> Vec<u8> {
|
fn to_bytes(&self) -> Vec<u8> {
|
||||||
unimplemented!()
|
let mut bytes = Vec::with_capacity(
|
||||||
|
9 +
|
||||||
|
self.files.len() * (
|
||||||
|
3 +
|
||||||
|
20 +
|
||||||
|
12 +
|
||||||
|
5 + // Upper estimate
|
||||||
|
31 +
|
||||||
|
5 + // Upper estimate
|
||||||
|
2
|
||||||
|
) +
|
||||||
|
2
|
||||||
|
);
|
||||||
|
|
||||||
|
bytes.extend_from_slice(b"d5:filesd");
|
||||||
|
|
||||||
|
for (info_hash, statistics) in self.files.iter(){
|
||||||
|
bytes.extend_from_slice(b"20:");
|
||||||
|
bytes.extend_from_slice(&info_hash.0);
|
||||||
|
bytes.extend_from_slice(b"d8:completei");
|
||||||
|
let _ = itoa::write(&mut bytes, statistics.complete);
|
||||||
|
bytes.extend_from_slice(b"e10:downloadedi0e10:incompletei");
|
||||||
|
let _ = itoa::write(&mut bytes, statistics.incomplete);
|
||||||
|
bytes.extend_from_slice(b"ee");
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes.extend_from_slice(b"ee");
|
||||||
|
|
||||||
|
bytes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -153,22 +182,9 @@ pub enum Response {
|
||||||
impl Response {
|
impl Response {
|
||||||
pub fn to_bytes(&self) -> Vec<u8> {
|
pub fn to_bytes(&self) -> Vec<u8> {
|
||||||
match self {
|
match self {
|
||||||
Response::Announce(r) => {
|
Response::Announce(r) => r.to_bytes(),
|
||||||
r.to_bytes()
|
Response::Failure(r) => r.to_bytes(),
|
||||||
},
|
Response::Scrape(r) => r.to_bytes(),
|
||||||
Response::Failure(r) => {
|
|
||||||
r.to_bytes()
|
|
||||||
},
|
|
||||||
Response::Scrape(r) => {
|
|
||||||
match bendy::serde::to_bytes(r){
|
|
||||||
Ok(bytes) => bytes,
|
|
||||||
Err(err) => {
|
|
||||||
::log::error!("Response::to_bytes: {}", err);
|
|
||||||
|
|
||||||
Vec::new()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -212,6 +228,18 @@ impl quickcheck::Arbitrary for ResponsePeerListV6 {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
impl quickcheck::Arbitrary for ScrapeStatistics {
|
||||||
|
fn arbitrary<G: quickcheck::Gen>(g: &mut G) -> Self {
|
||||||
|
Self {
|
||||||
|
complete: usize::arbitrary(g),
|
||||||
|
incomplete: usize::arbitrary(g),
|
||||||
|
downloaded: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
impl quickcheck::Arbitrary for AnnounceResponse {
|
impl quickcheck::Arbitrary for AnnounceResponse {
|
||||||
fn arbitrary<G: quickcheck::Gen>(g: &mut G) -> Self {
|
fn arbitrary<G: quickcheck::Gen>(g: &mut G) -> Self {
|
||||||
|
|
@ -226,6 +254,16 @@ impl quickcheck::Arbitrary for AnnounceResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
impl quickcheck::Arbitrary for ScrapeResponse {
|
||||||
|
fn arbitrary<G: quickcheck::Gen>(g: &mut G) -> Self {
|
||||||
|
Self {
|
||||||
|
files: BTreeMap::arbitrary(g),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
impl quickcheck::Arbitrary for FailureResponse {
|
impl quickcheck::Arbitrary for FailureResponse {
|
||||||
fn arbitrary<G: quickcheck::Gen>(g: &mut G) -> Self {
|
fn arbitrary<G: quickcheck::Gen>(g: &mut G) -> Self {
|
||||||
|
|
@ -251,6 +289,23 @@ mod tests {
|
||||||
response.to_bytes() == reference
|
response.to_bytes() == reference
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[quickcheck]
|
||||||
|
fn test_scrape_response_to_bytes(response: ScrapeResponse) -> bool {
|
||||||
|
let reference = bendy::serde::to_bytes(
|
||||||
|
&Response::Scrape(response.clone())
|
||||||
|
).unwrap();
|
||||||
|
let hand_written = response.to_bytes();
|
||||||
|
|
||||||
|
let success = hand_written == reference;
|
||||||
|
|
||||||
|
if !success {
|
||||||
|
println!("reference: {}", String::from_utf8_lossy(&reference));
|
||||||
|
println!("hand_written: {}", String::from_utf8_lossy(&hand_written));
|
||||||
|
}
|
||||||
|
|
||||||
|
success
|
||||||
|
}
|
||||||
|
|
||||||
#[quickcheck]
|
#[quickcheck]
|
||||||
fn test_failure_response_to_bytes(response: FailureResponse) -> bool {
|
fn test_failure_response_to_bytes(response: FailureResponse) -> bool {
|
||||||
let reference = bendy::serde::to_bytes(
|
let reference = bendy::serde::to_bytes(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue