#![feature(error_generic_member_access)]
use std::{fmt::Display, net::SocketAddr, str::FromStr};
#[cfg(feature = "connecting")]
pub mod connect;
#[cfg(feature = "packets")]
pub mod packets;
pub mod read;
pub mod resolver;
pub mod write;
#[derive(Debug, Clone)]
pub struct ServerAddress {
pub host: String,
pub port: u16,
}
impl<'a> TryFrom<&'a str> for ServerAddress {
type Error = String;
fn try_from(string: &str) -> Result<Self, Self::Error> {
if string.is_empty() {
return Err("Empty string".to_string());
}
let mut parts = string.split(':');
let host = parts.next().ok_or("No host specified")?.to_string();
let port = parts.next().unwrap_or("25565");
let port = u16::from_str(port).map_err(|_| "Invalid port specified")?;
Ok(ServerAddress { host, port })
}
}
impl From<SocketAddr> for ServerAddress {
fn from(addr: SocketAddr) -> Self {
ServerAddress {
host: addr.ip().to_string(),
port: addr.port(),
}
}
}
impl Display for ServerAddress {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}:{}", self.host, self.port)
}
}
impl<'de> serde::Deserialize<'de> for ServerAddress {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let string = String::deserialize(deserializer)?;
ServerAddress::try_from(string.as_str()).map_err(serde::de::Error::custom)
}
}
impl serde::Serialize for ServerAddress {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
#[cfg(test)]
mod tests {
use std::io::Cursor;
use bytes::BytesMut;
use uuid::Uuid;
use crate::{
packets::{
game::serverbound_chat_packet::{LastSeenMessagesUpdate, ServerboundChatPacket},
login::{serverbound_hello_packet::ServerboundHelloPacket, ServerboundLoginPacket},
},
read::{compression_decoder, read_packet},
write::{compression_encoder, serialize_packet, write_packet},
};
#[tokio::test]
async fn test_hello_packet() {
let packet = ServerboundHelloPacket {
name: "test".to_string(),
profile_id: Uuid::nil(),
}
.get();
let mut stream = Vec::new();
write_packet(&packet, &mut stream, None, &mut None)
.await
.unwrap();
let mut stream = Cursor::new(stream);
let _ = read_packet::<ServerboundLoginPacket, _>(
&mut stream,
&mut BytesMut::new(),
None,
&mut None,
)
.await
.unwrap();
}
#[tokio::test]
async fn test_double_hello_packet() {
let packet = ServerboundHelloPacket {
name: "test".to_string(),
profile_id: Uuid::nil(),
}
.get();
let mut stream = Vec::new();
write_packet(&packet, &mut stream, None, &mut None)
.await
.unwrap();
write_packet(&packet, &mut stream, None, &mut None)
.await
.unwrap();
let mut stream = Cursor::new(stream);
let mut buffer = BytesMut::new();
let _ = read_packet::<ServerboundLoginPacket, _>(&mut stream, &mut buffer, None, &mut None)
.await
.unwrap();
let _ = read_packet::<ServerboundLoginPacket, _>(&mut stream, &mut buffer, None, &mut None)
.await
.unwrap();
}
#[tokio::test]
async fn test_read_long_compressed_chat() {
let compression_threshold = 256;
let buf = serialize_packet(
&ServerboundChatPacket {
message: "a".repeat(256),
timestamp: 0,
salt: 0,
signature: None,
last_seen_messages: LastSeenMessagesUpdate::default(),
}
.get(),
)
.unwrap();
let buf = compression_encoder(&buf, compression_threshold).unwrap();
println!("{:?}", buf);
compression_decoder(&mut Cursor::new(&buf), compression_threshold).unwrap();
}
}