arnaucube
arnaucube/torrent-rsPublic Self-hosted repository
torrent-rs/src/lib.rs
src/lib.rsRaw
  1use byteorder::{BigEndian, ByteOrder};
  2use rand::Rng;
  3use sha1::{Digest, Sha1};
  4
  5extern crate serde;
  6extern crate serde_bencode;
  7#[macro_use]
  8extern crate serde_derive;
  9extern crate serde_bytes;
 10
 11use serde_bencode::{de, ser};
 12use serde_bytes::ByteBuf;
 13
 14#[derive(Debug, Deserialize)]
 15struct Node(String, i64);
 16
 17#[derive(Debug, Serialize, Deserialize)]
 18struct File {
 19    path: Vec<String>,
 20    length: i64,
 21    #[serde(default)]
 22    md5sum: Option<String>,
 23}
 24
 25#[derive(Debug, Serialize, Deserialize)]
 26struct Info {
 27    name: String,
 28    pieces: ByteBuf,
 29    #[serde(rename = "piece length")]
 30    piece_length: i64,
 31    #[serde(default)]
 32    md5sum: Option<String>,
 33    #[serde(default)]
 34    length: Option<i64>,
 35    #[serde(default)]
 36    files: Option<Vec<File>>,
 37    #[serde(default)]
 38    private: Option<u8>,
 39    #[serde(default)]
 40    path: Option<Vec<String>>,
 41    #[serde(default)]
 42    #[serde(rename = "root hash")]
 43    root_hash: Option<String>,
 44}
 45
 46#[derive(Debug, Deserialize)]
 47struct Torrent {
 48    info: Info,
 49    #[serde(default)]
 50    announce: Option<String>,
 51    #[serde(default)]
 52    nodes: Option<Vec<Node>>,
 53    #[serde(default)]
 54    encoding: Option<String>,
 55    #[serde(default)]
 56    httpseeds: Option<Vec<String>>,
 57    #[serde(default)]
 58    #[serde(rename = "announce-list")]
 59    announce_list: Option<Vec<Vec<String>>>,
 60    #[serde(default)]
 61    #[serde(rename = "creation date")]
 62    creation_date: Option<i64>,
 63    #[serde(rename = "comment")]
 64    comment: Option<String>,
 65    #[serde(default)]
 66    #[serde(rename = "created by")]
 67    created_by: Option<String>,
 68}
 69
 70impl Torrent {
 71    pub fn open(path: &str) -> Torrent {
 72        let b = std::fs::read(path).unwrap();
 73        de::from_bytes::<Torrent>(&b).unwrap()
 74    }
 75    pub fn size(&self) -> u64 {
 76        let files = self.info.files.as_ref().unwrap();
 77        let mut size: u64 = 0;
 78        for i in 0..files.len() {
 79            size = size + files[i].length as u64;
 80        }
 81        size
 82    }
 83    pub fn info_hash(&self) -> Vec<u8> {
 84        let info_bytes: Vec<u8> = ser::to_bytes(&self.info).unwrap();
 85        let mut hasher = Sha1::new();
 86        hasher.update(info_bytes);
 87        let result = hasher.finalize();
 88        result.to_vec()
 89    }
 90}
 91
 92const CONNECT_MSG: u32 = 0;
 93const ANNOUNCE_MSG: u32 = 1;
 94
 95fn conn_req_msg() -> [u8; 16] {
 96    let mut b: [u8; 16] = [0; 16];
 97    BigEndian::write_u64(&mut b[0..8], 0x41727101980); // connection_id
 98    let random_bytes = rand::thread_rng().gen::<[u8; 4]>();
 99    b[12..16].clone_from_slice(&random_bytes[..]);
100    b
101}
102
103fn ann_req_msg(connection_id: u64, torrent: &Torrent, port: u16) -> Vec<u8> {
104    let mut b: [u8; 98] = [0; 98];
105    BigEndian::write_u64(&mut b[0..8], connection_id);
106    BigEndian::write_u32(&mut b[8..12], CONNECT_MSG); // action
107    let random_bytes = rand::thread_rng().gen::<[u8; 4]>();
108    b[12..16].clone_from_slice(&random_bytes[..]);
109    // println!("md5sum {:?}", torrent);
110    b[16..36].clone_from_slice(&torrent.info_hash()[..]);
111    println!("info_hash: {:?}", &b[16..36]);
112    // TODO [36..56] peerId b[36..56].clone_from_slice("todo".as_bytes());
113    // TODO [56..64] downloaded
114    println!("torrent.size(): {:?}", torrent.size());
115    BigEndian::write_u64(&mut b[64..72], torrent.size()); // [64..72] left
116                                                          // TODO [72..80] uploaded
117                                                          // TODO [80..84] event (0:none, 1:completed, 2:started, 3:stopped)
118                                                          // TODO [84..88] ip address
119    let random_bytes = rand::thread_rng().gen::<[u8; 4]>();
120    b[88..92].clone_from_slice(&random_bytes[..]); // [88..92] key (random)
121    BigEndian::write_i32(&mut b[92..96], -1); // [92..96] num_want (default: -1)
122    BigEndian::write_u16(&mut b[96..98], port); // [96..98] port
123    b.to_vec()
124}
125
126#[cfg(test)]
127mod tests {
128    use super::*;
129
130    #[test]
131    fn test_read() {
132        let t = Torrent::open("test.torrent");
133        println!("torrent: {:?}", t.info.name);
134        println!("announce: {:?}", t.announce.clone().unwrap());
135
136        println!("conn_req_msg: {:?}", conn_req_msg());
137    }
138}