synapse_session/
lib.rs

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            // Torrent has not acquired all pieces
97            Incomplete,
98            // Torrent has acquired all pieces, regardless of validity
99            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}