Move everything to workspaces
This commit is contained in:
parent
75547d3000
commit
ad867e8e3c
42 changed files with 338 additions and 168 deletions
|
|
@ -1,197 +0,0 @@
|
|||
use std::{collections::HashMap, marker::PhantomData};
|
||||
|
||||
use serde::{Deserialize, Deserializer};
|
||||
|
||||
use crate::{
|
||||
buffers::{ByteBuf, ByteString},
|
||||
clone_to_owned::CloneToOwned,
|
||||
serde_bencode_de::from_bytes,
|
||||
};
|
||||
|
||||
pub fn dyn_from_bytes<'de, ByteBuf>(buf: &'de [u8]) -> anyhow::Result<BencodeValue<ByteBuf>>
|
||||
where
|
||||
ByteBuf: From<&'de [u8]> + Deserialize<'de> + std::hash::Hash + Eq,
|
||||
{
|
||||
from_bytes(buf)
|
||||
}
|
||||
|
||||
impl<ByteBuf: serde::Serialize + Eq + std::hash::Hash> serde::Serialize for BencodeValue<ByteBuf> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
match self {
|
||||
BencodeValue::Bytes(b) => b.serialize(serializer),
|
||||
BencodeValue::Integer(v) => v.serialize(serializer),
|
||||
BencodeValue::List(l) => l.serialize(serializer),
|
||||
BencodeValue::Dict(d) => d.serialize(serializer),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, ByteBuf> serde::de::Deserialize<'de> for BencodeValue<ByteBuf>
|
||||
where
|
||||
ByteBuf: From<&'de [u8]> + Deserialize<'de> + std::hash::Hash + Eq,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct Visitor<ByteBuf> {
|
||||
buftype: PhantomData<ByteBuf>,
|
||||
}
|
||||
|
||||
impl<'de, ByteBuf> serde::de::Visitor<'de> for Visitor<ByteBuf>
|
||||
where
|
||||
ByteBuf: From<&'de [u8]> + Deserialize<'de> + std::hash::Hash + Eq,
|
||||
{
|
||||
type Value = BencodeValue<ByteBuf>;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(formatter, "a bencode value")
|
||||
}
|
||||
|
||||
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
Ok(BencodeValue::Integer(v))
|
||||
}
|
||||
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: serde::de::SeqAccess<'de>,
|
||||
{
|
||||
let mut v = Vec::new();
|
||||
while let Some(value) = seq.next_element()? {
|
||||
v.push(value);
|
||||
}
|
||||
Ok(BencodeValue::List(v))
|
||||
}
|
||||
|
||||
fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
Ok(BencodeValue::Bytes(ByteBuf::from(v)))
|
||||
}
|
||||
|
||||
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: serde::de::MapAccess<'de>,
|
||||
{
|
||||
let mut hmap = HashMap::new();
|
||||
while let Some(key) = map.next_key()? {
|
||||
let value = map.next_value()?;
|
||||
hmap.insert(key, value);
|
||||
}
|
||||
Ok(BencodeValue::Dict(hmap))
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_any(Visitor {
|
||||
buftype: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// A dynamic value when we don't know exactly what we are deserializing.
|
||||
// Useful for debugging.
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub enum BencodeValue<ByteBuf: std::hash::Hash + Eq> {
|
||||
Bytes(ByteBuf),
|
||||
Integer(i64),
|
||||
List(Vec<BencodeValue<ByteBuf>>),
|
||||
Dict(HashMap<ByteBuf, BencodeValue<ByteBuf>>),
|
||||
}
|
||||
|
||||
impl<ByteBuf: std::fmt::Debug + std::hash::Hash + Eq> std::fmt::Debug for BencodeValue<ByteBuf> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
BencodeValue::Bytes(b) => std::fmt::Debug::fmt(b, f),
|
||||
BencodeValue::Integer(i) => std::fmt::Debug::fmt(i, f),
|
||||
BencodeValue::List(l) => std::fmt::Debug::fmt(l, f),
|
||||
BencodeValue::Dict(d) => std::fmt::Debug::fmt(d, f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<ByteBuf> CloneToOwned for BencodeValue<ByteBuf>
|
||||
where
|
||||
ByteBuf: CloneToOwned + std::hash::Hash + Eq,
|
||||
<ByteBuf as CloneToOwned>::Target: Eq + std::hash::Hash,
|
||||
{
|
||||
type Target = BencodeValue<<ByteBuf as CloneToOwned>::Target>;
|
||||
|
||||
fn clone_to_owned(&self) -> Self::Target {
|
||||
match self {
|
||||
BencodeValue::Bytes(b) => BencodeValue::Bytes(b.clone_to_owned()),
|
||||
BencodeValue::Integer(i) => BencodeValue::Integer(*i),
|
||||
BencodeValue::List(l) => BencodeValue::List(l.clone_to_owned()),
|
||||
BencodeValue::Dict(d) => BencodeValue::Dict(d.clone_to_owned()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type BencodeValueBorrowed<'a> = BencodeValue<ByteBuf<'a>>;
|
||||
pub type BencodeValueOwned = BencodeValue<ByteString>;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::serde_bencode_ser::bencode_serialize_to_writer;
|
||||
|
||||
use super::*;
|
||||
use serde::Serialize;
|
||||
use std::io::Read;
|
||||
|
||||
#[test]
|
||||
fn test_deserialize_torrent_dyn() {
|
||||
let mut buf = Vec::new();
|
||||
let filename = "resources/ubuntu-21.04-desktop-amd64.iso.torrent";
|
||||
std::fs::File::open(filename)
|
||||
.unwrap()
|
||||
.read_to_end(&mut buf)
|
||||
.unwrap();
|
||||
|
||||
let torrent_borrowed: BencodeValueBorrowed = from_bytes(&buf).unwrap();
|
||||
let torrent_owned: BencodeValueOwned = from_bytes(&buf).unwrap();
|
||||
dbg!(torrent_borrowed);
|
||||
dbg!(torrent_owned);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serialize_torrent_dyn() {
|
||||
let mut buf = Vec::new();
|
||||
let filename = "resources/ubuntu-21.04-desktop-amd64.iso.torrent";
|
||||
std::fs::File::open(filename)
|
||||
.unwrap()
|
||||
.read_to_end(&mut buf)
|
||||
.unwrap();
|
||||
|
||||
let torrent: BencodeValueBorrowed = from_bytes(&buf).unwrap();
|
||||
|
||||
let mut buf = Vec::<u8>::new();
|
||||
bencode_serialize_to_writer(&torrent, &mut buf).unwrap();
|
||||
|
||||
let new_torrent = from_bytes(&buf).unwrap();
|
||||
assert_eq!(torrent, new_torrent);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serialize_struct_with_option() {
|
||||
#[derive(Serialize)]
|
||||
struct Test {
|
||||
f1: i64,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
missing: Option<i64>,
|
||||
}
|
||||
let test = Test {
|
||||
f1: 100,
|
||||
missing: None,
|
||||
};
|
||||
let mut buf = Vec::<u8>::new();
|
||||
bencode_serialize_to_writer(&test, &mut buf).unwrap();
|
||||
assert_eq!(&buf, b"d2:f1i100ee");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,166 +0,0 @@
|
|||
use serde::{Deserialize, Deserializer};
|
||||
|
||||
use crate::clone_to_owned::CloneToOwned;
|
||||
|
||||
#[derive(Default, PartialEq, Eq, Hash, Clone, PartialOrd, Ord)]
|
||||
pub struct ByteString(pub Vec<u8>);
|
||||
|
||||
#[derive(Default, Deserialize, PartialEq, Eq, Hash, Clone, PartialOrd, Ord)]
|
||||
#[serde(transparent)]
|
||||
pub struct ByteBuf<'a>(pub &'a [u8]);
|
||||
|
||||
pub trait ByteBufT {
|
||||
fn as_slice(&self) -> &[u8];
|
||||
}
|
||||
|
||||
impl ByteBufT for ByteString {
|
||||
fn as_slice(&self) -> &[u8] {
|
||||
self.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ByteBufT for ByteBuf<'a> {
|
||||
fn as_slice(&self) -> &[u8] {
|
||||
self.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
fn debug_bytes(b: &[u8], f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if b.iter().all(|b| *b == 0) {
|
||||
return write!(f, "<{} bytes, all zeroes>", b.len());
|
||||
}
|
||||
match std::str::from_utf8(b) {
|
||||
Ok(s) => write!(f, "{:?}", s),
|
||||
Err(_e) => write!(f, "<{} bytes>", b.len()),
|
||||
}
|
||||
}
|
||||
|
||||
fn display_bytes(b: &[u8], f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if b.iter().all(|b| *b == 0) {
|
||||
return write!(f, "<{} bytes, all zeroes>", b.len());
|
||||
}
|
||||
match std::str::from_utf8(b) {
|
||||
Ok(s) => write!(f, "{}", s),
|
||||
Err(_e) => write!(f, "<{} bytes>", b.len()),
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::fmt::Debug for ByteBuf<'a> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
debug_bytes(self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::fmt::Display for ByteBuf<'a> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
display_bytes(self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for ByteString {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
debug_bytes(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ByteString {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
display_bytes(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: ByteBufT> CloneToOwned for B {
|
||||
type Target = ByteString;
|
||||
|
||||
fn clone_to_owned(&self) -> Self::Target {
|
||||
ByteString(self.as_slice().to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::convert::AsRef<[u8]> for ByteBuf<'a> {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::AsRef<[u8]> for ByteString {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::ops::Deref for ByteBuf<'a> {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for ByteString {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a [u8]> for ByteBuf<'a> {
|
||||
fn from(b: &'a [u8]) -> Self {
|
||||
Self(b)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a [u8]> for ByteString {
|
||||
fn from(b: &'a [u8]) -> Self {
|
||||
Self(b.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<u8>> for ByteString {
|
||||
fn from(b: Vec<u8>) -> Self {
|
||||
Self(b)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> serde::ser::Serialize for ByteBuf<'a> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
serializer.serialize_bytes(self.as_slice())
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::ser::Serialize for ByteString {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
serializer.serialize_bytes(self.as_slice())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::de::Deserialize<'de> for ByteString {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct Visitor;
|
||||
|
||||
impl<'de> serde::de::Visitor<'de> for Visitor {
|
||||
type Value = Vec<u8>;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("byte string")
|
||||
}
|
||||
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
Ok(v.to_owned())
|
||||
}
|
||||
}
|
||||
Ok(ByteString(deserializer.deserialize_byte_buf(Visitor {})?))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,8 @@
|
|||
use librqbit_core::lengths::{ChunkInfo, Lengths, ValidPieceIndex};
|
||||
use log::{debug, info};
|
||||
use peer_binary_protocol::Piece;
|
||||
|
||||
use crate::{
|
||||
lengths::{ChunkInfo, Lengths, ValidPieceIndex},
|
||||
peer_binary_protocol::Piece,
|
||||
type_aliases::BF,
|
||||
};
|
||||
use crate::type_aliases::BF;
|
||||
|
||||
pub struct ChunkTracker {
|
||||
// This forms the basis of a "queue" to pull from.
|
||||
|
|
@ -131,7 +129,11 @@ impl ChunkTracker {
|
|||
where
|
||||
ByteBuf: AsRef<[u8]>,
|
||||
{
|
||||
let chunk_info = self.lengths.chunk_info_from_received_piece(piece)?;
|
||||
let chunk_info = self.lengths.chunk_info_from_received_piece(
|
||||
piece.index,
|
||||
piece.begin,
|
||||
piece.block.as_ref().len() as u32,
|
||||
)?;
|
||||
let chunk_range = self.lengths.chunk_range(chunk_info.piece_index);
|
||||
let chunk_range = self.chunk_status.get_mut(chunk_range).unwrap();
|
||||
if chunk_range.all() {
|
||||
|
|
|
|||
|
|
@ -1,62 +0,0 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
pub trait CloneToOwned {
|
||||
type Target;
|
||||
|
||||
fn clone_to_owned(&self) -> Self::Target;
|
||||
}
|
||||
|
||||
impl<T> CloneToOwned for Option<T>
|
||||
where
|
||||
T: CloneToOwned,
|
||||
{
|
||||
type Target = Option<<T as CloneToOwned>::Target>;
|
||||
|
||||
fn clone_to_owned(&self) -> Self::Target {
|
||||
self.as_ref().map(|i| i.clone_to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> CloneToOwned for Vec<T>
|
||||
where
|
||||
T: CloneToOwned,
|
||||
{
|
||||
type Target = Vec<<T as CloneToOwned>::Target>;
|
||||
|
||||
fn clone_to_owned(&self) -> Self::Target {
|
||||
self.iter().map(|i| i.clone_to_owned()).collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl CloneToOwned for u8 {
|
||||
type Target = u8;
|
||||
|
||||
fn clone_to_owned(&self) -> Self::Target {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl CloneToOwned for u32 {
|
||||
type Target = u32;
|
||||
|
||||
fn clone_to_owned(&self) -> Self::Target {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> CloneToOwned for HashMap<K, V>
|
||||
where
|
||||
K: CloneToOwned,
|
||||
<K as CloneToOwned>::Target: std::hash::Hash + Eq,
|
||||
V: CloneToOwned,
|
||||
{
|
||||
type Target = HashMap<<K as CloneToOwned>::Target, <V as CloneToOwned>::Target>;
|
||||
|
||||
fn clone_to_owned(&self) -> Self::Target {
|
||||
let mut result = HashMap::with_capacity(self.capacity());
|
||||
for (k, v) in self {
|
||||
result.insert(k.clone_to_owned(), v.clone_to_owned());
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
pub const CHUNK_SIZE: u32 = 16384;
|
||||
|
|
@ -1,10 +1,12 @@
|
|||
use std::net::SocketAddr;
|
||||
|
||||
use buffers::ByteString;
|
||||
use futures::{stream::FuturesUnordered, StreamExt};
|
||||
use librqbit_core::torrent_metainfo::TorrentMetaV1Info;
|
||||
use log::debug;
|
||||
use tokio::sync::mpsc::UnboundedReceiver;
|
||||
|
||||
use crate::{buffers::ByteString, peer_info_reader, torrent_metainfo::TorrentMetaV1Info};
|
||||
use crate::peer_info_reader;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ReadMetainfoResult {
|
||||
|
|
@ -61,9 +63,11 @@ pub async fn read_metainfo_from_peer_receiver(
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use librqbit_core::{info_hash::decode_info_hash, peer_id::generate_peer_id};
|
||||
|
||||
use crate::dht::jsdht::JsDht;
|
||||
|
||||
use super::*;
|
||||
use crate::info_hash::decode_info_hash;
|
||||
use crate::{dht::jsdht::JsDht, peer_id::generate_peer_id};
|
||||
use std::sync::Once;
|
||||
|
||||
static LOG_INIT: Once = Once::new();
|
||||
|
|
|
|||
|
|
@ -6,17 +6,17 @@ use std::{
|
|||
};
|
||||
|
||||
use anyhow::Context;
|
||||
use buffers::ByteString;
|
||||
use librqbit_core::{
|
||||
lengths::{ChunkInfo, Lengths, ValidPieceIndex},
|
||||
torrent_metainfo::{FileIteratorName, TorrentMetaV1Info},
|
||||
};
|
||||
use log::{debug, trace, warn};
|
||||
use parking_lot::Mutex;
|
||||
use peer_binary_protocol::Piece;
|
||||
use sha1w::ISha1;
|
||||
|
||||
use crate::{
|
||||
buffers::ByteString,
|
||||
lengths::{ChunkInfo, Lengths, ValidPieceIndex},
|
||||
peer_binary_protocol::Piece,
|
||||
sha1w::ISha1,
|
||||
torrent_metainfo::{FileIteratorName, TorrentMetaV1Info},
|
||||
type_aliases::{PeerHandle, BF},
|
||||
};
|
||||
use crate::type_aliases::{PeerHandle, BF};
|
||||
|
||||
pub struct InitialCheckResults {
|
||||
pub needed_pieces: BF,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use librqbit_core::speed_estimator::SpeedEstimator;
|
||||
use std::io::Write;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::time::Instant;
|
||||
use warp::Filter;
|
||||
|
||||
use crate::speed_estimator::SpeedEstimator;
|
||||
use crate::torrent_state::TorrentState;
|
||||
|
||||
// This is just a stub for debugging, nothing useful here.
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
pub type InfoHash = [u8; 20];
|
||||
|
||||
pub fn decode_info_hash(hash_str: &str) -> anyhow::Result<InfoHash> {
|
||||
let mut hash_arr = [0u8; 20];
|
||||
hex::decode_to_slice(hash_str, &mut hash_arr)?;
|
||||
Ok(hash_arr)
|
||||
}
|
||||
|
|
@ -1,309 +0,0 @@
|
|||
use crate::{constants::CHUNK_SIZE, peer_binary_protocol::Piece};
|
||||
|
||||
const fn is_power_of_two(x: u64) -> bool {
|
||||
(x != 0) && ((x & (x - 1)) == 0)
|
||||
}
|
||||
|
||||
pub const fn ceil_div_u64(a: u64, b: u64) -> u64 {
|
||||
(a + b - 1) / b
|
||||
}
|
||||
|
||||
pub const fn last_element_size_u64(total: u64, chunk_size: u64) -> u64 {
|
||||
let rem = total % chunk_size;
|
||||
if rem == 0 {
|
||||
return chunk_size;
|
||||
}
|
||||
rem
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct PieceInfo {
|
||||
pub piece_index: ValidPieceIndex,
|
||||
pub len: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct ChunkInfo {
|
||||
pub piece_index: ValidPieceIndex,
|
||||
pub chunk_index: u32,
|
||||
pub absolute_index: u32,
|
||||
pub size: u32,
|
||||
pub offset: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Lengths {
|
||||
chunk_length: u32,
|
||||
total_length: u64,
|
||||
piece_length: u32,
|
||||
last_piece_id: u32,
|
||||
last_piece_length: u32,
|
||||
chunks_per_piece: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct ValidPieceIndex(u32);
|
||||
impl std::fmt::Display for ValidPieceIndex {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
impl std::fmt::Debug for ValidPieceIndex {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ValidPieceIndex {
|
||||
pub fn get(&self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Lengths {
|
||||
pub fn new(
|
||||
total_length: u64,
|
||||
piece_length: u32,
|
||||
chunk_length: Option<u32>,
|
||||
) -> anyhow::Result<Self> {
|
||||
let chunk_length = chunk_length.unwrap_or(CHUNK_SIZE);
|
||||
if !(is_power_of_two(piece_length as u64)) {
|
||||
anyhow::bail!("piece length {} is not a power of 2", piece_length);
|
||||
}
|
||||
if !(is_power_of_two(chunk_length as u64)) {
|
||||
anyhow::bail!("chunk length {} is not a power of 2", chunk_length);
|
||||
}
|
||||
if chunk_length >= piece_length {
|
||||
anyhow::bail!(
|
||||
"chunk length {} should be smaller than pice length {}",
|
||||
chunk_length,
|
||||
piece_length
|
||||
);
|
||||
}
|
||||
Ok(Self {
|
||||
chunk_length,
|
||||
piece_length,
|
||||
total_length,
|
||||
chunks_per_piece: piece_length / chunk_length,
|
||||
last_piece_id: ((total_length + 1) / piece_length as u64) as u32,
|
||||
last_piece_length: last_element_size_u64(total_length, piece_length as u64) as u32,
|
||||
})
|
||||
}
|
||||
pub const fn piece_bitfield_bytes(&self) -> usize {
|
||||
ceil_div_u64(self.total_pieces() as u64, 8) as usize
|
||||
}
|
||||
pub const fn chunk_bitfield_bytes(&self) -> usize {
|
||||
ceil_div_u64(self.total_chunks() as u64, 8) as usize
|
||||
}
|
||||
pub const fn total_length(&self) -> u64 {
|
||||
self.total_length
|
||||
}
|
||||
pub const fn validate_piece_index(&self, index: u32) -> Option<ValidPieceIndex> {
|
||||
if index > self.last_piece_id {
|
||||
return None;
|
||||
}
|
||||
Some(ValidPieceIndex(index))
|
||||
}
|
||||
pub const fn default_piece_length(&self) -> u32 {
|
||||
self.piece_length
|
||||
}
|
||||
pub const fn default_chunk_length(&self) -> u32 {
|
||||
self.chunk_length
|
||||
}
|
||||
pub const fn default_chunks_per_piece(&self) -> u32 {
|
||||
self.chunks_per_piece
|
||||
}
|
||||
pub const fn total_chunks(&self) -> u32 {
|
||||
ceil_div_u64(self.total_length, self.chunk_length as u64) as u32
|
||||
}
|
||||
pub const fn total_pieces(&self) -> u32 {
|
||||
self.last_piece_id + 1
|
||||
}
|
||||
pub const fn piece_length(&self, index: ValidPieceIndex) -> u32 {
|
||||
if index.0 == self.last_piece_id {
|
||||
return self.last_piece_length;
|
||||
}
|
||||
self.piece_length
|
||||
}
|
||||
pub const fn chunk_absolute_offset(&self, chunk_info: &ChunkInfo) -> u64 {
|
||||
self.piece_offset(chunk_info.piece_index) + chunk_info.offset as u64
|
||||
}
|
||||
pub const fn piece_offset(&self, index: ValidPieceIndex) -> u64 {
|
||||
index.0 as u64 * self.piece_length as u64
|
||||
}
|
||||
|
||||
pub fn iter_piece_infos(&self) -> impl Iterator<Item = PieceInfo> {
|
||||
let last_id = self.last_piece_id;
|
||||
let last_len = self.last_piece_length;
|
||||
let pl = self.piece_length;
|
||||
(0..self.total_pieces()).map(move |idx| PieceInfo {
|
||||
piece_index: ValidPieceIndex(idx),
|
||||
len: if idx == last_id { last_len } else { pl },
|
||||
})
|
||||
}
|
||||
|
||||
pub fn iter_chunk_infos(&self, index: ValidPieceIndex) -> impl Iterator<Item = ChunkInfo> {
|
||||
let mut remaining = self.piece_length(index);
|
||||
let chunk_size = self.chunk_length;
|
||||
let absolute_offset = index.0 * self.chunks_per_piece;
|
||||
(0u32..).scan(0, move |offset, idx| {
|
||||
if remaining == 0 {
|
||||
return None;
|
||||
}
|
||||
let s = std::cmp::min(remaining, chunk_size);
|
||||
let result = ChunkInfo {
|
||||
piece_index: index,
|
||||
chunk_index: idx,
|
||||
absolute_index: absolute_offset + idx,
|
||||
size: s,
|
||||
offset: *offset,
|
||||
};
|
||||
*offset += s;
|
||||
remaining -= s;
|
||||
Some(result)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn chunk_info_from_received_data(
|
||||
&self,
|
||||
piece_index: ValidPieceIndex,
|
||||
begin: u32,
|
||||
chunk_size: u32,
|
||||
) -> Option<ChunkInfo> {
|
||||
let index = begin / self.chunk_length;
|
||||
let expected_chunk_size = self.chunk_size(piece_index, index)?;
|
||||
let offset = self.chunk_offset_in_piece(piece_index, index)?;
|
||||
if offset != begin {
|
||||
return None;
|
||||
}
|
||||
if expected_chunk_size != chunk_size {
|
||||
return None;
|
||||
}
|
||||
let absolute_index = self.chunks_per_piece * piece_index.get() + index;
|
||||
Some(ChunkInfo {
|
||||
piece_index,
|
||||
chunk_index: index,
|
||||
size: chunk_size,
|
||||
offset,
|
||||
absolute_index,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn chunk_info_from_received_piece<ByteBuf>(
|
||||
&self,
|
||||
piece: &Piece<ByteBuf>,
|
||||
) -> Option<ChunkInfo>
|
||||
where
|
||||
ByteBuf: AsRef<[u8]>,
|
||||
{
|
||||
self.chunk_info_from_received_data(
|
||||
self.validate_piece_index(piece.index)?,
|
||||
piece.begin,
|
||||
piece.block.as_ref().len() as u32,
|
||||
)
|
||||
}
|
||||
pub const fn chunk_range(&self, index: ValidPieceIndex) -> std::ops::Range<usize> {
|
||||
let start = index.0 * self.chunks_per_piece;
|
||||
let end = start + self.chunks_per_piece(index);
|
||||
start as usize..end as usize
|
||||
}
|
||||
pub const fn chunks_per_piece(&self, index: ValidPieceIndex) -> u32 {
|
||||
if index.0 == self.last_piece_id {
|
||||
return (self.last_piece_length + self.chunk_length - 1) / self.chunk_length;
|
||||
}
|
||||
self.chunks_per_piece
|
||||
}
|
||||
pub const fn chunk_offset_in_piece(
|
||||
&self,
|
||||
piece_index: ValidPieceIndex,
|
||||
chunk_index: u32,
|
||||
) -> Option<u32> {
|
||||
if chunk_index >= self.chunks_per_piece(piece_index) {
|
||||
return None;
|
||||
}
|
||||
Some(chunk_index * self.chunk_length)
|
||||
}
|
||||
pub fn chunk_size(&self, piece_index: ValidPieceIndex, chunk_index: u32) -> Option<u32> {
|
||||
let chunks_per_piece = self.chunks_per_piece(piece_index);
|
||||
let pl = self.piece_length(piece_index);
|
||||
if chunk_index >= chunks_per_piece {
|
||||
return None;
|
||||
}
|
||||
let offset = chunk_index * self.chunk_length;
|
||||
Some(std::cmp::min(self.chunk_length, pl - offset))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn make_lengths() -> Lengths {
|
||||
Lengths::new(1174243328, 262144, None).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_total_pieces() {
|
||||
let l = make_lengths();
|
||||
assert_eq!(l.total_pieces(), 4480);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_piece_length() {
|
||||
let l = make_lengths();
|
||||
let p = l.validate_piece_index(4479).unwrap();
|
||||
|
||||
assert_eq!(l.piece_length(l.validate_piece_index(0).unwrap()), 262144);
|
||||
assert_eq!(l.piece_length(p), 100352);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_chunks_in_piece() {
|
||||
let l = make_lengths();
|
||||
let p = l.validate_piece_index(4479).unwrap();
|
||||
|
||||
assert_eq!(l.chunks_per_piece(l.validate_piece_index(0).unwrap()), 16);
|
||||
assert_eq!(l.chunks_per_piece(p), 7);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_chunk_size() {
|
||||
let l = make_lengths();
|
||||
let p = l.validate_piece_index(4479).unwrap();
|
||||
|
||||
assert_eq!(l.chunk_size(p, 0), Some(16384));
|
||||
assert_eq!(l.chunk_size(p, 6), Some(2048));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_chunk_infos() {
|
||||
let l = make_lengths();
|
||||
let p = l.validate_piece_index(4479).unwrap();
|
||||
|
||||
let mut it = l.iter_chunk_infos(p);
|
||||
let first = it.next().unwrap();
|
||||
let last = it.last().unwrap();
|
||||
|
||||
assert_eq!(
|
||||
first,
|
||||
ChunkInfo {
|
||||
piece_index: p,
|
||||
chunk_index: 0,
|
||||
absolute_index: 71664,
|
||||
size: 16384,
|
||||
offset: 0,
|
||||
}
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
last,
|
||||
ChunkInfo {
|
||||
piece_index: p,
|
||||
chunk_index: 6,
|
||||
absolute_index: 71670,
|
||||
size: 2048,
|
||||
offset: 98304,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,27 +1,20 @@
|
|||
pub mod bencode_value;
|
||||
pub mod buffers;
|
||||
pub mod chunk_tracker;
|
||||
pub mod clone_to_owned;
|
||||
pub mod constants;
|
||||
pub mod dht;
|
||||
pub mod file_ops;
|
||||
pub mod http_api;
|
||||
pub mod info_hash;
|
||||
pub mod lengths;
|
||||
pub mod magnet;
|
||||
pub mod peer_binary_protocol;
|
||||
pub mod peer_connection;
|
||||
pub mod peer_handler;
|
||||
pub mod peer_id;
|
||||
pub mod peer_info_reader;
|
||||
pub mod peer_state;
|
||||
pub mod serde_bencode_de;
|
||||
pub mod serde_bencode_ser;
|
||||
pub mod sha1w;
|
||||
pub mod spawn_utils;
|
||||
pub mod speed_estimator;
|
||||
pub mod torrent_manager;
|
||||
pub mod torrent_metainfo;
|
||||
pub mod torrent_state;
|
||||
pub mod tracker_comms;
|
||||
pub mod type_aliases;
|
||||
|
||||
pub use buffers::*;
|
||||
pub use clone_to_owned::CloneToOwned;
|
||||
pub use librqbit_core::info_hash::*;
|
||||
pub use librqbit_core::magnet::*;
|
||||
pub use librqbit_core::peer_id::*;
|
||||
pub use librqbit_core::torrent_metainfo::*;
|
||||
|
|
|
|||
|
|
@ -1,48 +0,0 @@
|
|||
use crate::info_hash::{decode_info_hash, InfoHash};
|
||||
use anyhow::Context;
|
||||
|
||||
pub struct Magnet {
|
||||
pub info_hash: InfoHash,
|
||||
pub trackers: Vec<String>,
|
||||
}
|
||||
|
||||
impl Magnet {
|
||||
pub fn parse(url: &str) -> anyhow::Result<Magnet> {
|
||||
let url = url::Url::parse(url).context("magnet link must be a valid URL")?;
|
||||
if url.scheme() != "magnet" {
|
||||
anyhow::bail!("expected scheme magnet");
|
||||
}
|
||||
let mut info_hash: Option<InfoHash> = None;
|
||||
let mut trackers = Vec::<String>::new();
|
||||
for (key, value) in url.query_pairs() {
|
||||
match key.as_ref() {
|
||||
"xt" => match value.as_ref().strip_prefix("urn:btih:") {
|
||||
Some(infohash) => {
|
||||
info_hash.replace(decode_info_hash(infohash)?);
|
||||
}
|
||||
None => anyhow::bail!("expected xt to start with urn:btih:"),
|
||||
},
|
||||
"tr" => trackers.push(value.into()),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
match info_hash {
|
||||
Some(info_hash) => Ok(Magnet {
|
||||
info_hash,
|
||||
trackers,
|
||||
}),
|
||||
None => {
|
||||
anyhow::bail!("did not find infohash")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn test_parse_magnet_as_url() {
|
||||
let magnet = "magnet:?xt=urn:btih:a621779b5e3d486e127c3efbca9b6f8d135f52e5&dn=rutor.info_%D0%92%D0%BE%D0%B9%D0%BD%D0%B0+%D0%B1%D1%83%D0%B4%D1%83%D1%89%D0%B5%D0%B3%D0%BE+%2F+The+Tomorrow+War+%282021%29+WEB-DLRip+%D0%BE%D1%82+MegaPeer+%7C+P+%7C+NewComers&tr=udp://opentor.org:2710&tr=udp://opentor.org:2710&tr=http://retracker.local/announce";
|
||||
dbg!(url::Url::parse(magnet).unwrap());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,141 +0,0 @@
|
|||
use std::{
|
||||
collections::HashMap,
|
||||
net::{IpAddr, Ipv4Addr, Ipv6Addr},
|
||||
};
|
||||
|
||||
use byteorder::ByteOrder;
|
||||
use byteorder::BE;
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
|
||||
use crate::{
|
||||
buffers::ByteBuf, clone_to_owned::CloneToOwned, peer_binary_protocol::MY_EXTENDED_UT_METADATA,
|
||||
};
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug, Default)]
|
||||
pub struct ExtendedHandshake<ByteBuf: Eq + std::hash::Hash> {
|
||||
#[serde(bound(deserialize = "ByteBuf: From<&'de [u8]>"))]
|
||||
pub m: HashMap<ByteBuf, u8>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub p: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub v: Option<ByteBuf>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub yourip: Option<YourIP>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub ipv6: Option<ByteBuf>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub ipv4: Option<ByteBuf>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub reqq: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub metadata_size: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub complete_ago: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub upload_only: Option<u32>,
|
||||
}
|
||||
|
||||
impl ExtendedHandshake<ByteBuf<'static>> {
|
||||
pub fn new() -> Self {
|
||||
let mut features = HashMap::new();
|
||||
features.insert(ByteBuf(b"ut_metadata"), MY_EXTENDED_UT_METADATA);
|
||||
Self {
|
||||
m: features,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<ByteBuf: Eq + std::hash::Hash> ExtendedHandshake<ByteBuf> {
|
||||
pub fn get_msgid(&self, msg_type: &[u8]) -> Option<u8>
|
||||
where
|
||||
ByteBuf: AsRef<[u8]>,
|
||||
{
|
||||
self.m.iter().find_map(|(k, v)| {
|
||||
if k.as_ref() == msg_type {
|
||||
Some(*v)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<ByteBuf> CloneToOwned for ExtendedHandshake<ByteBuf>
|
||||
where
|
||||
ByteBuf: CloneToOwned + Eq + std::hash::Hash,
|
||||
<ByteBuf as CloneToOwned>::Target: Eq + std::hash::Hash,
|
||||
{
|
||||
type Target = ExtendedHandshake<<ByteBuf as CloneToOwned>::Target>;
|
||||
|
||||
fn clone_to_owned(&self) -> Self::Target {
|
||||
ExtendedHandshake {
|
||||
m: self.m.clone_to_owned(),
|
||||
p: self.p,
|
||||
v: self.v.clone_to_owned(),
|
||||
yourip: self.yourip,
|
||||
ipv6: self.ipv6.clone_to_owned(),
|
||||
ipv4: self.ipv4.clone_to_owned(),
|
||||
reqq: self.reqq,
|
||||
metadata_size: self.metadata_size,
|
||||
complete_ago: self.complete_ago,
|
||||
upload_only: self.upload_only,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct YourIP(pub IpAddr);
|
||||
|
||||
impl Serialize for YourIP {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
match self.0 {
|
||||
IpAddr::V4(ipv4) => {
|
||||
let buf = ipv4.octets();
|
||||
serializer.serialize_bytes(&buf)
|
||||
}
|
||||
IpAddr::V6(_) => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for YourIP {
|
||||
fn deserialize<D>(de: D) -> Result<YourIP, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct Visitor {}
|
||||
impl<'de> serde::de::Visitor<'de> for Visitor {
|
||||
type Value = YourIP;
|
||||
|
||||
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "expecting 4 bytes of ipv4 or 16 bytes of ipv6")
|
||||
}
|
||||
|
||||
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
if v.len() == 4 {
|
||||
return Ok(YourIP(IpAddr::V4(Ipv4Addr::new(v[0], v[1], v[2], v[3]))));
|
||||
} else if v.len() == 16 {
|
||||
return Ok(YourIP(IpAddr::V6(Ipv6Addr::new(
|
||||
BE::read_u16(&v[..2]),
|
||||
BE::read_u16(&v[2..4]),
|
||||
BE::read_u16(&v[4..6]),
|
||||
BE::read_u16(&v[6..8]),
|
||||
BE::read_u16(&v[8..10]),
|
||||
BE::read_u16(&v[10..12]),
|
||||
BE::read_u16(&v[12..14]),
|
||||
BE::read_u16(&v[14..]),
|
||||
))));
|
||||
}
|
||||
Err(E::custom("expected 4 or 16 byte address"))
|
||||
}
|
||||
}
|
||||
de.deserialize_bytes(Visitor {})
|
||||
}
|
||||
}
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{bencode_value::BencodeValue, buffers::ByteString, clone_to_owned::CloneToOwned};
|
||||
|
||||
use self::{handshake::ExtendedHandshake, ut_metadata::UtMetadata};
|
||||
|
||||
use super::MessageDeserializeError;
|
||||
|
||||
pub mod handshake;
|
||||
pub mod ut_metadata;
|
||||
|
||||
use super::MY_EXTENDED_UT_METADATA;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ExtendedMessage<ByteBuf: std::hash::Hash + Eq> {
|
||||
Handshake(ExtendedHandshake<ByteBuf>),
|
||||
UtMetadata(UtMetadata<ByteBuf>),
|
||||
Dyn(u8, BencodeValue<ByteBuf>),
|
||||
}
|
||||
|
||||
impl<ByteBuf> CloneToOwned for ExtendedMessage<ByteBuf>
|
||||
where
|
||||
ByteBuf: CloneToOwned + std::hash::Hash + Eq,
|
||||
<ByteBuf as CloneToOwned>::Target: std::hash::Hash + Eq,
|
||||
{
|
||||
type Target = ExtendedMessage<<ByteBuf as CloneToOwned>::Target>;
|
||||
|
||||
fn clone_to_owned(&self) -> Self::Target {
|
||||
match self {
|
||||
ExtendedMessage::Handshake(h) => ExtendedMessage::Handshake(h.clone_to_owned()),
|
||||
ExtendedMessage::Dyn(u, d) => ExtendedMessage::Dyn(*u, d.clone_to_owned()),
|
||||
ExtendedMessage::UtMetadata(m) => ExtendedMessage::UtMetadata(m.clone_to_owned()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, ByteBuf: 'a + std::hash::Hash + Eq + Serialize> ExtendedMessage<ByteBuf> {
|
||||
pub fn serialize(
|
||||
&self,
|
||||
out: &mut Vec<u8>,
|
||||
extended_handshake: Option<&ExtendedHandshake<ByteString>>,
|
||||
) -> anyhow::Result<()>
|
||||
where
|
||||
ByteBuf: AsRef<[u8]>,
|
||||
{
|
||||
match self {
|
||||
ExtendedMessage::Dyn(msg_id, v) => {
|
||||
out.push(*msg_id);
|
||||
crate::serde_bencode_ser::bencode_serialize_to_writer(v, out)?;
|
||||
}
|
||||
ExtendedMessage::Handshake(h) => {
|
||||
out.push(0);
|
||||
crate::serde_bencode_ser::bencode_serialize_to_writer(h, out)?;
|
||||
}
|
||||
ExtendedMessage::UtMetadata(u) => {
|
||||
let h = extended_handshake.ok_or_else(|| {
|
||||
anyhow::anyhow!("need peer's handshake to serialize ut_metadata")
|
||||
})?;
|
||||
let emsg_id = h
|
||||
.get_msgid(b"ut_metadata")
|
||||
.ok_or_else(|| anyhow::anyhow!("peer doesn't support ut_metadata"))?;
|
||||
out.push(emsg_id);
|
||||
u.serialize(out);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn deserialize(mut buf: &'a [u8]) -> Result<Self, MessageDeserializeError>
|
||||
where
|
||||
ByteBuf: Deserialize<'a> + From<&'a [u8]>,
|
||||
{
|
||||
use crate::serde_bencode_de::from_bytes;
|
||||
|
||||
let emsg_id = buf.get(0).copied().ok_or_else(|| {
|
||||
MessageDeserializeError::Other(anyhow::anyhow!(
|
||||
"cannot deserialize extended message: can't read first byte"
|
||||
))
|
||||
})?;
|
||||
|
||||
buf = &buf.get(1..).ok_or_else(|| {
|
||||
MessageDeserializeError::Other(anyhow::anyhow!(
|
||||
"cannot deserialize extended message: buffer empty"
|
||||
))
|
||||
})?;
|
||||
|
||||
match emsg_id {
|
||||
0 => Ok(ExtendedMessage::Handshake(from_bytes(&buf)?)),
|
||||
MY_EXTENDED_UT_METADATA => {
|
||||
Ok(ExtendedMessage::UtMetadata(UtMetadata::deserialize(&buf)?))
|
||||
}
|
||||
_ => Ok(ExtendedMessage::Dyn(emsg_id, from_bytes(&buf)?)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,142 +0,0 @@
|
|||
use std::io::Write;
|
||||
|
||||
use crate::{
|
||||
clone_to_owned::CloneToOwned, peer_binary_protocol::MessageDeserializeError,
|
||||
serde_bencode_de::BencodeDeserializer, serde_bencode_ser::bencode_serialize_to_writer,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum UtMetadata<ByteBuf> {
|
||||
Request(u32),
|
||||
Data {
|
||||
piece: u32,
|
||||
total_size: u32,
|
||||
data: ByteBuf,
|
||||
},
|
||||
Reject(u32),
|
||||
}
|
||||
|
||||
impl<ByteBuf: CloneToOwned> CloneToOwned for UtMetadata<ByteBuf> {
|
||||
type Target = UtMetadata<<ByteBuf as CloneToOwned>::Target>;
|
||||
|
||||
fn clone_to_owned(&self) -> Self::Target {
|
||||
match self {
|
||||
UtMetadata::Request(req) => UtMetadata::Request(*req),
|
||||
UtMetadata::Data {
|
||||
piece,
|
||||
total_size,
|
||||
data,
|
||||
} => UtMetadata::Data {
|
||||
piece: *piece,
|
||||
total_size: *total_size,
|
||||
data: data.clone_to_owned(),
|
||||
},
|
||||
UtMetadata::Reject(piece) => UtMetadata::Reject(*piece),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, ByteBuf: 'a> UtMetadata<ByteBuf> {
|
||||
pub fn serialize(&self, buf: &mut Vec<u8>)
|
||||
where
|
||||
ByteBuf: AsRef<[u8]>,
|
||||
{
|
||||
#[derive(Serialize)]
|
||||
struct Message {
|
||||
msg_type: u32,
|
||||
piece: u32,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
total_size: Option<u32>,
|
||||
}
|
||||
match self {
|
||||
UtMetadata::Request(piece) => {
|
||||
let message = Message {
|
||||
msg_type: 0,
|
||||
piece: *piece,
|
||||
total_size: None,
|
||||
};
|
||||
bencode_serialize_to_writer(message, buf).unwrap()
|
||||
}
|
||||
UtMetadata::Data {
|
||||
piece,
|
||||
total_size,
|
||||
data,
|
||||
} => {
|
||||
let message = Message {
|
||||
msg_type: 1,
|
||||
piece: *piece,
|
||||
total_size: Some(*total_size),
|
||||
};
|
||||
bencode_serialize_to_writer(message, buf).unwrap();
|
||||
buf.write_all(data.as_ref()).unwrap();
|
||||
}
|
||||
UtMetadata::Reject(piece) => {
|
||||
let message = Message {
|
||||
msg_type: 2,
|
||||
piece: *piece,
|
||||
total_size: None,
|
||||
};
|
||||
bencode_serialize_to_writer(message, buf).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn deserialize(buf: &'a [u8]) -> Result<Self, MessageDeserializeError>
|
||||
where
|
||||
ByteBuf: From<&'a [u8]>,
|
||||
{
|
||||
let mut de = BencodeDeserializer::new_from_buf(buf);
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Message {
|
||||
msg_type: u32,
|
||||
piece: u32,
|
||||
total_size: Option<u32>,
|
||||
}
|
||||
|
||||
let message =
|
||||
Message::deserialize(&mut de).map_err(|e| MessageDeserializeError::Other(e.into()))?;
|
||||
let remaining = de.into_remaining();
|
||||
|
||||
match message.msg_type {
|
||||
// request
|
||||
0 => {
|
||||
if !remaining.is_empty() {
|
||||
return Err(MessageDeserializeError::Other(anyhow::anyhow!(
|
||||
"trailing bytes when decoding UtMetadata"
|
||||
)));
|
||||
}
|
||||
Ok(UtMetadata::Request(message.piece))
|
||||
}
|
||||
// data
|
||||
1 => {
|
||||
let total_size = message.total_size.ok_or_else(|| {
|
||||
MessageDeserializeError::Other(anyhow::anyhow!(
|
||||
"expected key total_size to be present in UtMetadata \"data\" message"
|
||||
))
|
||||
})?;
|
||||
Ok(UtMetadata::Data {
|
||||
piece: message.piece,
|
||||
total_size,
|
||||
data: ByteBuf::from(remaining),
|
||||
})
|
||||
}
|
||||
// reject
|
||||
2 => {
|
||||
if !remaining.is_empty() {
|
||||
return Err(MessageDeserializeError::Other(anyhow::anyhow!(
|
||||
"trailing bytes when decoding UtMetadata"
|
||||
)));
|
||||
}
|
||||
Ok(UtMetadata::Reject(message.piece))
|
||||
}
|
||||
other => {
|
||||
return Err(MessageDeserializeError::Other(anyhow::anyhow!(
|
||||
"unrecognized ut_metadata message type {}",
|
||||
other
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,599 +0,0 @@
|
|||
pub mod extended;
|
||||
|
||||
use bincode::Options;
|
||||
use byteorder::{ByteOrder, BE};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
buffers::{ByteBuf, ByteString},
|
||||
clone_to_owned::CloneToOwned,
|
||||
constants::CHUNK_SIZE,
|
||||
lengths::ChunkInfo,
|
||||
};
|
||||
|
||||
use self::extended::{handshake::ExtendedHandshake, ExtendedMessage};
|
||||
|
||||
const INTEGER_LEN: usize = 4;
|
||||
const MSGID_LEN: usize = 1;
|
||||
const PREAMBLE_LEN: usize = INTEGER_LEN + MSGID_LEN;
|
||||
const PIECE_MESSAGE_PREAMBLE_LEN: usize = PREAMBLE_LEN + INTEGER_LEN * 2;
|
||||
pub const PIECE_MESSAGE_DEFAULT_LEN: usize = PIECE_MESSAGE_PREAMBLE_LEN + CHUNK_SIZE as usize;
|
||||
|
||||
const NO_PAYLOAD_MSG_LEN: usize = PREAMBLE_LEN;
|
||||
|
||||
const PSTR_BT1: &str = "BitTorrent protocol";
|
||||
|
||||
const LEN_PREFIX_KEEPALIVE: u32 = 0;
|
||||
const LEN_PREFIX_CHOKE: u32 = 1;
|
||||
const LEN_PREFIX_UNCHOKE: u32 = 1;
|
||||
const LEN_PREFIX_INTERESTED: u32 = 1;
|
||||
const LEN_PREFIX_NOT_INTERESTED: u32 = 1;
|
||||
const LEN_PREFIX_HAVE: u32 = 5;
|
||||
const LEN_PREFIX_PIECE: u32 = 9;
|
||||
const LEN_PREFIX_REQUEST: u32 = 13;
|
||||
|
||||
const MSGID_CHOKE: u8 = 0;
|
||||
const MSGID_UNCHOKE: u8 = 1;
|
||||
const MSGID_INTERESTED: u8 = 2;
|
||||
const MSGID_NOT_INTERESTED: u8 = 3;
|
||||
const MSGID_HAVE: u8 = 4;
|
||||
const MSGID_BITFIELD: u8 = 5;
|
||||
const MSGID_REQUEST: u8 = 6;
|
||||
const MSGID_PIECE: u8 = 7;
|
||||
const MSGID_EXTENDED: u8 = 20;
|
||||
|
||||
pub const MY_EXTENDED_UT_METADATA: u8 = 3;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MessageDeserializeError {
|
||||
NotEnoughData(usize, &'static str),
|
||||
UnsupportedMessageId(u8),
|
||||
IncorrectLenPrefix {
|
||||
received: u32,
|
||||
expected: u32,
|
||||
msg_id: u8,
|
||||
},
|
||||
OtherBincode {
|
||||
error: bincode::Error,
|
||||
msg_id: u8,
|
||||
len_prefix: u32,
|
||||
name: &'static str,
|
||||
},
|
||||
Other(anyhow::Error),
|
||||
}
|
||||
|
||||
pub fn serialize_piece_preamble(chunk: &ChunkInfo, mut buf: &mut [u8]) -> usize {
|
||||
BE::write_u32(&mut buf[0..4], LEN_PREFIX_PIECE + chunk.size);
|
||||
buf[4] = MSGID_PIECE;
|
||||
|
||||
buf = &mut buf[PREAMBLE_LEN..];
|
||||
BE::write_u32(&mut buf[0..4], chunk.piece_index.get());
|
||||
BE::write_u32(&mut buf[4..8], chunk.offset);
|
||||
|
||||
PIECE_MESSAGE_PREAMBLE_LEN
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Piece<ByteBuf> {
|
||||
pub index: u32,
|
||||
pub begin: u32,
|
||||
pub block: ByteBuf,
|
||||
}
|
||||
|
||||
impl<ByteBuf> Piece<ByteBuf>
|
||||
where
|
||||
ByteBuf: AsRef<[u8]>,
|
||||
{
|
||||
pub fn from_data<T>(index: u32, begin: u32, block: T) -> Piece<ByteBuf>
|
||||
where
|
||||
ByteBuf: From<T>,
|
||||
{
|
||||
Piece {
|
||||
index,
|
||||
begin,
|
||||
block: ByteBuf::from(block),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn serialize(&self, mut buf: &mut [u8]) -> usize {
|
||||
byteorder::BigEndian::write_u32(&mut buf[0..4], self.index);
|
||||
byteorder::BigEndian::write_u32(&mut buf[4..8], self.begin);
|
||||
buf = &mut buf[8..];
|
||||
buf.copy_from_slice(self.block.as_ref());
|
||||
self.block.as_ref().len() + 8
|
||||
}
|
||||
pub fn deserialize<'a>(buf: &'a [u8]) -> Piece<ByteBuf>
|
||||
where
|
||||
ByteBuf: From<&'a [u8]> + 'a,
|
||||
{
|
||||
let index = byteorder::BigEndian::read_u32(&buf[0..4]);
|
||||
let begin = byteorder::BigEndian::read_u32(&buf[4..8]);
|
||||
let block = ByteBuf::from(&buf[8..]);
|
||||
Piece {
|
||||
index,
|
||||
begin,
|
||||
block,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for MessageDeserializeError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
MessageDeserializeError::NotEnoughData(b, name) => {
|
||||
write!(
|
||||
f,
|
||||
"not enough data to deserialize {}: expected at least {} more bytes",
|
||||
name, b
|
||||
)
|
||||
}
|
||||
MessageDeserializeError::UnsupportedMessageId(msg_id) => {
|
||||
write!(f, "unsupported message id {}", msg_id)
|
||||
}
|
||||
MessageDeserializeError::IncorrectLenPrefix {
|
||||
received,
|
||||
expected,
|
||||
msg_id,
|
||||
} => write!(
|
||||
f,
|
||||
"incorrect len prefix for message id {}, expected {}, received {}",
|
||||
msg_id, expected, received
|
||||
),
|
||||
MessageDeserializeError::OtherBincode {
|
||||
error,
|
||||
msg_id,
|
||||
name,
|
||||
len_prefix,
|
||||
} => write!(
|
||||
f,
|
||||
"error deserializing {} (msg_id={}, len_prefix={}): {:?}",
|
||||
name, msg_id, len_prefix, error
|
||||
),
|
||||
MessageDeserializeError::Other(e) => write!(f, "{}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for MessageDeserializeError {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
MessageDeserializeError::OtherBincode { error, .. } => Some(error),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<anyhow::Error> for MessageDeserializeError {
|
||||
fn from(e: anyhow::Error) -> Self {
|
||||
MessageDeserializeError::Other(e)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Message<ByteBuf: std::hash::Hash + Eq> {
|
||||
Request(Request),
|
||||
Bitfield(ByteBuf),
|
||||
KeepAlive,
|
||||
Have(u32),
|
||||
Choke,
|
||||
Unchoke,
|
||||
Interested,
|
||||
NotInterested,
|
||||
Piece(Piece<ByteBuf>),
|
||||
Extended(ExtendedMessage<ByteBuf>),
|
||||
}
|
||||
|
||||
pub type MessageBorrowed<'a> = Message<ByteBuf<'a>>;
|
||||
pub type MessageOwned = Message<ByteString>;
|
||||
|
||||
pub type BitfieldBorrowed<'a> = &'a bitvec::slice::BitSlice<bitvec::order::Lsb0, u8>;
|
||||
pub type BitfieldOwned = bitvec::vec::BitVec<bitvec::order::Lsb0, u8>;
|
||||
|
||||
pub struct Bitfield<'a> {
|
||||
pub data: BitfieldBorrowed<'a>,
|
||||
}
|
||||
|
||||
impl<ByteBuf> CloneToOwned for Message<ByteBuf>
|
||||
where
|
||||
ByteBuf: CloneToOwned + std::hash::Hash + Eq,
|
||||
<ByteBuf as CloneToOwned>::Target: std::hash::Hash + Eq,
|
||||
{
|
||||
type Target = Message<<ByteBuf as CloneToOwned>::Target>;
|
||||
|
||||
fn clone_to_owned(&self) -> Self::Target {
|
||||
match self {
|
||||
Message::Request(req) => Message::Request(*req),
|
||||
Message::Bitfield(b) => Message::Bitfield(b.clone_to_owned()),
|
||||
Message::Choke => Message::Choke,
|
||||
Message::Unchoke => Message::Unchoke,
|
||||
Message::Interested => Message::Interested,
|
||||
Message::Piece(piece) => Message::Piece(Piece {
|
||||
index: piece.index,
|
||||
begin: piece.begin,
|
||||
block: piece.block.clone_to_owned(),
|
||||
}),
|
||||
Message::KeepAlive => Message::KeepAlive,
|
||||
Message::Have(v) => Message::Have(*v),
|
||||
Message::NotInterested => Message::NotInterested,
|
||||
Message::Extended(e) => Message::Extended(e.clone_to_owned()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Bitfield<'a> {
|
||||
pub fn new_from_slice(buf: &'a [u8]) -> anyhow::Result<Self> {
|
||||
Ok(Self {
|
||||
data: bitvec::slice::BitSlice::from_slice(buf)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::fmt::Debug for Bitfield<'a> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Bitfield")
|
||||
.field("_ones", &self.data.count_ones())
|
||||
.field("_len", &self.data.len())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<ByteBuf> Message<ByteBuf>
|
||||
where
|
||||
ByteBuf: AsRef<[u8]> + std::hash::Hash + Eq + Serialize,
|
||||
{
|
||||
pub fn len_prefix_and_msg_id(&self) -> (u32, u8) {
|
||||
match self {
|
||||
Message::Request(_) => (LEN_PREFIX_REQUEST, MSGID_REQUEST),
|
||||
Message::Bitfield(b) => (1 + b.as_ref().len() as u32, MSGID_BITFIELD),
|
||||
Message::Choke => (LEN_PREFIX_CHOKE, MSGID_CHOKE),
|
||||
Message::Unchoke => (LEN_PREFIX_UNCHOKE, MSGID_UNCHOKE),
|
||||
Message::Interested => (LEN_PREFIX_INTERESTED, MSGID_INTERESTED),
|
||||
Message::NotInterested => (LEN_PREFIX_NOT_INTERESTED, MSGID_NOT_INTERESTED),
|
||||
Message::Piece(p) => (
|
||||
LEN_PREFIX_PIECE + p.block.as_ref().len() as u32,
|
||||
MSGID_PIECE,
|
||||
),
|
||||
Message::KeepAlive => (LEN_PREFIX_KEEPALIVE, 0),
|
||||
Message::Have(_) => (LEN_PREFIX_HAVE, MSGID_HAVE),
|
||||
Message::Extended(_) => (0, MSGID_EXTENDED),
|
||||
}
|
||||
}
|
||||
pub fn serialize(
|
||||
&self,
|
||||
out: &mut Vec<u8>,
|
||||
peer_extended_handshake: Option<&ExtendedHandshake<ByteString>>,
|
||||
) -> anyhow::Result<usize> {
|
||||
let (lp, msg_id) = self.len_prefix_and_msg_id();
|
||||
|
||||
out.resize(PREAMBLE_LEN, 0);
|
||||
|
||||
byteorder::BigEndian::write_u32(&mut out[..4], lp);
|
||||
out[4] = msg_id;
|
||||
|
||||
let ser = bopts();
|
||||
|
||||
match self {
|
||||
Message::Request(request) => {
|
||||
const MSG_LEN: usize = PREAMBLE_LEN + 12;
|
||||
out.resize(MSG_LEN, 0);
|
||||
debug_assert_eq!((&out[PREAMBLE_LEN..]).len(), 12);
|
||||
ser.serialize_into(&mut out[PREAMBLE_LEN..], request)
|
||||
.unwrap();
|
||||
Ok(MSG_LEN)
|
||||
}
|
||||
Message::Bitfield(b) => {
|
||||
let block_len = b.as_ref().len();
|
||||
let msg_len = PREAMBLE_LEN + block_len;
|
||||
out.resize(msg_len, 0);
|
||||
(&mut out[PREAMBLE_LEN..PREAMBLE_LEN + block_len]).copy_from_slice(b.as_ref());
|
||||
Ok(msg_len)
|
||||
}
|
||||
Message::Choke | Message::Unchoke | Message::Interested | Message::NotInterested => {
|
||||
Ok(PREAMBLE_LEN)
|
||||
}
|
||||
Message::Piece(p) => {
|
||||
let block_len = p.block.as_ref().len();
|
||||
let payload_len = 8 + block_len;
|
||||
let msg_len = PREAMBLE_LEN + payload_len;
|
||||
out.resize(msg_len, 0);
|
||||
let tmp = &mut out[PREAMBLE_LEN..];
|
||||
p.serialize(&mut tmp[..payload_len]);
|
||||
Ok(msg_len)
|
||||
}
|
||||
Message::KeepAlive => {
|
||||
// the len prefix was already written out to buf
|
||||
Ok(4)
|
||||
}
|
||||
Message::Have(v) => {
|
||||
let msg_len = PREAMBLE_LEN + 4;
|
||||
out.resize(msg_len, 0);
|
||||
BE::write_u32(&mut out[PREAMBLE_LEN..], *v);
|
||||
Ok(msg_len)
|
||||
}
|
||||
Message::Extended(e) => {
|
||||
e.serialize(out, peer_extended_handshake)?;
|
||||
let msg_size = out.len();
|
||||
// no fucking idea why +1, but I tweaked that for it all to match up
|
||||
// with real messages.
|
||||
BE::write_u32(&mut out[..4], (msg_size - PREAMBLE_LEN + 1) as u32);
|
||||
Ok(msg_size)
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn deserialize<'a>(
|
||||
buf: &'a [u8],
|
||||
) -> Result<(Message<ByteBuf>, usize), MessageDeserializeError>
|
||||
where
|
||||
ByteBuf: From<&'a [u8]> + 'a + Deserialize<'a>,
|
||||
{
|
||||
let len_prefix = match buf.get(0..4) {
|
||||
Some(bytes) => byteorder::BigEndian::read_u32(bytes),
|
||||
None => return Err(MessageDeserializeError::NotEnoughData(4, "message")),
|
||||
};
|
||||
if len_prefix == 0 {
|
||||
return Ok((Message::KeepAlive, 4));
|
||||
}
|
||||
|
||||
let msg_id = match buf.get(4) {
|
||||
Some(msg_id) => *msg_id,
|
||||
None => return Err(MessageDeserializeError::NotEnoughData(1, "message")),
|
||||
};
|
||||
let rest = &buf[5..];
|
||||
let decoder_config = bincode::DefaultOptions::new()
|
||||
.with_fixint_encoding()
|
||||
.with_big_endian();
|
||||
|
||||
match msg_id {
|
||||
MSGID_CHOKE => {
|
||||
if len_prefix != LEN_PREFIX_CHOKE {
|
||||
return Err(MessageDeserializeError::IncorrectLenPrefix {
|
||||
received: len_prefix,
|
||||
expected: LEN_PREFIX_CHOKE,
|
||||
msg_id,
|
||||
});
|
||||
}
|
||||
Ok((Message::Choke, NO_PAYLOAD_MSG_LEN))
|
||||
}
|
||||
MSGID_UNCHOKE => {
|
||||
if len_prefix != LEN_PREFIX_UNCHOKE {
|
||||
return Err(MessageDeserializeError::IncorrectLenPrefix {
|
||||
received: len_prefix,
|
||||
expected: LEN_PREFIX_UNCHOKE,
|
||||
msg_id,
|
||||
});
|
||||
}
|
||||
Ok((Message::Unchoke, NO_PAYLOAD_MSG_LEN))
|
||||
}
|
||||
MSGID_INTERESTED => {
|
||||
if len_prefix != LEN_PREFIX_INTERESTED {
|
||||
return Err(MessageDeserializeError::IncorrectLenPrefix {
|
||||
received: len_prefix,
|
||||
expected: LEN_PREFIX_INTERESTED,
|
||||
msg_id,
|
||||
});
|
||||
}
|
||||
Ok((Message::Interested, NO_PAYLOAD_MSG_LEN))
|
||||
}
|
||||
MSGID_NOT_INTERESTED => {
|
||||
if len_prefix != LEN_PREFIX_NOT_INTERESTED {
|
||||
return Err(MessageDeserializeError::IncorrectLenPrefix {
|
||||
received: len_prefix,
|
||||
expected: LEN_PREFIX_NOT_INTERESTED,
|
||||
msg_id,
|
||||
});
|
||||
}
|
||||
Ok((Message::NotInterested, NO_PAYLOAD_MSG_LEN))
|
||||
}
|
||||
MSGID_HAVE => {
|
||||
let expected_len = 4;
|
||||
match rest.get(..expected_len as usize) {
|
||||
Some(h) => Ok((Message::Have(BE::read_u32(&h)), PREAMBLE_LEN + expected_len)),
|
||||
None => {
|
||||
let missing = expected_len - rest.len();
|
||||
Err(MessageDeserializeError::NotEnoughData(missing, "have"))
|
||||
}
|
||||
}
|
||||
}
|
||||
MSGID_BITFIELD => {
|
||||
if len_prefix <= 1 {
|
||||
return Err(MessageDeserializeError::IncorrectLenPrefix {
|
||||
expected: 2,
|
||||
received: len_prefix,
|
||||
msg_id,
|
||||
});
|
||||
}
|
||||
let expected_len = len_prefix as usize - 1;
|
||||
match rest.get(..expected_len as usize) {
|
||||
Some(bitfield) => Ok((
|
||||
Message::Bitfield(ByteBuf::from(bitfield)),
|
||||
PREAMBLE_LEN + expected_len,
|
||||
)),
|
||||
None => {
|
||||
let missing = expected_len - rest.len();
|
||||
Err(MessageDeserializeError::NotEnoughData(missing, "bitfield"))
|
||||
}
|
||||
}
|
||||
}
|
||||
MSGID_REQUEST => {
|
||||
let expected_len = 12;
|
||||
match rest.get(..expected_len as usize) {
|
||||
Some(b) => {
|
||||
let request = decoder_config.deserialize::<Request>(&b).unwrap();
|
||||
Ok((Message::Request(request), PREAMBLE_LEN + expected_len))
|
||||
}
|
||||
None => {
|
||||
let missing = expected_len - rest.len();
|
||||
Err(MessageDeserializeError::NotEnoughData(missing, "request"))
|
||||
}
|
||||
}
|
||||
}
|
||||
MSGID_PIECE => {
|
||||
if len_prefix <= 9 {
|
||||
return Err(MessageDeserializeError::IncorrectLenPrefix {
|
||||
expected: 10,
|
||||
received: len_prefix,
|
||||
msg_id,
|
||||
});
|
||||
}
|
||||
// <len=0009+X> is for "9", "8" is for 2 integer fields in the piece.
|
||||
let expected_len = len_prefix as usize - 9 + 8;
|
||||
match rest.get(..expected_len) {
|
||||
Some(b) => Ok((
|
||||
Message::Piece(Piece::deserialize(&b)),
|
||||
PREAMBLE_LEN + expected_len,
|
||||
)),
|
||||
None => Err(MessageDeserializeError::NotEnoughData(
|
||||
expected_len - rest.len(),
|
||||
"piece",
|
||||
)),
|
||||
}
|
||||
}
|
||||
MSGID_EXTENDED => {
|
||||
if len_prefix <= 6 {
|
||||
return Err(MessageDeserializeError::IncorrectLenPrefix {
|
||||
expected: 6,
|
||||
received: len_prefix,
|
||||
msg_id,
|
||||
});
|
||||
}
|
||||
// TODO: NO clue why - 1 here. Empirically figured out.
|
||||
let expected_len = len_prefix as usize - 1;
|
||||
match rest.get(..expected_len) {
|
||||
Some(b) => Ok((
|
||||
Message::Extended(ExtendedMessage::deserialize(&b)?),
|
||||
PREAMBLE_LEN + expected_len,
|
||||
)),
|
||||
None => Err(MessageDeserializeError::NotEnoughData(
|
||||
expected_len - rest.len(),
|
||||
"extended",
|
||||
)),
|
||||
}
|
||||
}
|
||||
msg_id => Err(MessageDeserializeError::UnsupportedMessageId(msg_id)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct Handshake<'a> {
|
||||
pub pstr: &'a str,
|
||||
pub reserved: [u8; 8],
|
||||
pub info_hash: [u8; 20],
|
||||
pub peer_id: [u8; 20],
|
||||
}
|
||||
|
||||
fn bopts() -> impl bincode::Options {
|
||||
bincode::DefaultOptions::new()
|
||||
.with_fixint_encoding()
|
||||
.with_big_endian()
|
||||
}
|
||||
|
||||
impl<'a> Handshake<'a> {
|
||||
pub fn new(info_hash: [u8; 20], peer_id: [u8; 20]) -> Handshake<'static> {
|
||||
debug_assert_eq!(PSTR_BT1.len(), 19);
|
||||
|
||||
let mut reserved: u64 = 0;
|
||||
// supports extended messaging
|
||||
reserved |= 1 << 20;
|
||||
let mut reserved_arr = [0u8; 8];
|
||||
BE::write_u64(&mut reserved_arr, reserved);
|
||||
|
||||
Handshake {
|
||||
pstr: PSTR_BT1,
|
||||
reserved: reserved_arr,
|
||||
info_hash,
|
||||
peer_id,
|
||||
}
|
||||
}
|
||||
pub fn supports_extended(&self) -> bool {
|
||||
self.reserved[5] & 0x10 > 0
|
||||
}
|
||||
fn bopts() -> impl bincode::Options {
|
||||
bincode::DefaultOptions::new()
|
||||
}
|
||||
pub fn deserialize(b: &[u8]) -> Result<(Handshake<'_>, usize), MessageDeserializeError> {
|
||||
let pstr_len = *b
|
||||
.get(0)
|
||||
.ok_or(MessageDeserializeError::NotEnoughData(1, "handshake"))?;
|
||||
let expected_len = 1usize + pstr_len as usize + 48;
|
||||
let hbuf = b
|
||||
.get(..expected_len)
|
||||
.ok_or(MessageDeserializeError::NotEnoughData(
|
||||
expected_len,
|
||||
"handshake",
|
||||
))?;
|
||||
Ok((Self::bopts().deserialize(&hbuf).unwrap(), expected_len))
|
||||
}
|
||||
pub fn serialize(&self, buf: &mut Vec<u8>) {
|
||||
Self::bopts().serialize_into(buf, &self).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
|
||||
pub struct Request {
|
||||
pub index: u32,
|
||||
pub begin: u32,
|
||||
pub length: u32,
|
||||
}
|
||||
|
||||
impl Request {
|
||||
pub fn new(index: u32, begin: u32, length: u32) -> Self {
|
||||
Self {
|
||||
index,
|
||||
begin,
|
||||
length,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn test_handshake_serialize() {
|
||||
let info_hash = [
|
||||
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
|
||||
];
|
||||
let peer_id = [
|
||||
1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
|
||||
];
|
||||
let mut buf = Vec::new();
|
||||
Handshake::new(info_hash, peer_id).serialize(&mut buf);
|
||||
assert_eq!(buf.len(), 20 + 20 + 8 + 19 + 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extended_serialize() {
|
||||
let msg = Message::Extended(ExtendedMessage::Handshake(ExtendedHandshake::new()));
|
||||
let mut out = Vec::new();
|
||||
msg.serialize(&mut out, None).unwrap();
|
||||
dbg!(out);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deserialize_serialize_extended_is_same() {
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
let mut buf = Vec::new();
|
||||
File::open("resources/test/extended-handshake.bin")
|
||||
.unwrap()
|
||||
.read_to_end(&mut buf)
|
||||
.unwrap();
|
||||
let (msg, size) = MessageBorrowed::deserialize(&buf).unwrap();
|
||||
assert_eq!(size, buf.len());
|
||||
let mut write_buf = Vec::new();
|
||||
msg.serialize(&mut write_buf, None).unwrap();
|
||||
if buf != write_buf {
|
||||
{
|
||||
use std::io::Write;
|
||||
let mut f = std::fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
.open("/tmp/test_deserialize_serialize_extended_is_same")
|
||||
.unwrap();
|
||||
f.write_all(&write_buf).unwrap();
|
||||
}
|
||||
panic!("resources/test/extended-handshake.bin did not serialize exactly the same. Dumped to /tmp/test_deserialize_serialize_extended_is_same, you can compare with resources/test/extended-handshake.bin")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +1,16 @@
|
|||
use std::{net::SocketAddr, time::Duration};
|
||||
|
||||
use anyhow::Context;
|
||||
use buffers::{ByteBuf, ByteString};
|
||||
use clone_to_owned::CloneToOwned;
|
||||
use librqbit_core::{lengths::ChunkInfo, peer_id::try_decode_peer_id};
|
||||
use log::{debug, trace};
|
||||
use tokio::time::timeout;
|
||||
|
||||
use crate::{
|
||||
buffers::{ByteBuf, ByteString},
|
||||
clone_to_owned::CloneToOwned,
|
||||
lengths::ChunkInfo,
|
||||
peer_binary_protocol::{
|
||||
extended::{handshake::ExtendedHandshake, ExtendedMessage},
|
||||
serialize_piece_preamble, Handshake, Message, MessageBorrowed, MessageDeserializeError,
|
||||
MessageOwned, PIECE_MESSAGE_DEFAULT_LEN,
|
||||
},
|
||||
peer_id::try_decode_peer_id,
|
||||
use peer_binary_protocol::{
|
||||
extended::{handshake::ExtendedHandshake, ExtendedMessage},
|
||||
serialize_piece_preamble, Handshake, Message, MessageBorrowed, MessageDeserializeError,
|
||||
MessageOwned, PIECE_MESSAGE_DEFAULT_LEN,
|
||||
};
|
||||
use tokio::time::timeout;
|
||||
|
||||
pub trait PeerConnectionHandler {
|
||||
fn get_have_bytes(&self) -> u64;
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
#[derive(Debug)]
|
||||
pub enum AzureusStyleKind {
|
||||
Deluge,
|
||||
LibTorrent,
|
||||
Transmission,
|
||||
Other([char; 2]),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AzureusStyle {
|
||||
pub kind: AzureusStyleKind,
|
||||
pub version: [char; 4],
|
||||
}
|
||||
|
||||
impl AzureusStyleKind {
|
||||
pub const fn from_bytes(b1: u8, b2: u8) -> Self {
|
||||
match &[b1, b2] {
|
||||
b"DE" => AzureusStyleKind::Deluge,
|
||||
b"lt" | b"LT" => AzureusStyleKind::LibTorrent,
|
||||
b"TR" => AzureusStyleKind::Transmission,
|
||||
_ => AzureusStyleKind::Other([b1 as char, b2 as char]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn try_decode_azureus_style(p: &[u8; 20]) -> Option<AzureusStyle> {
|
||||
if !(p[0] == b'-' && p[7] == b'-') {
|
||||
return None;
|
||||
}
|
||||
let mut version = ['0'; 4];
|
||||
for (i, c) in (&p[3..7]).iter().copied().enumerate() {
|
||||
version[i] = c as char;
|
||||
}
|
||||
let kind = AzureusStyleKind::from_bytes(p[1], p[2]);
|
||||
Some(AzureusStyle { kind, version })
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PeerId {
|
||||
AzureusStyle(AzureusStyle),
|
||||
}
|
||||
|
||||
pub fn try_decode_peer_id(p: [u8; 20]) -> Option<PeerId> {
|
||||
Some(PeerId::AzureusStyle(try_decode_azureus_style(&p)?))
|
||||
}
|
||||
|
||||
pub fn generate_peer_id() -> [u8; 20] {
|
||||
let mut peer_id = [0u8; 20];
|
||||
|
||||
let u = uuid::Uuid::new_v4();
|
||||
(&mut peer_id[4..20]).copy_from_slice(&u.as_bytes()[..]);
|
||||
|
||||
(&mut peer_id[..8]).copy_from_slice(b"-rQ0001-");
|
||||
|
||||
peer_id
|
||||
}
|
||||
|
|
@ -1,23 +1,22 @@
|
|||
use std::net::SocketAddr;
|
||||
|
||||
use crate::sha1w::ISha1;
|
||||
use log::debug;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use tokio::sync::mpsc::UnboundedSender;
|
||||
|
||||
use crate::{
|
||||
buffers::{ByteBuf, ByteString},
|
||||
use bencode::from_bytes;
|
||||
use buffers::{ByteBuf, ByteString};
|
||||
use librqbit_core::{
|
||||
constants::CHUNK_SIZE,
|
||||
lengths::{ceil_div_u64, last_element_size_u64, ChunkInfo},
|
||||
peer_binary_protocol::{
|
||||
extended::{handshake::ExtendedHandshake, ut_metadata::UtMetadata, ExtendedMessage},
|
||||
Handshake, Message,
|
||||
},
|
||||
peer_connection::{PeerConnection, PeerConnectionHandler, WriterRequest},
|
||||
serde_bencode_de::from_bytes,
|
||||
torrent_metainfo::TorrentMetaV1Info,
|
||||
type_aliases::Sha1,
|
||||
};
|
||||
use log::debug;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use peer_binary_protocol::{
|
||||
extended::{handshake::ExtendedHandshake, ut_metadata::UtMetadata, ExtendedMessage},
|
||||
Handshake, Message,
|
||||
};
|
||||
use sha1w::{ISha1, Sha1};
|
||||
use tokio::sync::mpsc::UnboundedSender;
|
||||
|
||||
use crate::peer_connection::{PeerConnection, PeerConnectionHandler, WriterRequest};
|
||||
|
||||
pub async fn read_metainfo_from_peer(
|
||||
addr: SocketAddr,
|
||||
|
|
@ -217,7 +216,7 @@ impl PeerConnectionHandler for Handler {
|
|||
mod tests {
|
||||
use std::{net::SocketAddr, str::FromStr, sync::Once};
|
||||
|
||||
use crate::peer_id::generate_peer_id;
|
||||
use librqbit_core::peer_id::generate_peer_id;
|
||||
|
||||
use super::read_metainfo_from_peer;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
use std::{collections::HashSet, net::SocketAddr, sync::Arc};
|
||||
|
||||
use librqbit_core::lengths::{ChunkInfo, ValidPieceIndex};
|
||||
use tokio::sync::{Notify, Semaphore};
|
||||
|
||||
use crate::{
|
||||
lengths::{ChunkInfo, ValidPieceIndex},
|
||||
type_aliases::BF,
|
||||
};
|
||||
use crate::type_aliases::BF;
|
||||
|
||||
#[derive(Debug, Hash, PartialEq, Eq)]
|
||||
pub struct InflightRequest {
|
||||
|
|
|
|||
|
|
@ -1,566 +0,0 @@
|
|||
use crate::buffers::ByteBuf;
|
||||
use crate::sha1w::ISha1;
|
||||
use crate::type_aliases::Sha1;
|
||||
use serde::de::Error as DeError;
|
||||
|
||||
pub struct BencodeDeserializer<'de> {
|
||||
buf: &'de [u8],
|
||||
field_context: Vec<ByteBuf<'de>>,
|
||||
parsing_key: bool,
|
||||
pub(crate) is_torrent_info: bool,
|
||||
pub(crate) torrent_info_digest: Option<[u8; 20]>,
|
||||
}
|
||||
|
||||
impl<'de> BencodeDeserializer<'de> {
|
||||
pub fn new_from_buf(buf: &'de [u8]) -> BencodeDeserializer<'de> {
|
||||
Self {
|
||||
buf,
|
||||
field_context: Default::default(),
|
||||
parsing_key: false,
|
||||
is_torrent_info: false,
|
||||
torrent_info_digest: None,
|
||||
}
|
||||
}
|
||||
pub fn into_remaining(self) -> &'de [u8] {
|
||||
self.buf
|
||||
}
|
||||
fn parse_integer(&mut self) -> Result<i64, Error> {
|
||||
match self.buf.iter().copied().position(|e| e == b'e') {
|
||||
Some(end) => {
|
||||
let intbytes = &self.buf[1..end];
|
||||
let value: i64 = std::str::from_utf8(intbytes)
|
||||
.map_err(|e| Error::new_from_err(e).set_context(self))?
|
||||
.parse()
|
||||
.map_err(|e| Error::new_from_err(e).set_context(self))?;
|
||||
let rem = self.buf.get(end + 1..).unwrap_or_default();
|
||||
self.buf = rem;
|
||||
Ok(value)
|
||||
}
|
||||
None => Err(Error::custom("cannot parse integer, unexpected EOF").set_context(self)),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_bytes(&mut self) -> Result<&'de [u8], Error> {
|
||||
match self.buf.iter().copied().position(|e| e == b':') {
|
||||
Some(length_delim) => {
|
||||
let lenbytes = &self.buf[..length_delim];
|
||||
let length: usize = std::str::from_utf8(lenbytes)
|
||||
.map_err(|e| Error::new_from_err(e).set_context(self))?
|
||||
.parse()
|
||||
.map_err(|e| Error::new_from_err(e).set_context(self))?;
|
||||
let bytes_start = length_delim + 1;
|
||||
let bytes_end = bytes_start + length;
|
||||
let bytes = &self.buf.get(bytes_start..bytes_end).ok_or_else(|| {
|
||||
Error::custom(format!(
|
||||
"could not get byte range {}..{}, data in the buffer: {:?}",
|
||||
bytes_start, bytes_end, &self.buf
|
||||
))
|
||||
.set_context(self)
|
||||
})?;
|
||||
let rem = self.buf.get(bytes_end..).unwrap_or_default();
|
||||
self.buf = rem;
|
||||
Ok(bytes)
|
||||
}
|
||||
None => Err(Error::custom("cannot parse bytes, unexpected EOF").set_context(self)),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_bytes_checked(&mut self) -> Result<&'de [u8], Error> {
|
||||
let first = match self.buf.first().copied() {
|
||||
Some(first) => first,
|
||||
None => return Err(Error::custom("expected bencode bytes, got EOF").set_context(self)),
|
||||
};
|
||||
match first {
|
||||
b'0'..=b'9' => {}
|
||||
_ => return Err(Error::custom("expected bencode bytes").set_context(self)),
|
||||
}
|
||||
let b = self.parse_bytes()?;
|
||||
if self.parsing_key {
|
||||
self.field_context.push(ByteBuf(b));
|
||||
}
|
||||
Ok(b)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_bytes<'a, T>(buf: &'a [u8]) -> anyhow::Result<T>
|
||||
where
|
||||
T: serde::de::Deserialize<'a>,
|
||||
{
|
||||
let mut de = BencodeDeserializer::new_from_buf(buf);
|
||||
let v = T::deserialize(&mut de)?;
|
||||
if !de.buf.is_empty() {
|
||||
anyhow::bail!(
|
||||
"deserialized successfully, but {} bytes remaining",
|
||||
de.buf.len()
|
||||
)
|
||||
}
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ErrorKind {
|
||||
Other(anyhow::Error),
|
||||
NotSupported(&'static str),
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ErrorContext {
|
||||
field_stack: Vec<String>,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ErrorContext {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let mut it = self.field_stack.iter();
|
||||
if let Some(field) = it.next() {
|
||||
write!(f, "\"{}\"", field)?;
|
||||
} else {
|
||||
return Ok(());
|
||||
}
|
||||
for field in self.field_stack.iter().skip(1) {
|
||||
write!(f, " -> \"{}\"", field)?;
|
||||
}
|
||||
f.write_str(": ")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Error {
|
||||
kind: ErrorKind,
|
||||
context: ErrorContext,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ErrorKind {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
ErrorKind::Other(err) => err.fmt(f),
|
||||
ErrorKind::NotSupported(s) => write!(f, "{} is not supported by bencode", s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}{}", self.context, self.kind)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for Error {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match &self.kind {
|
||||
ErrorKind::Other(err) => err.source(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Error {
|
||||
fn new_from_err<E>(e: E) -> Self
|
||||
where
|
||||
E: std::error::Error + Send + Sync + 'static,
|
||||
{
|
||||
Error {
|
||||
kind: ErrorKind::Other(anyhow::Error::new(e)),
|
||||
context: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn new_from_kind(kind: ErrorKind) -> Self {
|
||||
Self {
|
||||
kind,
|
||||
context: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn new_from_anyhow(e: anyhow::Error) -> Self {
|
||||
Error {
|
||||
kind: ErrorKind::Other(e),
|
||||
context: Default::default(),
|
||||
}
|
||||
}
|
||||
fn custom_with_de<M: std::fmt::Display>(msg: M, de: &BencodeDeserializer<'_>) -> Self {
|
||||
Self::custom(msg).set_context(de)
|
||||
}
|
||||
fn set_context(mut self, de: &BencodeDeserializer<'_>) -> Self {
|
||||
self.context = ErrorContext {
|
||||
field_stack: de.field_context.iter().map(|s| format!("{}", s)).collect(),
|
||||
};
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::de::Error for Error {
|
||||
fn custom<T>(msg: T) -> Self
|
||||
where
|
||||
T: std::fmt::Display,
|
||||
{
|
||||
Self {
|
||||
kind: ErrorKind::Other(anyhow::anyhow!("{}", msg)),
|
||||
context: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut BencodeDeserializer<'de> {
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
match self.buf.first().copied() {
|
||||
Some(b'd') => self.deserialize_map(visitor),
|
||||
Some(b'i') => self.deserialize_u64(visitor),
|
||||
Some(b'l') => self.deserialize_seq(visitor),
|
||||
Some(_) => self.deserialize_bytes(visitor),
|
||||
None => Err(Error::custom_with_de("empty input", self)),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_bool<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
Err(
|
||||
Error::new_from_kind(ErrorKind::NotSupported("bencode doesn't support booleans"))
|
||||
.set_context(self),
|
||||
)
|
||||
}
|
||||
|
||||
fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_i64(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_i64(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_i64(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
if !self.buf.starts_with(b"i") {
|
||||
return Err(Error::custom_with_de("expected bencode int", self));
|
||||
}
|
||||
visitor
|
||||
.visit_i64(self.parse_integer()?)
|
||||
.map_err(|e: Self::Error| e.set_context(self))
|
||||
}
|
||||
|
||||
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_i64(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_i64(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_i64(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_i64(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_f32<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
Err(
|
||||
Error::new_from_kind(ErrorKind::NotSupported("bencode doesn't support floats"))
|
||||
.set_context(self),
|
||||
)
|
||||
}
|
||||
|
||||
fn deserialize_f64<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
Err(
|
||||
Error::new_from_kind(ErrorKind::NotSupported("bencode doesn't support floats"))
|
||||
.set_context(self),
|
||||
)
|
||||
}
|
||||
|
||||
fn deserialize_char<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
Err(
|
||||
Error::new_from_kind(ErrorKind::NotSupported("bencode doesn't support chars"))
|
||||
.set_context(self),
|
||||
)
|
||||
}
|
||||
|
||||
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
let first = match self.buf.first().copied() {
|
||||
Some(first) => first,
|
||||
None => {
|
||||
return Err(Error::custom_with_de(
|
||||
"expected bencode string, got EOF",
|
||||
self,
|
||||
))
|
||||
}
|
||||
};
|
||||
match first {
|
||||
b'0'..=b'9' => {}
|
||||
_ => return Err(Error::custom_with_de("expected bencode string", self)),
|
||||
}
|
||||
let b = self.parse_bytes()?;
|
||||
let s = std::str::from_utf8(b).map_err(|e| {
|
||||
Error::new_from_anyhow(anyhow::anyhow!("error reading utf-8: {}", e)).set_context(self)
|
||||
})?;
|
||||
visitor
|
||||
.visit_borrowed_str(s)
|
||||
.map_err(|e: Self::Error| e.set_context(self))
|
||||
}
|
||||
|
||||
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_str(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
let b = self.parse_bytes_checked()?;
|
||||
visitor
|
||||
.visit_borrowed_bytes(b)
|
||||
.map_err(|e: Self::Error| e.set_context(self))
|
||||
}
|
||||
|
||||
fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_bytes(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
visitor
|
||||
.visit_some(&mut *self)
|
||||
.map_err(|e: Self::Error| e.set_context(self))
|
||||
}
|
||||
|
||||
fn deserialize_unit<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
Err(Error::new_from_kind(ErrorKind::NotSupported(
|
||||
"bencode doesn't support unit types",
|
||||
))
|
||||
.set_context(self))
|
||||
}
|
||||
|
||||
fn deserialize_unit_struct<V>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
Err(Error::new_from_kind(ErrorKind::NotSupported(
|
||||
"bencode doesn't support unit structs",
|
||||
))
|
||||
.set_context(self))
|
||||
}
|
||||
|
||||
fn deserialize_newtype_struct<V>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
Err(
|
||||
Error::new_from_kind(ErrorKind::NotSupported("bencode doesn't newtype structs"))
|
||||
.set_context(self),
|
||||
)
|
||||
}
|
||||
|
||||
fn deserialize_seq<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
if !self.buf.starts_with(b"l") {
|
||||
return Err(Error::custom(format!(
|
||||
"expected bencode list, but got {}",
|
||||
self.buf[0] as char,
|
||||
)));
|
||||
}
|
||||
self.buf = self.buf.get(1..).unwrap_or_default();
|
||||
visitor
|
||||
.visit_seq(SeqAccess { de: &mut self })
|
||||
.map_err(|e: Self::Error| e.set_context(self))
|
||||
}
|
||||
|
||||
fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_seq(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_tuple_struct<V>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_len: usize,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_seq(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_map<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
if !self.buf.starts_with(b"d") {
|
||||
return Err(Error::custom("expected bencode dict"));
|
||||
}
|
||||
self.buf = self.buf.get(1..).unwrap_or_default();
|
||||
visitor
|
||||
.visit_map(MapAccess { de: &mut self })
|
||||
.map_err(|e: Self::Error| e.set_context(self))
|
||||
}
|
||||
|
||||
fn deserialize_struct<V>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_fields: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_map(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_enum<V>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variants: &'static [&'static str],
|
||||
_visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
Err(
|
||||
Error::new_from_kind(ErrorKind::NotSupported("deserializing enums not supported"))
|
||||
.set_context(self),
|
||||
)
|
||||
}
|
||||
|
||||
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
let name = self.parse_bytes_checked()?;
|
||||
visitor
|
||||
.visit_borrowed_bytes(name)
|
||||
.map_err(|e: Self::Error| e.set_context(self))
|
||||
}
|
||||
|
||||
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_any(visitor)
|
||||
}
|
||||
}
|
||||
|
||||
struct MapAccess<'a, 'de> {
|
||||
de: &'a mut BencodeDeserializer<'de>,
|
||||
}
|
||||
|
||||
struct SeqAccess<'a, 'de> {
|
||||
de: &'a mut BencodeDeserializer<'de>,
|
||||
}
|
||||
|
||||
impl<'a, 'de> serde::de::MapAccess<'de> for MapAccess<'a, 'de> {
|
||||
type Error = Error;
|
||||
|
||||
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
|
||||
where
|
||||
K: serde::de::DeserializeSeed<'de>,
|
||||
{
|
||||
if self.de.buf.starts_with(b"e") {
|
||||
self.de.buf = self.de.buf.get(1..).unwrap_or_default();
|
||||
return Ok(None);
|
||||
}
|
||||
self.de.parsing_key = true;
|
||||
let retval = seed.deserialize(&mut *self.de)?;
|
||||
self.de.parsing_key = false;
|
||||
Ok(Some(retval))
|
||||
}
|
||||
|
||||
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::DeserializeSeed<'de>,
|
||||
{
|
||||
let buf_before = self.de.buf;
|
||||
let value = seed.deserialize(&mut *self.de)?;
|
||||
if self.de.is_torrent_info && self.de.field_context.as_slice() == [ByteBuf(b"info")] {
|
||||
let len = self.de.buf.as_ptr() as usize - buf_before.as_ptr() as usize;
|
||||
let mut hash = Sha1::new();
|
||||
hash.update(&buf_before[..len]);
|
||||
let digest = hash.finish();
|
||||
self.de.torrent_info_digest = Some(digest)
|
||||
}
|
||||
self.de.field_context.pop();
|
||||
Ok(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'de> serde::de::SeqAccess<'de> for SeqAccess<'a, 'de> {
|
||||
type Error = Error;
|
||||
|
||||
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
|
||||
where
|
||||
T: serde::de::DeserializeSeed<'de>,
|
||||
{
|
||||
if self.de.buf.starts_with(b"e") {
|
||||
self.de.buf = self.de.buf.get(1..).unwrap_or_default();
|
||||
return Ok(None);
|
||||
}
|
||||
Ok(Some(seed.deserialize(&mut *self.de)?))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,491 +0,0 @@
|
|||
use std::collections::BTreeMap;
|
||||
|
||||
use serde::{Serialize, Serializer};
|
||||
|
||||
use crate::buffers::ByteString;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SerErrorKind {
|
||||
Other(anyhow::Error),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for SerErrorKind {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
SerErrorKind::Other(e) => write!(f, "{}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SerError {
|
||||
kind: SerErrorKind,
|
||||
}
|
||||
|
||||
impl SerError {
|
||||
fn custom_with_ser<T: std::fmt::Display, W: std::io::Write>(
|
||||
msg: T,
|
||||
_ser: &BencodeSerializer<W>,
|
||||
) -> Self {
|
||||
serde::ser::Error::custom(msg)
|
||||
}
|
||||
fn from_err_with_ser<E: std::error::Error + Send + Sync + 'static, W: std::io::Write>(
|
||||
err: E,
|
||||
_ser: &BencodeSerializer<W>,
|
||||
) -> Self {
|
||||
Self {
|
||||
kind: SerErrorKind::Other(err.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::ser::Error for SerError {
|
||||
fn custom<T>(msg: T) -> Self
|
||||
where
|
||||
T: std::fmt::Display,
|
||||
{
|
||||
Self {
|
||||
kind: SerErrorKind::Other(anyhow::anyhow!("{}", msg)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for SerError {}
|
||||
|
||||
impl std::fmt::Display for SerError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.kind)
|
||||
}
|
||||
}
|
||||
|
||||
struct BencodeSerializer<W: std::io::Write> {
|
||||
writer: W,
|
||||
hack_no_bytestring_prefix: bool,
|
||||
}
|
||||
|
||||
impl<W: std::io::Write> BencodeSerializer<W> {
|
||||
pub fn new(writer: W) -> Self {
|
||||
Self {
|
||||
writer,
|
||||
hack_no_bytestring_prefix: false,
|
||||
}
|
||||
}
|
||||
fn write_raw(&mut self, buf: &[u8]) -> Result<(), SerError> {
|
||||
self.writer
|
||||
.write_all(buf)
|
||||
.map_err(|e| SerError::from_err_with_ser(e, &self))
|
||||
}
|
||||
fn write_fmt(&mut self, fmt: core::fmt::Arguments<'_>) -> Result<(), SerError> {
|
||||
self.writer
|
||||
.write_fmt(fmt)
|
||||
.map_err(|e| SerError::from_err_with_ser(e, &self))
|
||||
}
|
||||
fn write_byte(&mut self, byte: u8) -> Result<(), SerError> {
|
||||
self.write_raw(&[byte])
|
||||
}
|
||||
fn write_number<N: std::fmt::Display>(&mut self, number: N) -> Result<(), SerError> {
|
||||
self.write_fmt(format_args!("i{}e", number))
|
||||
}
|
||||
fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), SerError> {
|
||||
if !self.hack_no_bytestring_prefix {
|
||||
self.write_fmt(format_args!("{}:", bytes.len()))?;
|
||||
}
|
||||
self.write_raw(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
struct SerializeSeq<'ser, W: std::io::Write> {
|
||||
ser: &'ser mut BencodeSerializer<W>,
|
||||
}
|
||||
impl<'ser, W: std::io::Write> serde::ser::SerializeSeq for SerializeSeq<'ser, W> {
|
||||
type Ok = ();
|
||||
|
||||
type Error = SerError;
|
||||
|
||||
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: serde::Serialize,
|
||||
{
|
||||
value.serialize(&mut *self.ser)
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Self::Ok, Self::Error> {
|
||||
self.ser.write_byte(b'e')
|
||||
}
|
||||
}
|
||||
|
||||
struct SerializeTuple<'ser, W: std::io::Write> {
|
||||
ser: &'ser mut BencodeSerializer<W>,
|
||||
}
|
||||
impl<'ser, W: std::io::Write> serde::ser::SerializeTuple for SerializeTuple<'ser, W> {
|
||||
type Ok = ();
|
||||
|
||||
type Error = SerError;
|
||||
|
||||
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: serde::Serialize,
|
||||
{
|
||||
value.serialize(&mut *self.ser)
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Self::Ok, Self::Error> {
|
||||
self.ser.write_byte(b'e')
|
||||
}
|
||||
}
|
||||
|
||||
struct SerializeTupleStruct<'ser, W: std::io::Write> {
|
||||
_ser: &'ser mut BencodeSerializer<W>,
|
||||
}
|
||||
impl<'ser, W: std::io::Write> serde::ser::SerializeTupleStruct for SerializeTupleStruct<'ser, W> {
|
||||
type Ok = ();
|
||||
|
||||
type Error = SerError;
|
||||
|
||||
fn serialize_field<T: ?Sized>(&mut self, _value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: serde::Serialize,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Self::Ok, Self::Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
struct SerializeTupleVariant<'ser, W: std::io::Write> {
|
||||
_ser: &'ser mut BencodeSerializer<W>,
|
||||
}
|
||||
impl<'ser, W: std::io::Write> serde::ser::SerializeTupleVariant for SerializeTupleVariant<'ser, W> {
|
||||
type Ok = ();
|
||||
|
||||
type Error = SerError;
|
||||
|
||||
fn serialize_field<T: ?Sized>(&mut self, _value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: serde::Serialize,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Self::Ok, Self::Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
struct SerializeMap<'ser, W: std::io::Write> {
|
||||
ser: &'ser mut BencodeSerializer<W>,
|
||||
tmp: BTreeMap<ByteString, ByteString>,
|
||||
last_key: Option<ByteString>,
|
||||
}
|
||||
impl<'ser, W: std::io::Write> serde::ser::SerializeMap for SerializeMap<'ser, W> {
|
||||
type Ok = ();
|
||||
|
||||
type Error = SerError;
|
||||
|
||||
fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: serde::Serialize,
|
||||
{
|
||||
let mut buf = Vec::new();
|
||||
let mut ser = BencodeSerializer::new(&mut buf);
|
||||
ser.hack_no_bytestring_prefix = true;
|
||||
key.serialize(&mut ser)?;
|
||||
self.last_key.replace(ByteString::from(buf));
|
||||
Ok(())
|
||||
// key.serialize(&mut *self.ser);
|
||||
}
|
||||
|
||||
fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: serde::Serialize,
|
||||
{
|
||||
let mut buf = Vec::new();
|
||||
let mut ser = BencodeSerializer::new(&mut buf);
|
||||
value.serialize(&mut ser)?;
|
||||
self.tmp
|
||||
.insert(self.last_key.take().unwrap(), ByteString::from(buf));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Self::Ok, Self::Error> {
|
||||
for (key, value) in self.tmp {
|
||||
self.ser.write_bytes(&key)?;
|
||||
self.ser.write_raw(&value)?;
|
||||
}
|
||||
self.ser.write_byte(b'e')
|
||||
}
|
||||
}
|
||||
|
||||
struct SerializeStruct<'ser, W: std::io::Write> {
|
||||
ser: &'ser mut BencodeSerializer<W>,
|
||||
tmp: BTreeMap<&'static str, ByteString>,
|
||||
}
|
||||
impl<'ser, W: std::io::Write> serde::ser::SerializeStruct for SerializeStruct<'ser, W> {
|
||||
type Ok = ();
|
||||
|
||||
type Error = SerError;
|
||||
|
||||
fn serialize_field<T: ?Sized>(
|
||||
&mut self,
|
||||
key: &'static str,
|
||||
value: &T,
|
||||
) -> Result<(), Self::Error>
|
||||
where
|
||||
T: serde::Serialize,
|
||||
{
|
||||
let mut buf = Vec::new();
|
||||
let mut ser = BencodeSerializer::new(&mut buf);
|
||||
value.serialize(&mut ser)?;
|
||||
self.tmp.insert(key, ByteString::from(buf));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Self::Ok, Self::Error> {
|
||||
for (key, value) in self.tmp {
|
||||
self.ser.write_bytes(key.as_bytes())?;
|
||||
self.ser.write_raw(&value)?;
|
||||
}
|
||||
self.ser.write_byte(b'e')
|
||||
}
|
||||
}
|
||||
|
||||
struct SerializeStructVariant<'ser, W: std::io::Write> {
|
||||
_ser: &'ser mut BencodeSerializer<W>,
|
||||
}
|
||||
impl<'ser, W: std::io::Write> serde::ser::SerializeStructVariant
|
||||
for SerializeStructVariant<'ser, W>
|
||||
{
|
||||
type Ok = ();
|
||||
|
||||
type Error = SerError;
|
||||
|
||||
fn serialize_field<T: ?Sized>(
|
||||
&mut self,
|
||||
_key: &'static str,
|
||||
_value: &T,
|
||||
) -> Result<(), Self::Error>
|
||||
where
|
||||
T: serde::Serialize,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Self::Ok, Self::Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ser, W: std::io::Write> Serializer for &'ser mut BencodeSerializer<W> {
|
||||
type Ok = ();
|
||||
|
||||
type Error = SerError;
|
||||
|
||||
type SerializeSeq = SerializeSeq<'ser, W>;
|
||||
|
||||
type SerializeTuple = SerializeTuple<'ser, W>;
|
||||
|
||||
type SerializeTupleStruct = SerializeTupleStruct<'ser, W>;
|
||||
|
||||
type SerializeTupleVariant = SerializeTupleVariant<'ser, W>;
|
||||
|
||||
type SerializeMap = SerializeMap<'ser, W>;
|
||||
|
||||
type SerializeStruct = SerializeStruct<'ser, W>;
|
||||
|
||||
type SerializeStructVariant = SerializeStructVariant<'ser, W>;
|
||||
|
||||
fn serialize_bool(self, _: bool) -> Result<Self::Ok, Self::Error> {
|
||||
Err(SerError::custom_with_ser(
|
||||
"bencode doesn't support booleans",
|
||||
&self,
|
||||
))
|
||||
}
|
||||
|
||||
fn serialize_i8(self, v: i8) -> Result<Self::Ok, Self::Error> {
|
||||
self.write_number(v)
|
||||
}
|
||||
|
||||
fn serialize_i16(self, v: i16) -> Result<Self::Ok, Self::Error> {
|
||||
self.write_number(v)
|
||||
}
|
||||
|
||||
fn serialize_i32(self, v: i32) -> Result<Self::Ok, Self::Error> {
|
||||
self.write_number(v)
|
||||
}
|
||||
|
||||
fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error> {
|
||||
self.write_number(v)
|
||||
}
|
||||
|
||||
fn serialize_u8(self, v: u8) -> Result<Self::Ok, Self::Error> {
|
||||
self.write_number(v)
|
||||
}
|
||||
|
||||
fn serialize_u16(self, v: u16) -> Result<Self::Ok, Self::Error> {
|
||||
self.write_number(v)
|
||||
}
|
||||
|
||||
fn serialize_u32(self, v: u32) -> Result<Self::Ok, Self::Error> {
|
||||
self.write_number(v)
|
||||
}
|
||||
|
||||
fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error> {
|
||||
self.write_number(v)
|
||||
}
|
||||
|
||||
fn serialize_f32(self, _: f32) -> Result<Self::Ok, Self::Error> {
|
||||
Err(SerError::custom_with_ser(
|
||||
"bencode doesn't support f32",
|
||||
&self,
|
||||
))
|
||||
}
|
||||
|
||||
fn serialize_f64(self, _: f64) -> Result<Self::Ok, Self::Error> {
|
||||
Err(SerError::custom_with_ser(
|
||||
"bencode doesn't support f32",
|
||||
&self,
|
||||
))
|
||||
}
|
||||
|
||||
fn serialize_char(self, _: char) -> Result<Self::Ok, Self::Error> {
|
||||
Err(SerError::custom_with_ser(
|
||||
"bencode doesn't support chars",
|
||||
&self,
|
||||
))
|
||||
}
|
||||
|
||||
fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error> {
|
||||
self.write_bytes(v.as_bytes())
|
||||
}
|
||||
|
||||
fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok, Self::Error> {
|
||||
self.write_bytes(v)
|
||||
}
|
||||
|
||||
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
|
||||
Err(SerError::custom_with_ser(
|
||||
"bencode doesn't support None",
|
||||
&self,
|
||||
))
|
||||
}
|
||||
|
||||
fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: serde::Serialize,
|
||||
{
|
||||
value.serialize(self)
|
||||
}
|
||||
|
||||
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
|
||||
Err(SerError::custom_with_ser(
|
||||
"bencode doesn't support Rust unit ()",
|
||||
&self,
|
||||
))
|
||||
}
|
||||
|
||||
fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn serialize_unit_variant(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
_variant: &'static str,
|
||||
) -> Result<Self::Ok, Self::Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn serialize_newtype_struct<T: ?Sized>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_value: &T,
|
||||
) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: serde::Serialize,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn serialize_newtype_variant<T: ?Sized>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
_variant: &'static str,
|
||||
_value: &T,
|
||||
) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: serde::Serialize,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
|
||||
self.write_byte(b'l')?;
|
||||
Ok(SerializeSeq { ser: self })
|
||||
}
|
||||
|
||||
fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn serialize_tuple_struct(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeTupleStruct, Self::Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn serialize_tuple_variant(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
_variant: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeTupleVariant, Self::Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
|
||||
self.write_byte(b'd')?;
|
||||
Ok(SerializeMap {
|
||||
ser: self,
|
||||
tmp: Default::default(),
|
||||
last_key: None,
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize_struct(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeStruct, Self::Error> {
|
||||
self.write_byte(b'd')?;
|
||||
Ok(SerializeStruct {
|
||||
ser: self,
|
||||
tmp: Default::default(),
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize_struct_variant(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
_variant: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeStructVariant, Self::Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bencode_serialize_to_writer<T: Serialize, W: std::io::Write>(
|
||||
value: T,
|
||||
writer: &mut W,
|
||||
) -> Result<(), SerError> {
|
||||
let mut serializer = BencodeSerializer::new(writer);
|
||||
value.serialize(&mut serializer)?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
// Wrapper for sha1 libraries.
|
||||
// Sha1 computation is the majority of CPU usage of this library.
|
||||
// openssl seems 2-3x faster, so using it for now, but
|
||||
// leaving the pure-rust impl here too. Maybe someday make them
|
||||
// runtime swappable or enabled with a feature.
|
||||
|
||||
pub trait ISha1 {
|
||||
fn new() -> Self;
|
||||
fn update(&mut self, buf: &[u8]);
|
||||
fn finish(self) -> [u8; 20];
|
||||
}
|
||||
|
||||
#[cfg(feature = "sha1-rust")]
|
||||
pub struct Sha1Rust {
|
||||
inner: sha1::Sha1,
|
||||
}
|
||||
|
||||
#[cfg(feature = "sha1-rust")]
|
||||
impl ISha1 for Sha1Rust {
|
||||
fn new() -> Self {
|
||||
Sha1Rust {
|
||||
inner: sha1::Sha1::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, buf: &[u8]) {
|
||||
self.inner.update(buf)
|
||||
}
|
||||
|
||||
fn finish(self) -> [u8; 20] {
|
||||
self.inner.digest().bytes()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "sha1-openssl")]
|
||||
pub struct Sha1Openssl {
|
||||
inner: openssl::sha::Sha1,
|
||||
}
|
||||
|
||||
#[cfg(feature = "sha1-openssl")]
|
||||
impl ISha1 for Sha1Openssl {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
inner: openssl::sha::Sha1::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, buf: &[u8]) {
|
||||
self.inner.update(buf)
|
||||
}
|
||||
|
||||
fn finish(self) -> [u8; 20] {
|
||||
self.inner.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "sha1-system")]
|
||||
pub struct Sha1System {
|
||||
inner: crypto_hash::Hasher,
|
||||
}
|
||||
|
||||
#[cfg(feature = "sha1-system")]
|
||||
impl ISha1 for Sha1System {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
inner: crypto_hash::Hasher::new(crypto_hash::Algorithm::SHA1),
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, buf: &[u8]) {
|
||||
use std::io::Write;
|
||||
self.inner.write_all(buf).unwrap();
|
||||
}
|
||||
|
||||
fn finish(mut self) -> [u8; 20] {
|
||||
let result = self.inner.finish();
|
||||
assert_eq!(result.len(), 20);
|
||||
let mut result_arr = [0u8; 20];
|
||||
result_arr.copy_from_slice(&result);
|
||||
result_arr
|
||||
}
|
||||
}
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
use std::{
|
||||
collections::VecDeque,
|
||||
sync::atomic::{AtomicU64, Ordering},
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use parking_lot::Mutex;
|
||||
|
||||
struct ProgressSnapshot {
|
||||
downloaded_bytes: u64,
|
||||
instant: Instant,
|
||||
}
|
||||
|
||||
pub struct SpeedEstimator {
|
||||
latest_per_second_snapshots: Mutex<VecDeque<ProgressSnapshot>>,
|
||||
download_bytes_per_second: AtomicU64,
|
||||
time_remaining_millis: AtomicU64,
|
||||
}
|
||||
|
||||
impl SpeedEstimator {
|
||||
pub fn new(window_seconds: usize) -> Self {
|
||||
assert!(window_seconds > 1);
|
||||
Self {
|
||||
latest_per_second_snapshots: Mutex::new(VecDeque::with_capacity(window_seconds)),
|
||||
download_bytes_per_second: Default::default(),
|
||||
time_remaining_millis: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn time_remaining(&self) -> Option<Duration> {
|
||||
let tr = self.time_remaining_millis.load(Ordering::Relaxed);
|
||||
if tr == 0 {
|
||||
return None;
|
||||
}
|
||||
Some(Duration::from_millis(tr))
|
||||
}
|
||||
|
||||
pub fn download_bps(&self) -> u64 {
|
||||
self.download_bytes_per_second.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
pub fn download_mbps(&self) -> f64 {
|
||||
self.download_bps() as f64 / 1024f64 / 1024f64
|
||||
}
|
||||
|
||||
pub fn add_snapshot(&self, downloaded_bytes: u64, remaining_bytes: u64, instant: Instant) {
|
||||
let mut g = self.latest_per_second_snapshots.lock();
|
||||
if g.len() < g.capacity() {
|
||||
g.push_back(ProgressSnapshot {
|
||||
downloaded_bytes,
|
||||
instant,
|
||||
});
|
||||
return;
|
||||
}
|
||||
let first = g.pop_front().unwrap();
|
||||
|
||||
let downloaded_bytes_diff = downloaded_bytes - first.downloaded_bytes;
|
||||
let elapsed = instant - first.instant;
|
||||
let bps = downloaded_bytes_diff as f64 / elapsed.as_secs_f64();
|
||||
|
||||
let time_remaining_millis_rounded: u64 = if downloaded_bytes_diff > 0 {
|
||||
let time_remaining_secs = remaining_bytes as f64 / bps;
|
||||
(time_remaining_secs * 1000f64) as u64
|
||||
} else {
|
||||
0
|
||||
};
|
||||
self.time_remaining_millis
|
||||
.store(time_remaining_millis_rounded, Ordering::Relaxed);
|
||||
self.download_bytes_per_second
|
||||
.store(bps as u64, Ordering::Relaxed);
|
||||
|
||||
g.push_back(ProgressSnapshot {
|
||||
downloaded_bytes,
|
||||
instant,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -12,24 +12,25 @@ use std::{
|
|||
};
|
||||
|
||||
use anyhow::Context;
|
||||
use bencode::from_bytes;
|
||||
use buffers::ByteString;
|
||||
use librqbit_core::{
|
||||
lengths::Lengths, peer_id::generate_peer_id, speed_estimator::SpeedEstimator,
|
||||
torrent_metainfo::TorrentMetaV1Info,
|
||||
};
|
||||
use log::{debug, info};
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use reqwest::Url;
|
||||
use sha1w::Sha1;
|
||||
use size_format::SizeFormatterBinary as SF;
|
||||
|
||||
use crate::{
|
||||
buffers::ByteString,
|
||||
chunk_tracker::ChunkTracker,
|
||||
file_ops::FileOps,
|
||||
http_api::make_and_run_http_api,
|
||||
lengths::Lengths,
|
||||
peer_id::generate_peer_id,
|
||||
spawn_utils::{spawn, BlockingSpawner},
|
||||
speed_estimator::SpeedEstimator,
|
||||
torrent_metainfo::TorrentMetaV1Info,
|
||||
torrent_state::{AtomicStats, TorrentState, TorrentStateLocked},
|
||||
tracker_comms::{TrackerError, TrackerRequest, TrackerRequestEvent, TrackerResponse},
|
||||
type_aliases::Sha1,
|
||||
};
|
||||
pub struct TorrentManagerBuilder {
|
||||
info: TorrentMetaV1Info<ByteString>,
|
||||
|
|
@ -307,13 +308,13 @@ impl TorrentManager {
|
|||
anyhow::bail!("tracker responded with {:?}", response.status());
|
||||
}
|
||||
let bytes = response.bytes().await?;
|
||||
if let Ok(error) = crate::serde_bencode_de::from_bytes::<TrackerError>(&bytes) {
|
||||
if let Ok(error) = from_bytes::<TrackerError>(&bytes) {
|
||||
anyhow::bail!(
|
||||
"tracker returned failure. Failure reason: {}",
|
||||
error.failure_reason
|
||||
)
|
||||
};
|
||||
let response = crate::serde_bencode_de::from_bytes::<TrackerResponse>(&bytes)?;
|
||||
let response = from_bytes::<TrackerResponse>(&bytes)?;
|
||||
|
||||
for peer in response.peers.iter_sockaddrs() {
|
||||
self.state.add_peer_if_not_seen(peer);
|
||||
|
|
|
|||
|
|
@ -1,286 +0,0 @@
|
|||
use std::{fmt::Write, ops::Deref, path::PathBuf};
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{
|
||||
buffers::{ByteBuf, ByteString},
|
||||
clone_to_owned::CloneToOwned,
|
||||
serde_bencode_de::BencodeDeserializer,
|
||||
};
|
||||
|
||||
pub type TorrentMetaV1Borrowed<'a> = TorrentMetaV1<ByteBuf<'a>>;
|
||||
pub type TorrentMetaV1Owned = TorrentMetaV1<ByteString>;
|
||||
|
||||
pub fn torrent_from_bytes<'de, ByteBuf: Clone + Deserialize<'de>>(
|
||||
buf: &'de [u8],
|
||||
) -> anyhow::Result<TorrentMetaV1<ByteBuf>> {
|
||||
let mut de = BencodeDeserializer::new_from_buf(buf);
|
||||
de.is_torrent_info = true;
|
||||
let mut t = TorrentMetaV1::deserialize(&mut de)?;
|
||||
t.info_hash = de.torrent_info_digest.unwrap();
|
||||
Ok(t)
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
pub struct TorrentMetaV1<BufType: Clone> {
|
||||
pub announce: BufType,
|
||||
#[serde(rename = "announce-list")]
|
||||
pub announce_list: Vec<Vec<BufType>>,
|
||||
pub info: TorrentMetaV1Info<BufType>,
|
||||
pub comment: Option<BufType>,
|
||||
#[serde(rename = "created by")]
|
||||
pub created_by: Option<BufType>,
|
||||
pub encoding: Option<BufType>,
|
||||
pub publisher: Option<BufType>,
|
||||
#[serde(rename = "publisher-url")]
|
||||
pub publisher_url: Option<BufType>,
|
||||
#[serde(rename = "creation date")]
|
||||
pub creation_date: Option<usize>,
|
||||
|
||||
#[serde(skip)]
|
||||
pub info_hash: [u8; 20],
|
||||
}
|
||||
|
||||
impl<BufType: Clone> TorrentMetaV1<BufType> {
|
||||
pub fn iter_announce(&self) -> impl Iterator<Item = &BufType> {
|
||||
std::iter::once(&self.announce).chain(self.announce_list.iter().flatten())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
pub struct TorrentMetaV1Info<BufType: Clone> {
|
||||
pub name: Option<BufType>,
|
||||
pub pieces: BufType,
|
||||
#[serde(rename = "piece length")]
|
||||
pub piece_length: u32,
|
||||
|
||||
// Single-file mode
|
||||
pub length: Option<u64>,
|
||||
pub md5sum: Option<BufType>,
|
||||
|
||||
// Multi-file mode
|
||||
pub files: Option<Vec<TorrentMetaV1File<BufType>>>,
|
||||
}
|
||||
|
||||
pub enum FileIteratorName<'a, ByteBuf> {
|
||||
Single(Option<&'a ByteBuf>),
|
||||
Tree(&'a [ByteBuf]),
|
||||
}
|
||||
|
||||
impl<'a, ByteBuf> std::fmt::Debug for FileIteratorName<'a, ByteBuf>
|
||||
where
|
||||
ByteBuf: AsRef<[u8]>,
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
for (idx, item) in self.iter_components().enumerate() {
|
||||
if idx > 0 {
|
||||
f.write_char(std::path::MAIN_SEPARATOR)?;
|
||||
}
|
||||
match item {
|
||||
Some(bit) => {
|
||||
f.write_str(std::str::from_utf8(bit.as_ref()).unwrap_or("<INVALID UTF-8>"))?;
|
||||
}
|
||||
None => f.write_str("output")?,
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, ByteBuf> FileIteratorName<'a, ByteBuf> {
|
||||
pub fn to_pathbuf(&self) -> anyhow::Result<PathBuf>
|
||||
where
|
||||
ByteBuf: AsRef<[u8]>,
|
||||
{
|
||||
let mut buf = PathBuf::new();
|
||||
for part in self.iter_components() {
|
||||
if let Some(part) = part {
|
||||
buf.push(std::str::from_utf8(part.as_ref())?)
|
||||
} else {
|
||||
buf.push("output");
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(buf)
|
||||
}
|
||||
pub fn iter_components(&self) -> impl Iterator<Item = Option<&'a ByteBuf>> {
|
||||
let single_it = std::iter::once(match self {
|
||||
FileIteratorName::Single(n) => Some(*n),
|
||||
FileIteratorName::Tree(_) => None,
|
||||
});
|
||||
let multi_it = match self {
|
||||
FileIteratorName::Single(_) => &[],
|
||||
FileIteratorName::Tree(t) => *t,
|
||||
}
|
||||
.iter()
|
||||
.map(|p| Some(Some(p)));
|
||||
|
||||
single_it.chain(multi_it).flatten()
|
||||
}
|
||||
}
|
||||
|
||||
impl<BufType: Clone + Deref<Target = [u8]>> TorrentMetaV1Info<BufType> {
|
||||
pub fn get_hash(&self, piece: u32) -> Option<&[u8]> {
|
||||
let start = piece as usize * 20;
|
||||
let end = start + 20;
|
||||
let expected_hash = self.pieces.deref().get(start..end)?;
|
||||
Some(expected_hash)
|
||||
}
|
||||
pub fn compare_hash(&self, piece: u32, hash: [u8; 20]) -> Option<bool> {
|
||||
let start = piece as usize * 20;
|
||||
let end = start + 20;
|
||||
let expected_hash = self.pieces.deref().get(start..end)?;
|
||||
Some(expected_hash == hash)
|
||||
}
|
||||
pub fn iter_filenames_and_lengths(
|
||||
&self,
|
||||
) -> impl Iterator<Item = (FileIteratorName<'_, BufType>, u64)> {
|
||||
let single_it = std::iter::once(match (self.name.as_ref(), self.length) {
|
||||
(Some(n), Some(l)) => Some((FileIteratorName::Single(Some(n)), l)),
|
||||
_ => None,
|
||||
});
|
||||
let multi_it = self
|
||||
.files
|
||||
.as_deref()
|
||||
.unwrap_or_default()
|
||||
.iter()
|
||||
.map(|f| Some((FileIteratorName::Tree(&f.path), f.length)));
|
||||
single_it.chain(multi_it).flatten()
|
||||
}
|
||||
pub fn iter_file_lengths(&self) -> impl Iterator<Item = u64> + '_ {
|
||||
std::iter::once(self.length)
|
||||
.chain(
|
||||
self.files
|
||||
.as_deref()
|
||||
.unwrap_or_default()
|
||||
.iter()
|
||||
.map(|f| Some(f.length)),
|
||||
)
|
||||
.flatten()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
pub struct TorrentMetaV1File<BufType: Clone> {
|
||||
pub length: u64,
|
||||
pub path: Vec<BufType>,
|
||||
}
|
||||
|
||||
impl<BufType> TorrentMetaV1File<BufType>
|
||||
where
|
||||
BufType: Clone + AsRef<[u8]>,
|
||||
{
|
||||
pub fn full_path(&self, parent: &mut PathBuf) -> anyhow::Result<()> {
|
||||
for p in self.path.iter() {
|
||||
let bit = std::str::from_utf8(p.as_ref())?;
|
||||
parent.push(bit);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<ByteBuf> CloneToOwned for TorrentMetaV1File<ByteBuf>
|
||||
where
|
||||
ByteBuf: CloneToOwned + Clone,
|
||||
<ByteBuf as CloneToOwned>::Target: Clone,
|
||||
{
|
||||
type Target = TorrentMetaV1File<<ByteBuf as CloneToOwned>::Target>;
|
||||
|
||||
fn clone_to_owned(&self) -> Self::Target {
|
||||
TorrentMetaV1File {
|
||||
length: self.length,
|
||||
path: self.path.clone_to_owned(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<ByteBuf> CloneToOwned for TorrentMetaV1Info<ByteBuf>
|
||||
where
|
||||
ByteBuf: CloneToOwned + Clone,
|
||||
<ByteBuf as CloneToOwned>::Target: Clone,
|
||||
{
|
||||
type Target = TorrentMetaV1Info<<ByteBuf as CloneToOwned>::Target>;
|
||||
|
||||
fn clone_to_owned(&self) -> Self::Target {
|
||||
TorrentMetaV1Info {
|
||||
name: self.name.clone_to_owned(),
|
||||
pieces: self.pieces.clone_to_owned(),
|
||||
piece_length: self.piece_length,
|
||||
length: self.length,
|
||||
md5sum: self.md5sum.clone_to_owned(),
|
||||
files: self.files.clone_to_owned(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<ByteBuf> CloneToOwned for TorrentMetaV1<ByteBuf>
|
||||
where
|
||||
ByteBuf: CloneToOwned + Clone,
|
||||
<ByteBuf as CloneToOwned>::Target: Clone,
|
||||
{
|
||||
type Target = TorrentMetaV1<<ByteBuf as CloneToOwned>::Target>;
|
||||
|
||||
fn clone_to_owned(&self) -> Self::Target {
|
||||
TorrentMetaV1 {
|
||||
announce: self.announce.clone_to_owned(),
|
||||
announce_list: self.announce_list.clone_to_owned(),
|
||||
info: self.info.clone_to_owned(),
|
||||
comment: self.comment.clone_to_owned(),
|
||||
created_by: self.created_by.clone_to_owned(),
|
||||
encoding: self.encoding.clone_to_owned(),
|
||||
publisher: self.publisher.clone_to_owned(),
|
||||
publisher_url: self.publisher_url.clone_to_owned(),
|
||||
creation_date: self.creation_date,
|
||||
info_hash: self.info_hash,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::io::Read;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_deserialize_torrent_owned() {
|
||||
let mut buf = Vec::new();
|
||||
let filename = "resources/ubuntu-21.04-desktop-amd64.iso.torrent";
|
||||
std::fs::File::open(filename)
|
||||
.unwrap()
|
||||
.read_to_end(&mut buf)
|
||||
.unwrap();
|
||||
|
||||
let torrent: TorrentMetaV1Owned = torrent_from_bytes(&buf).unwrap();
|
||||
dbg!(torrent);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deserialize_torrent_borrowed() {
|
||||
let mut buf = Vec::new();
|
||||
let filename = "resources/ubuntu-21.04-desktop-amd64.iso.torrent";
|
||||
std::fs::File::open(filename)
|
||||
.unwrap()
|
||||
.read_to_end(&mut buf)
|
||||
.unwrap();
|
||||
|
||||
let torrent: TorrentMetaV1Borrowed = torrent_from_bytes(&buf).unwrap();
|
||||
dbg!(torrent);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deserialize_torrent_with_info_hash() {
|
||||
let mut buf = Vec::new();
|
||||
let filename = "resources/ubuntu-21.04-desktop-amd64.iso.torrent";
|
||||
std::fs::File::open(filename)
|
||||
.unwrap()
|
||||
.read_to_end(&mut buf)
|
||||
.unwrap();
|
||||
|
||||
let torrent: TorrentMetaV1Borrowed = torrent_from_bytes(&buf).unwrap();
|
||||
assert_eq!(
|
||||
torrent.info_hash,
|
||||
*b"\x64\xa9\x80\xab\xe6\xe4\x48\x22\x6b\xb9\x30\xba\x06\x15\x92\xe4\x4c\x37\x81\xa1"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -10,25 +10,28 @@ use std::{
|
|||
};
|
||||
|
||||
use anyhow::Context;
|
||||
use buffers::{ByteBuf, ByteString};
|
||||
use clone_to_owned::CloneToOwned;
|
||||
use futures::{stream::FuturesUnordered, StreamExt};
|
||||
use librqbit_core::{
|
||||
lengths::{ChunkInfo, Lengths, ValidPieceIndex},
|
||||
torrent_metainfo::TorrentMetaV1Info,
|
||||
};
|
||||
use log::{debug, info, trace, warn};
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use peer_binary_protocol::{
|
||||
extended::handshake::ExtendedHandshake, Handshake, Message, MessageOwned, Piece, Request,
|
||||
};
|
||||
use sha1w::Sha1;
|
||||
use tokio::{sync::mpsc::UnboundedSender, time::timeout};
|
||||
|
||||
use crate::{
|
||||
buffers::{ByteBuf, ByteString},
|
||||
chunk_tracker::{ChunkMarkingResult, ChunkTracker},
|
||||
clone_to_owned::CloneToOwned,
|
||||
file_ops::FileOps,
|
||||
lengths::{Lengths, ValidPieceIndex},
|
||||
peer_binary_protocol::{
|
||||
extended::handshake::ExtendedHandshake, Handshake, Message, MessageOwned, Piece, Request,
|
||||
},
|
||||
peer_connection::{PeerConnection, PeerConnectionHandler, WriterRequest},
|
||||
peer_state::{InflightRequest, LivePeerState, PeerState},
|
||||
spawn_utils::{spawn, BlockingSpawner},
|
||||
torrent_metainfo::TorrentMetaV1Info,
|
||||
type_aliases::{PeerHandle, Sha1, BF},
|
||||
type_aliases::{PeerHandle, BF},
|
||||
};
|
||||
|
||||
pub struct InflightPiece {
|
||||
|
|
@ -516,7 +519,7 @@ impl PeerConnectionHandler for PeerHandler {
|
|||
.fetch_add(bytes as u64, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
fn read_chunk(&self, chunk: &crate::lengths::ChunkInfo, buf: &mut [u8]) -> anyhow::Result<()> {
|
||||
fn read_chunk(&self, chunk: &ChunkInfo, buf: &mut [u8]) -> anyhow::Result<()> {
|
||||
self.state.file_ops().read_chunk(self.addr, chunk, buf)
|
||||
}
|
||||
|
||||
|
|
@ -764,7 +767,11 @@ impl PeerHandler {
|
|||
}
|
||||
|
||||
fn on_received_piece(&self, handle: PeerHandle, piece: Piece<ByteBuf>) -> anyhow::Result<()> {
|
||||
let chunk_info = match self.state.lengths.chunk_info_from_received_piece(&piece) {
|
||||
let chunk_info = match self.state.lengths.chunk_info_from_received_piece(
|
||||
piece.index,
|
||||
piece.begin,
|
||||
piece.block.len() as u32,
|
||||
) {
|
||||
Some(i) => i,
|
||||
None => {
|
||||
anyhow::bail!(
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use buffers::ByteBuf;
|
||||
use byteorder::ByteOrder;
|
||||
use serde::{Deserialize, Deserializer};
|
||||
use std::{
|
||||
|
|
@ -7,8 +8,6 @@ use std::{
|
|||
str::FromStr,
|
||||
};
|
||||
|
||||
use crate::buffers::ByteBuf;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum TrackerRequestEvent {
|
||||
Started,
|
||||
|
|
|
|||
|
|
@ -3,12 +3,3 @@ use std::net::SocketAddr;
|
|||
pub type BF = bitvec::vec::BitVec<bitvec::order::Msb0, u8>;
|
||||
|
||||
pub type PeerHandle = SocketAddr;
|
||||
|
||||
#[cfg(feature = "sha1-openssl")]
|
||||
pub type Sha1 = crate::sha1w::Sha1Openssl;
|
||||
|
||||
#[cfg(feature = "sha1-system")]
|
||||
pub type Sha1 = crate::sha1w::Sha1System;
|
||||
|
||||
#[cfg(feature = "sha1-rust")]
|
||||
pub type Sha1 = crate::sha1w::Sha1Rust;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue