use serde::{Deserialize, Serialize};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use thiserror::Error;
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, Hash, Eq)]
pub enum Request {
Ls(IndexQuery),
Read(ReadQuery),
AnnouncePeer(AnnouncePeer),
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, Eq, Hash)]
pub struct IndexQuery {
pub path: Option<String>,
pub searchterm: Option<String>,
pub recursive: bool,
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, Eq, Hash)]
pub struct ReadQuery {
pub path: String,
pub start: Option<u64>,
pub end: Option<u64>,
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub enum LsResponse {
Success(Vec<Entry>),
Err(LsResponseError),
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct Entry {
pub name: String,
pub size: u64,
pub is_dir: bool,
}
#[derive(Error, Serialize, Deserialize, PartialEq, Debug, Clone)]
pub enum LsResponseError {
#[error("Database error")]
DbError,
#[error("Path not found")]
PathNotFound,
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, Hash, Eq)]
pub struct AnnounceAddress {
pub connection_details: PeerConnectionDetails,
pub public_key: [u8; 32],
}
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone, Hash)]
pub struct AnnouncePeer {
pub announce_address: AnnounceAddress,
}
impl AnnounceAddress {
pub fn from_bytes(input: Vec<u8>) -> Result<Self, AnnounceAddressDecodeError> {
if input.len() < 33 {
return Err(AnnounceAddressDecodeError::BadLength);
}
let public_key = &input[..32];
let type_value = &input[32];
let (type_value, ip, port) = if *type_value > 2 {
if input.len() < 33 + 16 {
return Err(AnnounceAddressDecodeError::BadLength);
}
let ip_bytes = &input[33..33 + 16];
let ip_u128 = u128::from_be_bytes(
ip_bytes
.try_into()
.map_err(|_| AnnounceAddressDecodeError::BadLength)?,
);
let ip = IpAddr::V6(Ipv6Addr::from_bits(ip_u128));
let type_value = type_value - 2;
let port = if type_value == 1 {
None
} else {
if input.len() < 33 + 16 + 2 {
return Err(AnnounceAddressDecodeError::BadLength);
}
let port_bytes = &input[33 + 16..33 + 16 + 2];
Some(u16::from_be_bytes(
port_bytes
.try_into()
.map_err(|_| AnnounceAddressDecodeError::BadLength)?,
))
};
(type_value, ip, port)
} else {
if input.len() < 33 + 4 {
return Err(AnnounceAddressDecodeError::BadLength);
}
let ip_bytes = &input[33..33 + 4];
let ip_u32 = u32::from_be_bytes(
ip_bytes
.try_into()
.map_err(|_| AnnounceAddressDecodeError::BadLength)?,
);
let ip = IpAddr::V4(Ipv4Addr::from_bits(ip_u32));
let port = if *type_value == 1 {
None
} else {
if input.len() < 33 + 4 + 2 {
return Err(AnnounceAddressDecodeError::BadLength);
}
let port_bytes = &input[33 + 4..33 + 4 + 2];
Some(u16::from_be_bytes(
port_bytes
.try_into()
.map_err(|_| AnnounceAddressDecodeError::BadLength)?,
))
};
(*type_value, ip, port)
};
let connection_details = match type_value {
0 => {
let socket_addr = match ip {
IpAddr::V4(ip) => SocketAddr::V4(SocketAddrV4::new(ip, port.unwrap())),
IpAddr::V6(ip) => SocketAddr::V6(SocketAddrV6::new(ip, port.unwrap(), 0, 0)),
};
PeerConnectionDetails::NoNat(socket_addr)
}
1 => PeerConnectionDetails::Symmetric(ip),
2 => {
let socket_addr = match ip {
IpAddr::V4(ip) => SocketAddr::V4(SocketAddrV4::new(ip, port.unwrap())),
IpAddr::V6(ip) => SocketAddr::V6(SocketAddrV6::new(ip, port.unwrap(), 0, 0)),
};
PeerConnectionDetails::Asymmetric(socket_addr)
}
_ => return Err(AnnounceAddressDecodeError::UnrecognizedTypeValue),
};
Ok(AnnounceAddress {
connection_details,
public_key: public_key.try_into().unwrap(),
})
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut type_value = match self.connection_details {
PeerConnectionDetails::NoNat(_) => 0,
PeerConnectionDetails::Symmetric(_) => 1,
PeerConnectionDetails::Asymmetric(_) => 2,
};
if self.connection_details.ip().is_ipv6() {
type_value += 3;
}
let ip = match self.connection_details.ip() {
IpAddr::V4(ip_v4) => {
let ip_bits = ip_v4.to_bits();
let ip_bytes = ip_bits.to_be_bytes();
ip_bytes.to_vec()
}
IpAddr::V6(ip_v6) => {
let ip_bits = ip_v6.to_bits();
let ip_bytes = ip_bits.to_be_bytes();
ip_bytes.to_vec()
}
};
let port = match self.connection_details.port() {
Some(port) => port.to_be_bytes().to_vec(),
None => Vec::new(),
};
let mut announce_address: Vec<u8> = Vec::new();
announce_address.extend_from_slice(&self.public_key);
announce_address.extend_from_slice(&[type_value]);
announce_address.extend_from_slice(&ip);
announce_address.extend_from_slice(&port);
announce_address
}
}
#[repr(u8)]
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone, Hash)]
pub enum PeerConnectionDetails {
NoNat(SocketAddr) = 1,
Asymmetric(SocketAddr) = 2,
Symmetric(IpAddr) = 3,
}
impl PeerConnectionDetails {
pub fn ip(&self) -> IpAddr {
match self {
PeerConnectionDetails::NoNat(addr) => addr.ip(),
PeerConnectionDetails::Asymmetric(addr) => addr.ip(),
PeerConnectionDetails::Symmetric(ip) => *ip,
}
}
pub fn port(&self) -> Option<u16> {
match self {
PeerConnectionDetails::NoNat(addr) => Some(addr.port()),
PeerConnectionDetails::Asymmetric(addr) => Some(addr.port()),
PeerConnectionDetails::Symmetric(_) => None,
}
}
}
#[derive(Error, Serialize, Deserialize, PartialEq, Debug, Clone)]
pub enum AnnounceAddressDecodeError {
#[error("Bad length")]
BadLength,
#[error("Type value is invalid")]
UnrecognizedTypeValue,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn announce_address_encoding() {
let announce_address = AnnounceAddress {
connection_details: PeerConnectionDetails::NoNat("127.0.0.1:3000".parse().unwrap()),
public_key: [1; 32],
};
let bytes = announce_address.to_bytes();
let announce_address_2 = AnnounceAddress::from_bytes(bytes).unwrap();
assert_eq!(announce_address, announce_address_2);
}
}