1extern crate bincode;
2extern crate chrono;
3extern crate serde;
4#[macro_use]
5extern crate serde_derive;
6
7pub mod torrent {
8 pub use self::ver_fa1b6f as current;
9 pub use self::current::Session;
10 use bincode;
11
12 #[derive(Serialize, Deserialize, Clone)]
13 pub struct Bitfield {
14 pub len: u64,
15 pub data: Box<[u8]>,
16 }
17
18 pub fn load(data: &[u8]) -> Option<Session> {
19 if let Ok(m) = bincode::deserialize::<ver_fa1b6f::Session>(data) {
20 Some(m)
21 } else if let Ok(m) = bincode::deserialize::<ver_6e27af::Session>(data) {
22 Some(m.migrate())
23 } else if let Ok(m) = bincode::deserialize::<ver_249b1b::Session>(data) {
24 Some(m.migrate())
25 } else if let Ok(m) = bincode::deserialize::<ver_5f166d::Session>(data) {
26 Some(m.migrate())
27 } else if let Ok(m) = bincode::deserialize::<ver_8e1121::Session>(data) {
28 Some(m.migrate())
29 } else {
30 None
31 }
32 }
33
34 impl Session {
35 pub fn migrate(self) -> Self {
36 self
37 }
38 }
39
40 pub mod ver_fa1b6f {
41 use super::Bitfield;
42
43 use chrono::{DateTime, Utc};
44
45 use std::path::PathBuf;
46
47 #[derive(Serialize, Deserialize)]
48 pub struct Session {
49 pub info: Info,
50 pub pieces: Bitfield,
51 pub uploaded: u64,
52 pub downloaded: u64,
53 pub status: Status,
54 pub path: Option<String>,
55 pub priority: u8,
56 pub priorities: Vec<u8>,
57 pub created: DateTime<Utc>,
58 pub throttle_ul: Option<i64>,
59 pub throttle_dl: Option<i64>,
60 pub trackers: Vec<String>,
61 }
62
63 #[derive(Clone, Serialize, Deserialize)]
64 pub struct Info {
65 pub name: String,
66 pub announce: Option<String>,
67 pub creator: Option<String>,
68 pub comment: Option<String>,
69 pub piece_len: u32,
70 pub total_len: u64,
71 pub hashes: Vec<Vec<u8>>,
72 pub hash: [u8; 20],
73 pub files: Vec<File>,
74 pub private: bool,
75 pub be_name: Option<Vec<u8>>,
76 pub piece_idx: Vec<(usize, u64)>,
77 }
78
79 #[derive(Serialize, Deserialize, Clone, Debug)]
80 pub struct File {
81 pub path: PathBuf,
82 pub length: u64,
83 }
84
85 #[derive(Clone, Debug, Serialize, Deserialize)]
86 pub struct Status {
87 pub paused: bool,
88 pub validating: bool,
89 pub error: Option<String>,
90 pub state: StatusState,
91 }
92
93 #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
94 pub enum StatusState {
95 Magnet,
96 Incomplete,
98 Complete,
100 }
101 }
102
103 pub mod ver_6e27af {
104 pub use super::ver_fa1b6f as next;
105 pub use self::next::{File, Status, StatusState};
106
107 use super::Bitfield;
108
109 use chrono::{DateTime, Utc};
110
111 #[derive(Serialize, Deserialize)]
112 pub struct Session {
113 pub info: Info,
114 pub pieces: Bitfield,
115 pub uploaded: u64,
116 pub downloaded: u64,
117 pub status: Status,
118 pub path: Option<String>,
119 pub priority: u8,
120 pub priorities: Vec<u8>,
121 pub created: DateTime<Utc>,
122 pub throttle_ul: Option<i64>,
123 pub throttle_dl: Option<i64>,
124 pub trackers: Vec<String>,
125 }
126
127 #[derive(Clone, Serialize, Deserialize)]
128 pub struct Info {
129 pub name: String,
130 pub announce: Option<String>,
131 pub piece_len: u32,
132 pub total_len: u64,
133 pub hashes: Vec<Vec<u8>>,
134 pub hash: [u8; 20],
135 pub files: Vec<File>,
136 pub private: bool,
137 pub be_name: Option<Vec<u8>>,
138 pub piece_idx: Vec<(usize, u64)>,
139 }
140
141 impl Session {
142 pub fn migrate(self) -> super::current::Session {
143 next::Session {
144 info: next::Info {
145 comment: None,
146 creator: None,
147 name: self.info.name,
148 announce: self.info.announce,
149 piece_len: self.info.piece_len,
150 total_len: self.info.total_len,
151 hashes: self.info.hashes,
152 hash: self.info.hash,
153 files: self.info.files,
154 private: self.info.private,
155 be_name: self.info.be_name,
156 piece_idx: self.info.piece_idx,
157 },
158 pieces: self.pieces,
159 uploaded: self.uploaded,
160 downloaded: self.downloaded,
161 status: self.status,
162 path: self.path,
163 priority: self.priority,
164 priorities: self.priorities,
165 created: self.created,
166 throttle_ul: self.throttle_ul,
167 throttle_dl: self.throttle_dl,
168 trackers: self.trackers,
169 }.migrate()
170 }
171 }
172 }
173
174 pub mod ver_249b1b {
175 pub use super::ver_6e27af as next;
176 use super::Bitfield;
177 pub use self::next::{File, Info, Status, StatusState};
178
179 use chrono::{DateTime, Utc};
180
181 #[derive(Serialize, Deserialize)]
182 pub struct Session {
183 pub info: Info,
184 pub pieces: Bitfield,
185 pub uploaded: u64,
186 pub downloaded: u64,
187 pub status: Status,
188 pub path: Option<String>,
189 pub priority: u8,
190 pub priorities: Vec<u8>,
191 pub created: DateTime<Utc>,
192 pub throttle_ul: Option<i64>,
193 pub throttle_dl: Option<i64>,
194 }
195
196 impl Session {
197 pub fn migrate(self) -> super::current::Session {
198 let mut trackers = Vec::new();
199 if let Some(ref url) = self.info.announce {
200 trackers.push(url.to_owned());
201 }
202 next::Session {
203 info: self.info,
204 pieces: self.pieces,
205 uploaded: self.uploaded,
206 downloaded: self.downloaded,
207 status: self.status,
208 path: self.path,
209 priority: self.priority,
210 priorities: self.priorities,
211 created: self.created,
212 throttle_ul: self.throttle_ul,
213 throttle_dl: self.throttle_dl,
214 trackers,
215 }.migrate()
216 }
217 }
218 }
219
220 pub mod ver_5f166d {
221 use super::ver_249b1b as next;
222 use super::Bitfield;
223
224 use chrono::{DateTime, Utc};
225
226 #[derive(Serialize, Deserialize)]
227 pub struct Session {
228 pub info: Info,
229 pub pieces: Bitfield,
230 pub uploaded: u64,
231 pub downloaded: u64,
232 pub status: Status,
233 pub path: Option<String>,
234 pub priority: u8,
235 pub priorities: Vec<u8>,
236 pub created: DateTime<Utc>,
237 pub throttle_ul: Option<i64>,
238 pub throttle_dl: Option<i64>,
239 }
240
241 #[derive(Serialize, Deserialize)]
242 pub enum Status {
243 Pending,
244 Paused,
245 Leeching,
246 Idle,
247 Seeding,
248 Validating,
249 Magnet,
250 DiskError,
251 }
252
253 #[derive(Serialize, Deserialize)]
254 pub struct Info {
255 pub name: String,
256 pub announce: String,
257 pub piece_len: u32,
258 pub total_len: u64,
259 pub hashes: Vec<Vec<u8>>,
260 pub hash: [u8; 20],
261 pub files: Vec<next::File>,
262 pub private: bool,
263 pub be_name: Option<Vec<u8>>,
264 }
265
266 impl Session {
267 pub fn migrate(self) -> super::current::Session {
268 let mut state = next::StatusState::Complete;
269 for i in 0..self.pieces.len - 1 {
270 if !(self.pieces.data[i as usize]) != 0 {
271 state = next::StatusState::Incomplete;
272 break;
273 }
274 }
275 if self.pieces.data.len() > 0 {
276 match (self.pieces.len % 8, *self.pieces.data.last().unwrap()) {
277 (0, 0xFF)
278 | (7, 0xFE)
279 | (6, 0xFC)
280 | (5, 0xF8)
281 | (4, 0xF0)
282 | (3, 0xE0)
283 | (2, 0xC0)
284 | (1, 0x80) => {}
285 _ => state = next::StatusState::Incomplete,
286 }
287 }
288 let paused = match self.status {
289 Status::Paused => true,
290 _ => false,
291 };
292 let piece_idx = generate_piece_idx(
293 self.info.hashes.len(),
294 self.info.piece_len as u64,
295 &self.info.files,
296 );
297 next::Session {
298 info: next::Info {
299 name: self.info.name,
300 announce: if self.info.announce == "" {
301 None
302 } else {
303 Some(self.info.announce)
304 },
305 piece_len: self.info.piece_len,
306 total_len: self.info.total_len,
307 hashes: self.info.hashes,
308 hash: self.info.hash,
309 files: self.info.files,
310 private: self.info.private,
311 be_name: self.info.be_name,
312 piece_idx,
313 },
314 pieces: self.pieces,
315 uploaded: self.uploaded,
316 downloaded: self.downloaded,
317 status: next::Status {
318 paused,
319 state,
320 validating: false,
321 error: None,
322 },
323 path: self.path,
324 priority: self.priority,
325 priorities: self.priorities,
326 created: self.created,
327 throttle_ul: self.throttle_ul,
328 throttle_dl: self.throttle_dl,
329 }.migrate()
330 }
331 }
332
333 fn generate_piece_idx(pieces: usize, pl: u64, files: &[next::File]) -> Vec<(usize, u64)> {
334 let mut piece_idx = Vec::with_capacity(pieces);
335 let mut file = 0;
336 let mut offset = 0u64;
337 for _ in 0..pieces {
338 piece_idx.push((file, offset));
339 offset += pl;
340 while file < files.len() && offset >= files[file].length {
341 offset -= files[file].length;
342 file += 1;
343 }
344 }
345 piece_idx
346 }
347 }
348
349 pub mod ver_8e1121 {
350 use super::ver_5f166d as next;
351 use super::Bitfield;
352 use self::next::{Info, Status};
353
354 use chrono::{DateTime, Utc};
355
356 #[derive(Serialize, Deserialize)]
357 pub struct Session {
358 pub info: Info,
359 pub pieces: Bitfield,
360 pub uploaded: u64,
361 pub downloaded: u64,
362 pub status: Status,
363 pub path: Option<String>,
364 pub wanted: Bitfield,
365 pub priority: u8,
366 pub priorities: Vec<u8>,
367 pub created: DateTime<Utc>,
368 pub throttle_ul: Option<i64>,
369 pub throttle_dl: Option<i64>,
370 }
371
372 impl Session {
373 pub fn migrate(self) -> super::current::Session {
374 next::Session {
375 info: self.info,
376 pieces: self.pieces,
377 uploaded: self.uploaded,
378 downloaded: self.downloaded,
379 status: self.status,
380 path: self.path,
381 priority: self.priority,
382 priorities: self.priorities,
383 created: self.created,
384 throttle_ul: self.throttle_ul,
385 throttle_dl: self.throttle_dl,
386 }.migrate()
387 }
388 }
389 }
390}