Added to_string(), new_no_validation and some Traits

to_string is a basic function that tries to generate a minimal magnet_url from a Magnet struct.

The new function was turned into a wrapper of no_new_validation, with the difference being that new makes sure that the magnet str given is a valid magnet url. This should theoretically increase speeds for those who use new_no_validation.

I also added Debug, Clone, Hash, and PartialEq traits to the struct, meaning that the struct is now a little bit more useful in general.

Of course I also added some tests of to_string and the new Traits
This commit is contained in:
William Batista 2021-02-18 12:49:06 -05:00
parent 79b360792b
commit 0d5eeff1fc
No known key found for this signature in database
GPG Key ID: C6D7973D216F38D3
1 changed files with 114 additions and 14 deletions

View File

@ -91,12 +91,40 @@ const MANIFEST_TOPIC_RE_STR: &str = r"mt=((\w+)[A-Za-z0-9!@#$%^:*<>,?/()_+=.{}\\
/// }; /// };
/// ``` /// ```
/// ///
/// From a Magnet struct, you can generate a magnet string again
///
/// ```
/// use magnet_url::Magnet;
/// //Note, this magnet won't actually download, sorry :/
/// let magnet_struct = Magnet {
/// dn: "hello_world".to_string(),
/// hash_type: "sha1".to_string(),
/// xt: "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed".to_string(),
/// xl: 1234567890,
/// tr:
/// {
/// let mut tr_vec = Vec::new();
/// tr_vec.push("https://example.com/".to_string());
/// tr_vec
/// },
/// kt: "cool+stuff".to_string(),
/// ws: String::new(),
/// acceptable_source: String::new(),
/// mt: String::new(),
/// xs: String::new(),
/// };
///
/// let magnet_string = magnet_struct.to_string();
/// println!("{}", magnet_string);
/// ```
///
/// Invalid magnet url's will result in a panic! (This will be changed to an error in v2.0.0 /// Invalid magnet url's will result in a panic! (This will be changed to an error in v2.0.0
/// ```#[should_panic] /// ```#[should_panic]
/// use magnet_url::Magnet; /// use magnet_url::Magnet;
/// let _magnet_link = Magnet::new("https://example.com"); /// let _magnet_link = Magnet::new("https://example.com");
/// ``` /// ```
#[derive(Debug, Clone, Hash, PartialEq)]
pub struct Magnet { pub struct Magnet {
///Display Name of the torrent ///Display Name of the torrent
pub dn: String, pub dn: String,
@ -134,23 +162,70 @@ pub struct Magnet {
} }
impl Magnet { impl Magnet {
pub fn gen_magnet_string(&self) -> String { /**
let mut magnet_string = This generates a magnet url string given a Magnet struct
format!("magnet:?xt=urn:{}:{}&dn={}&xl={}&xs={}&kt={}&ws={}&as={}&mt={}", self.hash_type, self.xt, self.dn, self.xl, self.xs, self.kt, self.ws, self.acceptable_source, self.mt); */
pub fn to_string(&self) -> String {
for tracker in &self.tr { let mut magnet_string = String::from("magnet:?");
magnet_string = format!("{}&tr={}", magnet_string, tracker)
if self.xt != String::new() {
magnet_string = format!("{}{}{}:{}", magnet_string, "xt=urn:", self.hash_type, self.xt);
} }
let add_to_mag_string = |p_name: String, p_val: &String| -> String {
if p_val != &String::new() {
format!("&{}={}", p_name, p_val)
} else {
String::new()
}
};
magnet_string = format!("{}{}", magnet_string, add_to_mag_string(String::from("dn"), &self.dn));
if self.xl != -1 {
magnet_string = format!("{}&xl={}", magnet_string, &self.xl);
}
magnet_string = {
let mut tr_string = String::new();
for tracker in &self.tr {
tr_string = format!("{}&tr={}", tr_string, tracker);
}
format!("{}{}", magnet_string, tr_string)
};
magnet_string = format!("{}{}", magnet_string, add_to_mag_string(String::from("ws"), &self.ws));
magnet_string = format!("{}{}", magnet_string, add_to_mag_string(String::from("xs"), &self.xs));
magnet_string = format!("{}{}", magnet_string, add_to_mag_string(String::from("kt"), &self.kt));
magnet_string = format!("{}{}", magnet_string, add_to_mag_string(String::from("as"), &self.acceptable_source));
magnet_string = format!("{}{}", magnet_string, add_to_mag_string(String::from("mt"), &self.mt));
magnet_string magnet_string
} }
///Just calls new_no_validation, but validates the string given before running it through.
/// This is the recommended way of creating a nw Magnet struct, if you're unsure of the quality
/// of the magnet url's you input.
pub fn new(magnet_str: &str) -> Magnet {
// Panicking is a temporary fix, in version 2.0.0 it will instead return an Error
if &magnet_str[0..8] != "magnet:?" {
panic!("Invalid magnet url")
}
Magnet::new_no_validation(magnet_str)
}
/**Given a magnet URL, identify the specific parts, and return the Magnet struct. If the program /**Given a magnet URL, identify the specific parts, and return the Magnet struct. If the program
can't identify a specific part of the magnet, then it will either give an empty version of what can't identify a specific part of the magnet, then it will either give an empty version of what
its value would normally be (such as an empty string, an empty vector, or in the case of xl, -1) its value would normally be (such as an empty string, an empty vector, or in the case of xl, -1).
It also doesn't validate whether the magnet url is good, which makes it faster, but dangerous!
Only use this function if you know for certain that the magnet url given is valid.
*/ */
pub fn new (magnet_str: &str) -> Magnet { pub fn new_no_validation (magnet_str: &str) -> Magnet {
lazy_static! { lazy_static! {
static ref DISPLAY_NAME_RE: Regex = Regex::new(DISPLAY_NAME_RE_STR).unwrap(); static ref DISPLAY_NAME_RE: Regex = Regex::new(DISPLAY_NAME_RE_STR).unwrap();
static ref EXACT_TOPIC_RE: Regex = Regex::new(EXACT_TOPIC_RE_STR).unwrap(); static ref EXACT_TOPIC_RE: Regex = Regex::new(EXACT_TOPIC_RE_STR).unwrap();
@ -163,11 +238,6 @@ impl Magnet {
static ref MANIFEST_TOPIC_RE: Regex = Regex::new(MANIFEST_TOPIC_RE_STR).unwrap(); static ref MANIFEST_TOPIC_RE: Regex = Regex::new(MANIFEST_TOPIC_RE_STR).unwrap();
} }
// Panicking is a temporary fix, in version 2.0.0 it will instead return an Error
if &magnet_str[0..8] != "magnet:?" {
panic!("Invalid magnet url")
}
let validate_regex = |regex: &Regex, re_group_index| -> String { let validate_regex = |regex: &Regex, re_group_index| -> String {
match regex.captures(magnet_str) { match regex.captures(magnet_str) {
Some(m) => m.get(re_group_index).map_or(String::new(), |m| m.as_str().to_string()), Some(m) => m.get(re_group_index).map_or(String::new(), |m| m.as_str().to_string()),
@ -214,7 +284,8 @@ mod tests {
#[test] #[test]
fn sintel_test() { fn sintel_test() {
let magnet_link = Magnet::new("magnet:?xt=urn:btih:08ada5a7a6183aae1e09d831df6748d566095a10&dn=Sintel&tr=udp%3A%2F%2Fexplodie.org%3A6969&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftracker.empire-js.us%3A1337&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337&tr=wss%3A%2F%2Ftracker.btorrent.xyz&tr=wss%3A%2F%2Ftracker.fastcast.nz&tr=wss%3A%2F%2Ftracker.openwebtorrent.com&ws=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2F&xs=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2Fsintel.torrent"); const MAGNET_STR: &str = "magnet:?xt=urn:btih:08ada5a7a6183aae1e09d831df6748d566095a10&dn=Sintel&tr=udp%3A%2F%2Fexplodie.org%3A6969&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftracker.empire-js.us%3A1337&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337&tr=wss%3A%2F%2Ftracker.btorrent.xyz&tr=wss%3A%2F%2Ftracker.fastcast.nz&tr=wss%3A%2F%2Ftracker.openwebtorrent.com&ws=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2F&xs=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2Fsintel.torrent";
let magnet_link = Magnet::new(MAGNET_STR);
assert_eq!(magnet_link.dn, "Sintel".to_string()); assert_eq!(magnet_link.dn, "Sintel".to_string());
assert_eq!(magnet_link.hash_type, "btih".to_string()); assert_eq!(magnet_link.hash_type, "btih".to_string());
@ -235,7 +306,10 @@ mod tests {
assert_eq!(magnet_link.acceptable_source, String::new()); assert_eq!(magnet_link.acceptable_source, String::new());
assert_eq!(magnet_link.mt, String::new()); assert_eq!(magnet_link.mt, String::new());
println!("{}", magnet_link.gen_magnet_string()); //Need to recreate a magnet struct from the string, since the elements could be in any order
assert_eq!(Magnet::new(&magnet_link.to_string()), magnet_link);
//Also tests PartialEq
assert_eq!(Magnet::new(&magnet_link.to_string()) == magnet_link, true);
} }
#[test] #[test]
@ -244,4 +318,30 @@ mod tests {
let _magnet_link = Magnet::new("https://example.com"); let _magnet_link = Magnet::new("https://example.com");
} }
#[test]
fn not_equal_magnet_test() {
//These two torrents aren't even close to equal
const MAGNET_STR_1: &str = "magnet:?xt=urn:btih:08ada5a7a6183aae1e09d831df6748d566095a10&dn=Sintel&tr=udp%3A%2F%2Fexplodie.org%3A6969&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftracker.empire-js.us%3A1337&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337&tr=wss%3A%2F%2Ftracker.btorrent.xyz&tr=wss%3A%2F%2Ftracker.fastcast.nz&tr=wss%3A%2F%2Ftracker.openwebtorrent.com&ws=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2F&xs=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2Fsintel.torrent";
const MAGNET_STR_2: &str = "magnet:?xt=urn:btih:da826adb2ba4933500d83c19bbdfa73ee28f34d5&dn=devuan%5Fbeowulf&tr=udp%3A%2F%2F9.rarbg.me%3A2710%2Fannounce&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337%2Fannounce&tr=udp%3A%2F%2Ftracker.cyberia.is%3A6969%2Fannounce";
let magnet_link_1 = Magnet::new(MAGNET_STR_1);
let magnet_link_2 = Magnet::new(MAGNET_STR_2);
//These two torrents, on the other hand, are very similar
const MAGNET_STR_3: &str = "magnet:?xt=urn:btih:da826adb2ba4933500d83c19bbdfa73ee28f34d5&dn=devuan%5Fbeowulf&tr=udp%3A%2F%2F9.rarbg.me%3A2710%2Fannounce&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337%2Fannounce&tr=udp%3A%2F%2Ftracker.cyberia.is%3A6969%2Fannounce";
const MAGNET_STR_4: &str = "magnet:?xt=urn:btih:da826adb2ba4933500d83c19bbdfa73ee28f34d5&dn=devuan%5Fbeowulf&tr=udp%3A%2F%2F9.rarbg.me%3A2710%2Fannounce&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337%2Fannounce&tr=udp%3A%2F%2Ftracker.cyberia.is%3A6969%2Fannounce&tr=https://example.com/fake_tracker";
let magnet_link_3 = Magnet::new(MAGNET_STR_3);
let magnet_link_4 = Magnet::new(MAGNET_STR_4);
assert_ne!(magnet_link_1, magnet_link_2);
assert_ne!(magnet_link_3, magnet_link_4);
//magnet_link_2 and magnet_link_3 are exactly the same
assert_eq!(magnet_link_2, magnet_link_3);
//Tests PartialEq instead of Debug
assert_eq!(magnet_link_2 == magnet_link_3, true);
}
} }