forked from torrust/torrust-tracker
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathresponse.rs
More file actions
133 lines (115 loc) · 3.75 KB
/
response.rs
File metadata and controls
133 lines (115 loc) · 3.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
use std::collections::HashMap;
use std::io::Write;
use std::net::IpAddr;
use serde;
use serde::Serialize;
use crate::protocol::info_hash::InfoHash;
#[derive(Serialize)]
pub struct Peer {
pub peer_id: String,
pub ip: IpAddr,
pub port: u16,
}
#[derive(Serialize)]
pub struct Announce {
pub interval: u32,
#[serde(rename = "min interval")]
pub interval_min: u32,
//pub tracker_id: String,
pub complete: u32,
pub incomplete: u32,
pub peers: Vec<Peer>,
}
impl Announce {
/// # Panics
///
/// It would panic if the `Announce` struct would contain an inappropriate type.
#[must_use]
pub fn write(&self) -> String {
serde_bencode::to_string(&self).unwrap()
}
/// # Errors
///
/// Will return `Err` if internally interrupted.
pub fn write_compact(&self) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
let mut peers_v4: Vec<u8> = Vec::new();
let mut peers_v6: Vec<u8> = Vec::new();
for peer in &self.peers {
match peer.ip {
IpAddr::V4(ip) => {
peers_v4.write_all(&u32::from(ip).to_be_bytes())?;
peers_v4.write_all(&peer.port.to_be_bytes())?;
}
IpAddr::V6(ip) => {
peers_v6.write_all(&u128::from(ip).to_be_bytes())?;
peers_v6.write_all(&peer.port.to_be_bytes())?;
}
}
}
let mut bytes: Vec<u8> = Vec::new();
bytes.write_all(b"d8:intervali")?;
bytes.write_all(self.interval.to_string().as_bytes())?;
bytes.write_all(b"e12:min intervali")?;
bytes.write_all(self.interval_min.to_string().as_bytes())?;
bytes.write_all(b"e8:completei")?;
bytes.write_all(self.complete.to_string().as_bytes())?;
bytes.write_all(b"e10:incompletei")?;
bytes.write_all(self.incomplete.to_string().as_bytes())?;
bytes.write_all(b"e5:peers")?;
bytes.write_all(peers_v4.len().to_string().as_bytes())?;
bytes.write_all(b":")?;
bytes.write_all(peers_v4.as_slice())?;
bytes.write_all(b"e6:peers6")?;
bytes.write_all(peers_v6.len().to_string().as_bytes())?;
bytes.write_all(b":")?;
bytes.write_all(peers_v6.as_slice())?;
bytes.write_all(b"e")?;
Ok(bytes)
}
}
#[derive(Serialize)]
pub struct ScrapeEntry {
pub complete: u32,
pub downloaded: u32,
pub incomplete: u32,
}
#[derive(Serialize)]
pub struct Scrape {
pub files: HashMap<InfoHash, ScrapeEntry>,
}
impl Scrape {
/// # Errors
///
/// Will return `Err` if internally interrupted.
pub fn write(&self) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
let mut bytes: Vec<u8> = Vec::new();
bytes.write_all(b"d5:filesd")?;
for (info_hash, scrape_response_entry) in &self.files {
bytes.write_all(b"20:")?;
bytes.write_all(&info_hash.0)?;
bytes.write_all(b"d8:completei")?;
bytes.write_all(scrape_response_entry.complete.to_string().as_bytes())?;
bytes.write_all(b"e10:downloadedi")?;
bytes.write_all(scrape_response_entry.downloaded.to_string().as_bytes())?;
bytes.write_all(b"e10:incompletei")?;
bytes.write_all(scrape_response_entry.incomplete.to_string().as_bytes())?;
bytes.write_all(b"ee")?;
}
bytes.write_all(b"ee")?;
Ok(bytes)
}
}
#[derive(Serialize)]
pub struct Error {
#[serde(rename = "failure reason")]
pub failure_reason: String,
}
impl Error {
/// # Panics
///
/// It would panic if the `Error` struct would contain an inappropriate type.
#[must_use]
pub fn write(&self) -> String {
serde_bencode::to_string(&self).unwrap()
}
}