mirror of
https://github.com/YGGverse/aquatic.git
synced 2026-04-02 10:45:30 +00:00
aquatic_ws: use [u8; 20] for info hash etc, fix deserialization
This commit is contained in:
parent
6b0f2463b6
commit
18c4a51b74
2 changed files with 38 additions and 11 deletions
|
|
@ -6,7 +6,7 @@ use super::InfoHash;
|
||||||
struct TwentyByteVisitor;
|
struct TwentyByteVisitor;
|
||||||
|
|
||||||
impl<'de> Visitor<'de> for TwentyByteVisitor {
|
impl<'de> Visitor<'de> for TwentyByteVisitor {
|
||||||
type Value = String;
|
type Value = [u8; 20];
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
formatter.write_str("string consisting of 20 bytes")
|
formatter.write_str("string consisting of 20 bytes")
|
||||||
|
|
@ -15,19 +15,40 @@ impl<'de> Visitor<'de> for TwentyByteVisitor {
|
||||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||||
where E: ::serde::de::Error,
|
where E: ::serde::de::Error,
|
||||||
{
|
{
|
||||||
if value.chars().count() == 20 { // FIXME
|
// Value is encoded in nodejs reference client something as follows:
|
||||||
Ok(value.to_string())
|
// ```
|
||||||
|
// var infoHash = 'abcd..'; // 40 hexadecimals
|
||||||
|
// Buffer.from(infoHash, 'hex').toString('binary');
|
||||||
|
// ```
|
||||||
|
// which produces a UTF16 string with each char having only the low
|
||||||
|
// byte set. Here, we extract it by casting to u8.
|
||||||
|
|
||||||
|
let mut arr = [0u8; 20];
|
||||||
|
let mut max_i = 0;
|
||||||
|
|
||||||
|
for (i, (a, c)) in arr.iter_mut().zip(value.chars()).enumerate(){
|
||||||
|
if c as u32 > 255 {
|
||||||
|
return Err(E::custom(format!(
|
||||||
|
"character not in single byte range: {}",
|
||||||
|
c
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
*a = c as u8;
|
||||||
|
max_i = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if max_i == 19 {
|
||||||
|
Ok(arr)
|
||||||
} else {
|
} else {
|
||||||
Err(E::custom(format!("not 20 bytes: {}", value)))
|
Err(E::custom(format!("not 20 bytes: {}", value)))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn deserialize_20_bytes<'de, D>(
|
pub fn deserialize_20_bytes<'de, D>(
|
||||||
deserializer: D
|
deserializer: D
|
||||||
) -> Result<String, D::Error>
|
) -> Result<[u8; 20], D::Error>
|
||||||
where D: Deserializer<'de>
|
where D: Deserializer<'de>
|
||||||
{
|
{
|
||||||
deserializer.deserialize_any(TwentyByteVisitor)
|
deserializer.deserialize_any(TwentyByteVisitor)
|
||||||
|
|
@ -95,7 +116,13 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn info_hash_from_bytes(bytes: &[u8]) -> InfoHash {
|
fn info_hash_from_bytes(bytes: &[u8]) -> InfoHash {
|
||||||
InfoHash(String::from_utf8_lossy(bytes).to_string())
|
let mut arr = [0u8; 20];
|
||||||
|
|
||||||
|
assert!(bytes.len() == 20);
|
||||||
|
|
||||||
|
arr.copy_from_slice(&bytes[..]);
|
||||||
|
|
||||||
|
InfoHash(arr)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -107,12 +134,12 @@ mod tests {
|
||||||
|
|
||||||
assert_eq!(observed, expected);
|
assert_eq!(observed, expected);
|
||||||
|
|
||||||
let input = r#""1aaaabbbbccccddddeeee""#;
|
let input = r#""aaaabbbbccccddddeee""#;
|
||||||
let res_info_hash: Result<InfoHash, _> = serde_json::from_str(input);
|
let res_info_hash: Result<InfoHash, _> = serde_json::from_str(input);
|
||||||
|
|
||||||
assert!(res_info_hash.is_err());
|
assert!(res_info_hash.is_err());
|
||||||
|
|
||||||
let input = r#""aaaabbbbccccddddeeeö""#;
|
let input = r#""aaaabbbbccccddddeee𝕊""#;
|
||||||
let res_info_hash: Result<InfoHash, _> = serde_json::from_str(input);
|
let res_info_hash: Result<InfoHash, _> = serde_json::from_str(input);
|
||||||
|
|
||||||
assert!(res_info_hash.is_err());
|
assert!(res_info_hash.is_err());
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ use deserialize::*;
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct PeerId(
|
pub struct PeerId(
|
||||||
#[serde(deserialize_with = "deserialize_20_bytes")]
|
#[serde(deserialize_with = "deserialize_20_bytes")]
|
||||||
pub String
|
pub [u8; 20]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -18,7 +18,7 @@ pub struct PeerId(
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct InfoHash(
|
pub struct InfoHash(
|
||||||
#[serde(deserialize_with = "deserialize_20_bytes")]
|
#[serde(deserialize_with = "deserialize_20_bytes")]
|
||||||
pub String
|
pub [u8; 20]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -26,7 +26,7 @@ pub struct InfoHash(
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct OfferId(
|
pub struct OfferId(
|
||||||
#[serde(deserialize_with = "deserialize_20_bytes")]
|
#[serde(deserialize_with = "deserialize_20_bytes")]
|
||||||
pub String
|
pub [u8; 20]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue