summaryrefslogtreecommitdiffstats
path: root/rust/src/main.rs
blob: adb656ca783e8cd3818e0c71d0a84d32ad8da2f6 (plain) (blame)
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
extern crate hex;
extern crate urlencoding;
extern crate bencode;

use std::collections::HashMap;
use std::net::IpAddr;
use chrono::{DateTime, Utc, TimeZone};
use sha2::{Sha256, Digest};
use sha1::{Sha1};
use bencode::{Bencode, FromBencode};
use bencode::util::ByteString;
use std::str;
use std::net::SocketAddr;

enum Version {
	V1,
	V2,
	Hybrid
}
struct Torrent {
	name: String,
	sha1: [u8; 20],
	sha256: [u8; 32],
	version: Version,
	files: HashMap<String, u64>,
	source: Option<SocketAddr>,
	date: Option<DateTime<Utc>>,
	hostname: Option<String>,
	software: Option<String>
}
impl Default for Torrent {
	fn default() -> Torrent {
		Torrent {
			name: String::from("travnik_default_name_unset"),
			sha1: [0; 20],
			sha256: [0; 32],
			version: Version::V1,
			files: HashMap::new(),
			source: None,
			date: None,
			hostname: None,
			software: None
		}
	}
}
impl Torrent {
	fn magnet(&self) -> String {
		let mut string = String::from("magnet:?dn=");
		string.push_str(&urlencoding::encode(&self.name));
		if matches!(self.version, Version::V1) || matches!(self.version, Version::Hybrid) {
			string.push_str("&xt=urn:btih:");
			string.push_str(&hex::encode(&self.sha1));
		}
		if matches!(self.version, Version::V2) || matches!(self.version, Version::Hybrid) {
			string.push_str("&xt=urn:btmh:1220");
			string.push_str(&hex::encode(&self.sha256));
		}
		string
	}
}
fn sockaddr_from_source(string) -> Result<SockAddra> // TODO nadaljuj
#[derive(Debug)]
enum TorrentDecodeError {
	NotADict,
	NoName,
	NoLength,
	CreatedByNotUtf8,
	SoftwareNotUtf8
}
impl FromBencode for Torrent {
	type Err = TorrentDecodeError;
	fn from_bencode(bencode: &Bencode) -> Result<Torrent, TorrentDecodeError> {
		let metainfo = match bencode {
			&Bencode::Dict(ref metainfo) => metainfo,
			_ => return Err(TorrentDecodeError::NotADict)
		};
		let torrent = Torrent {
			date: match metainfo.get(&ByteString::from_str("creation date")) {
					Some(&Bencode::Number(c)) => Some(Utc.timestamp(c, 0)),
					_ => None
			},
			hostname: match metainfo.get(&ByteString::from_str("created by")) {
				Some(&Bencode::ByteString(ref s)) => match str::from_utf8(&s) {
					Ok(v) => Some(match v.split(" ").nth(3) {
						Some(c) => String::from(c),
						None => String::from("b")
					}),
					Err(_) => return Err(TorrentDecodeError::CreatedByNotUtf8)
				},
				_ => None
			},
			software: match metainfo.get(&ByteString::from_str("source")) {
				Some(&Bencode::Dict(ref s)) => match s.get(&ByteString::from_str("v")) {
					Some(&Bencode::ByteString(ref s)) => match String::from_utf8(s.to_vec()) {
						Ok(v) => Some(v),
						Err(_) => return Err(TorrentDecodeError::SoftwareNotUtf8)
					},
					_ => None
				},
				_ => None
			},
			source: match metainfo.get(&ByteString::from_str("source")) {
				Some(&Bencode::Dict(ref s)) => match s.get(&ByteString::from_str("ip")) {
					Some(&Bencode::ByteString(ref s)) => match str::from_utf8(&s) {
						Ok(v) => Some(sockaddr_from_source(v)?), // TODO nadaljuj
						Err(_) => return Err(Torrent)
					},
					_ => None
				},
				_ => None
			},
			..Default::default()
		};
		Ok(torrent)
	}
}
fn main() {
	// let hash2 = Sha256::new().chain_update(b"test").finalize();
	// let hash1 = Sha1::new().chain_update(b"test").finalize();
	// println!("Hello, world! {:#?} {:#?}", hash2, hash1);
	let bencode: bencode::Bencode = bencode::from_vec(String::from("d1:wlee").as_bytes().to_vec()).unwrap();
	println!("{:#?}", bencode);
}