You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
176 lines
4.4 KiB
Rust
176 lines
4.4 KiB
Rust
use crate::message::{Handshake, Message, PieceMessage, SelectionMessage};
|
|
use std::collections::{HashSet, VecDeque};
|
|
use std::net::SocketAddr;
|
|
use torment_core::infohash::v1::U160;
|
|
use torment_core::metainfo::MetaInfo;
|
|
use torment_core::Bitfield;
|
|
|
|
pub mod message;
|
|
|
|
#[derive(Copy, Clone, Debug)]
|
|
pub struct PeerState {
|
|
chocked: bool,
|
|
interested: bool,
|
|
}
|
|
|
|
impl PeerState {
|
|
const fn new() -> PeerState {
|
|
PeerState {
|
|
chocked: true,
|
|
interested: false,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Default for PeerState {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Copy, Clone)]
|
|
pub enum PeerProtocol {
|
|
TCP,
|
|
MuTP,
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct Peer {
|
|
id: U160,
|
|
info_hash: U160,
|
|
address: SocketAddr,
|
|
protocol: PeerProtocol,
|
|
our_state: PeerState,
|
|
their_state: PeerState,
|
|
has: Bitfield,
|
|
request_state: HashSet<SelectionMessage>,
|
|
request_queue: VecDeque<SelectionMessage>,
|
|
requested_queue: HashSet<SelectionMessage>,
|
|
received_pieces: VecDeque<PieceMessage>,
|
|
queue: VecDeque<Message>,
|
|
}
|
|
|
|
impl Peer {
|
|
pub fn id(&self) -> U160 {
|
|
self.id
|
|
}
|
|
|
|
pub fn new(
|
|
address: SocketAddr,
|
|
protocol: PeerProtocol,
|
|
header: Handshake,
|
|
meta_info: &MetaInfo,
|
|
) -> Self {
|
|
Peer {
|
|
id: header.peer_id(),
|
|
info_hash: header.info_hash(),
|
|
address,
|
|
protocol,
|
|
our_state: PeerState::new(),
|
|
their_state: PeerState::new(),
|
|
has: Bitfield::with_size(meta_info.pieces()),
|
|
request_state: Default::default(),
|
|
request_queue: Default::default(),
|
|
requested_queue: Default::default(),
|
|
received_pieces: Default::default(),
|
|
queue: Default::default(),
|
|
}
|
|
}
|
|
|
|
pub fn has(&mut self) -> Bitfield {
|
|
self.has.clone()
|
|
}
|
|
|
|
pub fn process(&mut self, message: Message) -> bool {
|
|
match message {
|
|
Message::Choke => self.their_state.chocked = true,
|
|
Message::Unchoke => self.their_state.chocked = false,
|
|
Message::Interested => self.their_state.interested = true,
|
|
Message::NotInterested => self.their_state.interested = false,
|
|
Message::Have(nr) => self.has.set(nr),
|
|
Message::Bitfield(bitfield) => self.has.add(bitfield),
|
|
Message::Request(selection) => {
|
|
self.request_queue.push_back(selection);
|
|
self.request_state.insert(selection);
|
|
}
|
|
Message::Cancel(selection) => {
|
|
self.request_state.remove(&selection);
|
|
}
|
|
Message::Piece(piece) => {
|
|
self.requested_queue.remove(&SelectionMessage::new(
|
|
piece.index(),
|
|
piece.offset(),
|
|
piece.length(),
|
|
));
|
|
self.received_pieces.push_back(piece);
|
|
}
|
|
}
|
|
|
|
true
|
|
}
|
|
|
|
pub fn count_open_requests(&self) -> usize {
|
|
self.requested_queue.len()
|
|
}
|
|
|
|
pub fn is_choked(&self) -> bool {
|
|
self.their_state.chocked
|
|
}
|
|
|
|
pub fn is_interested(&self) -> bool {
|
|
self.their_state.interested
|
|
}
|
|
|
|
pub fn we_interested(&self) -> bool {
|
|
self.our_state.interested
|
|
}
|
|
|
|
pub fn we_choked(&self) -> bool {
|
|
self.our_state.chocked
|
|
}
|
|
|
|
pub fn set_we_choked(&mut self, choked: bool) {
|
|
self.our_state.chocked = choked;
|
|
}
|
|
|
|
pub fn set_we_interested(&mut self, interested: bool) {
|
|
self.our_state.interested = interested;
|
|
}
|
|
|
|
pub fn requested(&mut self, selection: SelectionMessage) -> bool {
|
|
self.requested_queue.insert(selection)
|
|
}
|
|
|
|
pub fn next_piece(&mut self) -> Option<PieceMessage> {
|
|
self.received_pieces.pop_front()
|
|
}
|
|
|
|
pub fn next_request(&mut self) -> Option<SelectionMessage> {
|
|
while let Some(item) = self.request_queue.pop_front() {
|
|
if self.request_state.remove(&item) {
|
|
return Some(item);
|
|
}
|
|
}
|
|
None
|
|
}
|
|
|
|
pub fn addr(&self) -> SocketAddr {
|
|
self.address
|
|
}
|
|
pub fn has_piece(&self, index: u32) -> bool {
|
|
self.has.get(index as u32)
|
|
}
|
|
|
|
pub fn next(&mut self) -> Option<Message> {
|
|
self.queue.pop_front()
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
#[test]
|
|
fn it_works() {
|
|
assert_eq!(2 + 2, 4);
|
|
}
|
|
}
|