mirror of
https://github.com/OMGeeky/mc-server-rs-sample.git
synced 2026-02-23 15:49:54 +01:00
create package structs for easier handling of individual packages & finally fix status.
It finally works in the client to list the server
This commit is contained in:
89
src/main.rs
89
src/main.rs
@@ -58,6 +58,10 @@ impl Connection {
|
|||||||
self.connection_state = ConnectionState::Closed;
|
self.connection_state = ConnectionState::Closed;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// else if size == 0xFE {
|
||||||
|
// // Legacy Ping (see https://wiki.vg/Server_List_Ping#1.6)
|
||||||
|
// handle_legacy_ping(&mut self.tcp_stream).await?;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
println!("could not peek if we reached the end of the stream.");
|
println!("could not peek if we reached the end of the stream.");
|
||||||
@@ -65,6 +69,16 @@ impl Connection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let length = VarInt::read_stream(&mut self.tcp_stream).await?;
|
let length = VarInt::read_stream(&mut self.tcp_stream).await?;
|
||||||
|
if *length == 0xFE {
|
||||||
|
//Legacy Ping (see https://wiki.vg/Server_List_Ping#1.6)
|
||||||
|
let x = handle_legacy_ping(&mut self.tcp_stream).await;
|
||||||
|
self.connection_state = ConnectionState::Closed;
|
||||||
|
self.tcp_stream.shutdown().await.map_err(|e| {
|
||||||
|
dbg!(e);
|
||||||
|
"?"
|
||||||
|
})?;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
println!("packet length: {}", length.as_rs());
|
println!("packet length: {}", length.as_rs());
|
||||||
let bytes_left_in_package = length.to_rs();
|
let bytes_left_in_package = length.to_rs();
|
||||||
|
|
||||||
@@ -102,24 +116,26 @@ impl Connection {
|
|||||||
_compression: bool,
|
_compression: bool,
|
||||||
// bytes_left_in_package: &mut i32,
|
// bytes_left_in_package: &mut i32,
|
||||||
) -> Result<ConnectionState, String> {
|
) -> Result<ConnectionState, String> {
|
||||||
println!("Handshake");
|
let handshake_data = protocols::handshake::Data::read_stream(stream).await?;
|
||||||
let protocol_version = VarInt::read_stream(stream).await?;
|
// dbg!(&handshake_data);
|
||||||
println!("protocol version: {}", protocol_version.as_rs());
|
Ok(handshake_data.next_state)
|
||||||
let address: McString<255> = McString::read_stream(stream)
|
// let protocol_version = VarInt::read_stream(stream).await?;
|
||||||
.await
|
// println!("protocol version: {}", protocol_version.as_rs());
|
||||||
.map_err(|_| "Could not read string".to_string())?;
|
// let address: McString<255> = McString::read_stream(stream)
|
||||||
println!("address: '{}'", address.as_rs());
|
// .await
|
||||||
stream.discard(2).await.unwrap(); //server port. Unused
|
// .map_err(|_| "Could not read string".to_string())?;
|
||||||
let next_state_id = VarInt::read_stream(stream).await?;
|
// println!("address: '{}'", address.as_rs());
|
||||||
println!("next state: {}", next_state_id.as_rs());
|
// stream.discard(2).await.unwrap(); //server port. Unused
|
||||||
let next_state = FromPrimitive::from_i32(next_state_id.to_rs());
|
// let next_state_id = VarInt::read_stream(stream).await?;
|
||||||
match next_state {
|
// println!("next state: {}", next_state_id.as_rs());
|
||||||
Some(next_state) => Ok(next_state),
|
// let next_state = FromPrimitive::from_i32(next_state_id.to_rs());
|
||||||
None => Err(format!(
|
// match next_state {
|
||||||
"Got an unknown next state: {}",
|
// Some(next_state) => Ok(next_state),
|
||||||
next_state_id.as_rs()
|
// None => Err(format!(
|
||||||
)),
|
// "Got an unknown next state: {}",
|
||||||
}
|
// next_state_id.as_rs()
|
||||||
|
// )),
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
async fn handle_package<T: AsyncRead + AsyncWrite + Unpin>(
|
async fn handle_package<T: AsyncRead + AsyncWrite + Unpin>(
|
||||||
stream: &mut RWStreamWithLimit<'_, T>,
|
stream: &mut RWStreamWithLimit<'_, T>,
|
||||||
@@ -128,13 +144,17 @@ impl Connection {
|
|||||||
) -> Result<ConnectionState, String> {
|
) -> Result<ConnectionState, String> {
|
||||||
let packet_id = VarInt::read_stream(stream).await?;
|
let packet_id = VarInt::read_stream(stream).await?;
|
||||||
|
|
||||||
println!("id: {:0>2x}", packet_id.as_rs());
|
println!(
|
||||||
|
"Handling new Package with id: {:0>2x} =======================",
|
||||||
|
packet_id.as_rs()
|
||||||
|
);
|
||||||
if connection_state == ConnectionState::NotConnected && packet_id.to_rs() == 0x00 {
|
if connection_state == ConnectionState::NotConnected && packet_id.to_rs() == 0x00 {
|
||||||
return Self::handshake(stream, compression).await;
|
return Self::handshake(stream, compression).await;
|
||||||
}
|
}
|
||||||
match FromPrimitive::from_i32(packet_id.to_rs()) {
|
match FromPrimitive::from_i32(packet_id.to_rs()) {
|
||||||
Some(protocol) => {
|
Some(protocol) => {
|
||||||
let res = protocols::handle(protocol, stream).await;
|
let res = types::package::Package::handle(protocol, stream).await;
|
||||||
|
// let res = protocols::handle(protocol, stream).await;
|
||||||
match res {
|
match res {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
println!("Success!");
|
println!("Success!");
|
||||||
@@ -159,6 +179,35 @@ impl Connection {
|
|||||||
Ok(connection_state)
|
Ok(connection_state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn handle_legacy_ping(stream: &mut TcpStream) -> Result<(), String> {
|
||||||
|
println!("handling legacy ping");
|
||||||
|
let id = stream.read_u8().await.map_err(|e| e.to_string())?;
|
||||||
|
let payload = stream.read_u8().await.map_err(|e| e.to_string())?;
|
||||||
|
let plugin_message_ident = stream.read_u8().await.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
|
stream
|
||||||
|
.write_all(&[
|
||||||
|
0xfe, // 1st packet id: 0xfe for server list ping
|
||||||
|
0x01, // payload: always 1
|
||||||
|
0xfa, // 2nd packet id: 0xfa for plugin message
|
||||||
|
0x00, 0x0b, // length of following string: always 11 as short,
|
||||||
|
0x00, 0x4d, 0x00, 0x43, 0x00, 0x7c, 0x00, 0x50, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67,
|
||||||
|
0x00, 0x48, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x74,
|
||||||
|
// ^^ MC|PingHost as UTF16-BE
|
||||||
|
|
||||||
|
// length of the rest of the data
|
||||||
|
13, // ^^
|
||||||
|
// protocol version: 127 for the invalid version, to signal, client is too old
|
||||||
|
0, 49, 0, 50, 0, 55, // ^^
|
||||||
|
0x00, 0x00, // length of hostname: 0 as short
|
||||||
|
0x00, 0x00, 0x00, 0x00, // port: 0 as int
|
||||||
|
])
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
async fn handle_connection(stream: TcpStream) {
|
async fn handle_connection(stream: TcpStream) {
|
||||||
let mut connection = Connection {
|
let mut connection = Connection {
|
||||||
connection_state: ConnectionState::NotConnected,
|
connection_state: ConnectionState::NotConnected,
|
||||||
|
|||||||
@@ -1,25 +1,31 @@
|
|||||||
use crate::utils::RWStreamWithLimit;
|
use crate::utils::RWStreamWithLimit;
|
||||||
use num_derive::FromPrimitive;
|
use num_derive::{FromPrimitive, ToPrimitive};
|
||||||
use tokio::io::{AsyncRead, AsyncWrite};
|
use tokio::io::{AsyncRead, AsyncWrite};
|
||||||
|
|
||||||
#[derive(FromPrimitive)]
|
#[derive(FromPrimitive, ToPrimitive, Debug, Copy, Clone)]
|
||||||
pub enum Protocol {
|
pub enum ProtocolId {
|
||||||
Status = 0x00,
|
Status = 0x00,
|
||||||
Ping = 0x01,
|
Ping = 0x01,
|
||||||
CustomReportDetails = 0x7a,
|
CustomReportDetails = 0x7a,
|
||||||
}
|
}
|
||||||
|
#[derive(FromPrimitive, ToPrimitive, Debug, Copy, Clone)]
|
||||||
|
pub enum ProtocolResponseId {
|
||||||
|
Status = 0x00,
|
||||||
|
Ping = 0x01,
|
||||||
|
}
|
||||||
pub async fn handle<T: AsyncRead + AsyncWrite + Unpin>(
|
pub async fn handle<T: AsyncRead + AsyncWrite + Unpin>(
|
||||||
protocol: Protocol,
|
protocol: ProtocolId,
|
||||||
stream: &mut RWStreamWithLimit<'_, T>,
|
stream: &mut RWStreamWithLimit<'_, T>,
|
||||||
// bytes_left_in_package: &mut i32,
|
// bytes_left_in_package: &mut i32,
|
||||||
) -> Result<(), bool> {
|
) -> Result<(), bool> {
|
||||||
match protocol {
|
match protocol {
|
||||||
Protocol::Status => status::Protocol::handle(stream).await?,
|
ProtocolId::Status => status::Protocol::handle(stream).await?,
|
||||||
Protocol::Ping => ping::Protocol::handle(stream).await?,
|
ProtocolId::Ping => ping::Protocol::handle(stream).await?,
|
||||||
Protocol::CustomReportDetails => custom_report_details::Protocol::handle(stream).await?,
|
ProtocolId::CustomReportDetails => custom_report_details::Protocol::handle(stream).await?,
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
mod custom_report_details;
|
pub(crate) mod custom_report_details;
|
||||||
mod ping;
|
pub(crate) mod handshake;
|
||||||
mod status;
|
pub(crate) mod ping;
|
||||||
|
pub(crate) mod status;
|
||||||
|
|||||||
@@ -1,11 +1,50 @@
|
|||||||
|
use crate::types::long::Long;
|
||||||
use crate::types::string::McString;
|
use crate::types::string::McString;
|
||||||
use crate::types::var_int::VarInt;
|
use crate::types::var_int::VarInt;
|
||||||
use crate::types::McRead;
|
use crate::types::McRead;
|
||||||
use crate::utils::RWStreamWithLimit;
|
use crate::utils::RWStreamWithLimit;
|
||||||
use tokio::io::{AsyncRead, AsyncWrite};
|
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, BufWriter};
|
||||||
|
|
||||||
pub struct Protocol {}
|
pub struct Protocol {}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Data {
|
||||||
|
details: Vec<(McString<128>, McString<4096>)>,
|
||||||
|
}
|
||||||
|
impl McRead for Data {
|
||||||
|
async fn read_stream<T: AsyncRead + Unpin>(stream: &mut T) -> Result<Self, String>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
// let size = stream.
|
||||||
|
// let mut v = vec![0; size];
|
||||||
|
// let mut writer = BufWriter::new(&mut v);
|
||||||
|
|
||||||
|
// let x = stream.read_buf(&mut v)
|
||||||
|
println!();
|
||||||
|
loop {
|
||||||
|
let byte = stream.read_u8().await.map_err(|e| {
|
||||||
|
dbg!(e);
|
||||||
|
"idk"
|
||||||
|
})?;
|
||||||
|
print!(" '{:0>2x}' ", byte);
|
||||||
|
dbg!(byte);
|
||||||
|
}
|
||||||
|
// println!("x");
|
||||||
|
// println!("{:?}", v);
|
||||||
|
// dbg!(&v);
|
||||||
|
// let count = VarInt::read_stream(stream).await?;
|
||||||
|
let details = vec![];
|
||||||
|
// let string = format!("Still need to get details from stream ({})", *count);
|
||||||
|
// dbg!(string);
|
||||||
|
// for i in 0..*count {
|
||||||
|
// let title = McString::<128>::read_stream(stream).await?;
|
||||||
|
// let description = McString::<128>::read_stream(stream).await?;
|
||||||
|
// }
|
||||||
|
|
||||||
|
Ok(Self { details })
|
||||||
|
}
|
||||||
|
}
|
||||||
impl Protocol {
|
impl Protocol {
|
||||||
pub async fn handle<T: AsyncRead + AsyncWrite + Unpin>(
|
pub async fn handle<T: AsyncRead + AsyncWrite + Unpin>(
|
||||||
stream: &mut RWStreamWithLimit<'_, T>,
|
stream: &mut RWStreamWithLimit<'_, T>,
|
||||||
@@ -18,14 +57,14 @@ impl Protocol {
|
|||||||
})?;
|
})?;
|
||||||
dbg!(&count);
|
dbg!(&count);
|
||||||
for i in 0..*count {
|
for i in 0..*count {
|
||||||
McString::<128>::read_stream(stream).await.map_err(|x| {
|
// McString::<128>::read_stream(stream).await.map_err(|x| {
|
||||||
dbg!(x);
|
// dbg!(x);
|
||||||
true
|
// true
|
||||||
})?;
|
// })?;
|
||||||
McString::<4096>::read_stream(stream).await.map_err(|x| {
|
// McString::<4096>::read_stream(stream).await.map_err(|x| {
|
||||||
dbg!(x);
|
// dbg!(x);
|
||||||
true
|
// true
|
||||||
})?;
|
// })?;
|
||||||
}
|
}
|
||||||
Err(true)
|
Err(true)
|
||||||
}
|
}
|
||||||
|
|||||||
47
src/protocols/handshake.rs
Normal file
47
src/protocols/handshake.rs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
use crate::types::long::Long;
|
||||||
|
use crate::types::string::McString;
|
||||||
|
use crate::types::var_int::{read_stream, VarInt};
|
||||||
|
use crate::types::var_long::VarLong;
|
||||||
|
use crate::types::{McRead, McRustRepr, McWrite};
|
||||||
|
use crate::utils::RWStreamWithLimit;
|
||||||
|
use crate::ConnectionState;
|
||||||
|
use num_traits::FromPrimitive;
|
||||||
|
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Data {
|
||||||
|
protocol_version: VarInt,
|
||||||
|
server_address: McString<255>,
|
||||||
|
server_port: u16,
|
||||||
|
pub(crate) next_state: ConnectionState,
|
||||||
|
}
|
||||||
|
impl McRead for Data {
|
||||||
|
async fn read_stream<T: AsyncRead + Unpin>(b: &mut T) -> Result<Self, String> {
|
||||||
|
println!("Reading Handshake");
|
||||||
|
let protocol_version = VarInt::read_stream(b).await?;
|
||||||
|
let server_address = McString::read_stream(b).await?;
|
||||||
|
let server_port = b
|
||||||
|
.read_u16()
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Error reading port:{e}"))?;
|
||||||
|
|
||||||
|
let next_state_id = VarInt::read_stream(b).await?;
|
||||||
|
println!("next state: {}", next_state_id.as_rs());
|
||||||
|
let next_state = FromPrimitive::from_i32(next_state_id.to_rs());
|
||||||
|
let next_state = match next_state {
|
||||||
|
Some(next_state) => next_state,
|
||||||
|
None => {
|
||||||
|
return Err(format!(
|
||||||
|
"Got an unknown next state: {}",
|
||||||
|
next_state_id.as_rs()
|
||||||
|
))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(Self {
|
||||||
|
server_port,
|
||||||
|
server_address,
|
||||||
|
next_state,
|
||||||
|
protocol_version,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,45 @@
|
|||||||
|
use crate::types::long::Long;
|
||||||
|
use crate::types::string::McString;
|
||||||
use crate::types::var_int::VarInt;
|
use crate::types::var_int::VarInt;
|
||||||
use crate::types::var_long::VarLong;
|
use crate::types::var_long::VarLong;
|
||||||
use crate::types::{McRead, McWrite};
|
use crate::types::{McRead, McWrite};
|
||||||
use crate::utils::RWStreamWithLimit;
|
use crate::utils::RWStreamWithLimit;
|
||||||
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
||||||
|
|
||||||
pub struct Protocol {}
|
pub struct Protocol();
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Data {
|
||||||
|
pub timespan: Long,
|
||||||
|
}
|
||||||
|
impl McRead for Data {
|
||||||
|
async fn read_stream<T: AsyncRead + Unpin>(stream: &mut T) -> Result<Self, String>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
Ok(Self {
|
||||||
|
timespan: Long::read_stream(stream).await?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ResponseData {
|
||||||
|
pub(crate) timespan: Long,
|
||||||
|
}
|
||||||
|
impl McWrite for ResponseData {
|
||||||
|
type Error = String;
|
||||||
|
|
||||||
|
async fn write_stream<T: AsyncWrite + Unpin>(
|
||||||
|
&self,
|
||||||
|
stream: &mut T,
|
||||||
|
) -> Result<usize, Self::Error> {
|
||||||
|
self.timespan
|
||||||
|
.write_stream(stream)
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
impl Protocol {
|
impl Protocol {
|
||||||
pub async fn handle<T: AsyncRead + AsyncWrite + Unpin>(
|
pub async fn handle<T: AsyncRead + AsyncWrite + Unpin>(
|
||||||
stream: &mut RWStreamWithLimit<'_, T>,
|
stream: &mut RWStreamWithLimit<'_, T>,
|
||||||
|
|||||||
@@ -1,13 +1,51 @@
|
|||||||
|
use crate::types::long::Long;
|
||||||
|
use crate::types::package::{OutgoingPackage, OutgoingPackageContent, Package};
|
||||||
use crate::types::string::McString;
|
use crate::types::string::McString;
|
||||||
use crate::types::var_int::VarInt;
|
use crate::types::var_int::VarInt;
|
||||||
use crate::types::var_long::VarLong;
|
use crate::types::var_long::VarLong;
|
||||||
use crate::types::McWrite;
|
use crate::types::{McRead, McWrite};
|
||||||
use crate::utils::RWStreamWithLimit;
|
use crate::utils::RWStreamWithLimit;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt, BufWriter};
|
use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt, BufWriter};
|
||||||
|
|
||||||
pub struct Protocol {}
|
pub struct Protocol {}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Data {}
|
||||||
|
|
||||||
|
impl McRead for Data {
|
||||||
|
async fn read_stream<T: AsyncRead + Unpin>(stream: &mut T) -> Result<Self, String>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
Ok(Self {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ResponseData {
|
||||||
|
json_response: McString<32767>,
|
||||||
|
}
|
||||||
|
impl Default for ResponseData {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
json_response: McString::from_string(Protocol::get_sample_result()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl McWrite for ResponseData {
|
||||||
|
type Error = String;
|
||||||
|
|
||||||
|
async fn write_stream<T: AsyncWrite + Unpin>(
|
||||||
|
&self,
|
||||||
|
stream: &mut T,
|
||||||
|
) -> Result<usize, Self::Error> {
|
||||||
|
self.json_response
|
||||||
|
.write_stream(stream)
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
impl Protocol {
|
impl Protocol {
|
||||||
pub async fn handle<T: AsyncRead + AsyncWrite + Unpin>(
|
pub async fn handle<T: AsyncRead + AsyncWrite + Unpin>(
|
||||||
stream: &mut RWStreamWithLimit<'_, T>,
|
stream: &mut RWStreamWithLimit<'_, T>,
|
||||||
@@ -18,40 +56,48 @@ impl Protocol {
|
|||||||
false
|
false
|
||||||
})?;
|
})?;
|
||||||
let string = Self::get_sample_result();
|
let string = Self::get_sample_result();
|
||||||
let mut total_size = 0;
|
let response = ResponseData {
|
||||||
let mut v = Vec::new();
|
json_response: McString::from_string(string),
|
||||||
let mut writer = BufWriter::new(&mut v);
|
};
|
||||||
|
let x = Package::Outgoing(OutgoingPackage {
|
||||||
//Package ID
|
protocol: crate::protocols::ProtocolResponseId::Status,
|
||||||
total_size += VarInt(0x00).write_stream(&mut writer).await.map_err(|x| {
|
content: OutgoingPackageContent::StatusResponse(response),
|
||||||
dbg!(x);
|
});
|
||||||
false
|
//
|
||||||
})?;
|
// let mut total_size = 0;
|
||||||
|
// let mut v = Vec::new();
|
||||||
//Status JSON
|
// let mut writer = BufWriter::new(&mut v);
|
||||||
total_size += McString::<32767>::from_string(string)
|
//
|
||||||
.write_stream(&mut writer)
|
// //Package ID
|
||||||
.await
|
// total_size += VarInt(0x00).write_stream(&mut writer).await.map_err(|x| {
|
||||||
.map_err(|x| {
|
// dbg!(x);
|
||||||
dbg!(x);
|
// false
|
||||||
false
|
// })?;
|
||||||
})?;
|
//
|
||||||
writer.flush().await.unwrap();
|
// //Status JSON
|
||||||
|
// total_size += McString::<32767>::from_string(string)
|
||||||
println!("total size: {}: {:?}", total_size, &v);
|
// .write_stream(&mut writer)
|
||||||
//Size in front
|
// .await
|
||||||
VarInt(total_size as i32)
|
// .map_err(|x| {
|
||||||
.write_stream(stream)
|
// dbg!(x);
|
||||||
.await
|
// false
|
||||||
.map_err(|x| {
|
// })?;
|
||||||
dbg!(x);
|
// writer.flush().await.unwrap();
|
||||||
false
|
//
|
||||||
})?;
|
// println!("total size: {}: {:?}", total_size, &v);
|
||||||
//actually write the content to the stream, not just a local buffer
|
// //Size in front
|
||||||
stream.write_all(&v).await.map_err(|x| {
|
// VarInt(total_size as i32)
|
||||||
dbg!(x);
|
// .write_stream(stream)
|
||||||
false
|
// .await
|
||||||
})?;
|
// .map_err(|x| {
|
||||||
|
// dbg!(x);
|
||||||
|
// false
|
||||||
|
// })?;
|
||||||
|
// //actually write the content to the stream, not just a local buffer
|
||||||
|
// stream.write_all(&v).await.map_err(|x| {
|
||||||
|
// dbg!(x);
|
||||||
|
// false
|
||||||
|
// })?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -63,7 +109,7 @@ impl Protocol {
|
|||||||
"protocol": 768
|
"protocol": 768
|
||||||
},
|
},
|
||||||
"players": {
|
"players": {
|
||||||
"max": 100,
|
"max": 1000000000,
|
||||||
"online": 5,
|
"online": 5,
|
||||||
"sample": [
|
"sample": [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
use tokio::io::{AsyncRead, AsyncWrite};
|
use tokio::io::{AsyncRead, AsyncWrite};
|
||||||
|
|
||||||
pub(crate) trait McRead {
|
pub(crate) trait McRead {
|
||||||
type Error;
|
async fn read_stream<T: AsyncRead + Unpin>(stream: &mut T) -> Result<Self, String>
|
||||||
async fn read_stream<T: AsyncRead + Unpin>(stream: &mut T) -> Result<Self, Self::Error>
|
|
||||||
where
|
where
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
}
|
}
|
||||||
@@ -21,6 +20,8 @@ pub trait McRustRepr {
|
|||||||
fn to_rs(&self) -> Self::RustRepresentation;
|
fn to_rs(&self) -> Self::RustRepresentation;
|
||||||
fn as_rs(&self) -> &Self::RustRepresentation;
|
fn as_rs(&self) -> &Self::RustRepresentation;
|
||||||
}
|
}
|
||||||
|
pub mod long;
|
||||||
|
pub mod package;
|
||||||
pub mod string;
|
pub mod string;
|
||||||
pub mod var_int;
|
pub mod var_int;
|
||||||
pub mod var_long;
|
pub mod var_long;
|
||||||
|
|||||||
49
src/types/long.rs
Normal file
49
src/types/long.rs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
use crate::types::var_int::{read_stream, VarInt};
|
||||||
|
use crate::types::{McRead, McRustRepr, McWrite};
|
||||||
|
use std::ops::Deref;
|
||||||
|
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct Long(pub i64);
|
||||||
|
impl Deref for Long {
|
||||||
|
type Target = i64;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl McWrite for Long {
|
||||||
|
type Error = std::io::Error;
|
||||||
|
|
||||||
|
async fn write_stream<T: AsyncWrite + Unpin>(
|
||||||
|
&self,
|
||||||
|
stream: &mut T,
|
||||||
|
) -> Result<usize, Self::Error>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
stream.write_i64(self.0).await?;
|
||||||
|
Ok(8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl McRead for Long {
|
||||||
|
async fn read_stream<T: AsyncRead + Unpin>(b: &mut T) -> Result<Self, String> {
|
||||||
|
Ok(Self(b.read_i64().await.map_err(|e| e.to_string())?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl McRustRepr for Long {
|
||||||
|
type RustRepresentation = i64;
|
||||||
|
|
||||||
|
fn into_rs(self) -> Self::RustRepresentation {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_rs(&self) -> Self::RustRepresentation {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_rs(&self) -> &Self::RustRepresentation {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
174
src/types/package.rs
Normal file
174
src/types/package.rs
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
use crate::protocols::{self, ProtocolId, ProtocolResponseId};
|
||||||
|
use crate::types::string::McString;
|
||||||
|
use crate::types::var_int::VarInt;
|
||||||
|
use crate::types::{McRead, McWrite};
|
||||||
|
use crate::utils::RWStreamWithLimit;
|
||||||
|
use num_traits::ToPrimitive;
|
||||||
|
use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt, BufWriter};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Package {
|
||||||
|
Incoming(IncomingPackage),
|
||||||
|
Outgoing(OutgoingPackage),
|
||||||
|
}
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct IncomingPackage {
|
||||||
|
pub(crate) protocol: ProtocolId,
|
||||||
|
pub(crate) content: IncomingPackageContent,
|
||||||
|
}
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct OutgoingPackage {
|
||||||
|
pub(crate) protocol: ProtocolResponseId,
|
||||||
|
pub(crate) content: OutgoingPackageContent,
|
||||||
|
}
|
||||||
|
impl OutgoingPackage {
|
||||||
|
pub fn empty() {}
|
||||||
|
}
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum IncomingPackageContent {
|
||||||
|
Handshake(crate::protocols::handshake::Data),
|
||||||
|
Status(crate::protocols::status::Data),
|
||||||
|
Ping(crate::protocols::ping::Data),
|
||||||
|
CustomReportDetails(crate::protocols::custom_report_details::Data),
|
||||||
|
}
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum OutgoingPackageContent {
|
||||||
|
StatusResponse(crate::protocols::status::ResponseData),
|
||||||
|
PingResponse(crate::protocols::ping::ResponseData),
|
||||||
|
}
|
||||||
|
impl McWrite for OutgoingPackageContent {
|
||||||
|
type Error = String;
|
||||||
|
|
||||||
|
async fn write_stream<T: AsyncWrite + Unpin>(
|
||||||
|
&self,
|
||||||
|
stream: &mut T,
|
||||||
|
) -> Result<usize, Self::Error>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
OutgoingPackageContent::StatusResponse(x) => x.write_stream(stream).await,
|
||||||
|
OutgoingPackageContent::PingResponse(x) => x.write_stream(stream).await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl McWrite for OutgoingPackage {
|
||||||
|
type Error = String;
|
||||||
|
|
||||||
|
async fn write_stream<T: AsyncWrite + Unpin>(
|
||||||
|
&self,
|
||||||
|
stream: &mut T,
|
||||||
|
) -> Result<usize, Self::Error>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let id = self.protocol;
|
||||||
|
let mut total_size = 0;
|
||||||
|
|
||||||
|
//write the content to a local buffer first to determine size
|
||||||
|
let mut v = Vec::new();
|
||||||
|
println!("total size: {}: {:?}", total_size, &v);
|
||||||
|
|
||||||
|
let mut writer = BufWriter::new(&mut v);
|
||||||
|
total_size +=
|
||||||
|
VarInt(ToPrimitive::to_i32(&id).expect("All the ids should be hard coded to work..."))
|
||||||
|
.write_stream(&mut writer)
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
writer.flush().await.map_err(|e| e.to_string())?;
|
||||||
|
println!("total size: {}: {:?}", total_size, &v);
|
||||||
|
|
||||||
|
let mut writer = BufWriter::new(&mut v);
|
||||||
|
total_size += self.content.write_stream(&mut writer).await?;
|
||||||
|
writer.flush().await.map_err(|e| e.to_string())?;
|
||||||
|
println!("total size: {}: {:?}", total_size, &v);
|
||||||
|
|
||||||
|
// //Size in front
|
||||||
|
let x = VarInt(total_size as i32)
|
||||||
|
.write_stream(stream)
|
||||||
|
.await
|
||||||
|
.map_err(|x| {
|
||||||
|
dbg!(&x);
|
||||||
|
format!("Error writing the size: {:?}", x).to_string()
|
||||||
|
})?;
|
||||||
|
// //actually write the content to the stream, not just a local buffer
|
||||||
|
stream.write_all(&v).await.map_err(|x| {
|
||||||
|
dbg!(&x);
|
||||||
|
format!("Error writing the bytes: {:?}", x).to_string()
|
||||||
|
})?;
|
||||||
|
stream.flush().await.map_err(|e| e.to_string())?;
|
||||||
|
Ok(total_size + x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl IncomingPackage {
|
||||||
|
async fn answer<T: AsyncRead + AsyncWrite + Unpin>(
|
||||||
|
&self,
|
||||||
|
stream: &mut RWStreamWithLimit<'_, T>,
|
||||||
|
) -> Result<(), bool> {
|
||||||
|
let answer = match (&self.protocol, &self.content) {
|
||||||
|
(ProtocolId::Status, _) => Some(OutgoingPackage {
|
||||||
|
protocol: ProtocolResponseId::Status,
|
||||||
|
content: OutgoingPackageContent::StatusResponse(
|
||||||
|
protocols::status::ResponseData::default(),
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
(ProtocolId::Ping, IncomingPackageContent::Ping(ping_data)) => Some(OutgoingPackage {
|
||||||
|
protocol: ProtocolResponseId::Ping,
|
||||||
|
content: OutgoingPackageContent::PingResponse(protocols::ping::ResponseData {
|
||||||
|
timespan: ping_data.timespan,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
(ProtocolId::Ping, _) => unreachable!(),
|
||||||
|
(ProtocolId::CustomReportDetails, _) => None,
|
||||||
|
};
|
||||||
|
if let Some(outgoing_package) = answer {
|
||||||
|
outgoing_package.write_stream(stream).await.map_err(|e| {
|
||||||
|
dbg!(e);
|
||||||
|
false
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Package {
|
||||||
|
pub async fn handle<T: AsyncRead + AsyncWrite + Unpin>(
|
||||||
|
protocol_id: ProtocolId,
|
||||||
|
stream: &mut RWStreamWithLimit<'_, T>,
|
||||||
|
) -> Result<(), bool> {
|
||||||
|
let incoming_content = read_data(protocol_id, stream).await.map_err(|e| {
|
||||||
|
dbg!(e);
|
||||||
|
true
|
||||||
|
})?;
|
||||||
|
let incoming = IncomingPackage {
|
||||||
|
protocol: protocol_id,
|
||||||
|
content: incoming_content,
|
||||||
|
};
|
||||||
|
incoming.answer(stream).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn read_data<T: AsyncRead + AsyncWrite + Unpin>(
|
||||||
|
protocol_id: ProtocolId,
|
||||||
|
stream: &mut RWStreamWithLimit<'_, T>,
|
||||||
|
) -> Result<IncomingPackageContent, String> {
|
||||||
|
Ok(match protocol_id {
|
||||||
|
ProtocolId::Status => {
|
||||||
|
IncomingPackageContent::Status(protocols::status::Data::read_stream(stream).await?)
|
||||||
|
}
|
||||||
|
ProtocolId::Ping => {
|
||||||
|
IncomingPackageContent::Ping(protocols::ping::Data::read_stream(stream).await?)
|
||||||
|
}
|
||||||
|
ProtocolId::CustomReportDetails => {
|
||||||
|
// return Err("Not implemented".to_string());
|
||||||
|
let x = IncomingPackageContent::CustomReportDetails(
|
||||||
|
protocols::custom_report_details::Data::read_stream(stream).await?,
|
||||||
|
);
|
||||||
|
stream.discard_unread().await.map_err(|e| {
|
||||||
|
dbg!(e);
|
||||||
|
"Could not discard unused stuff"
|
||||||
|
})?;
|
||||||
|
x
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -3,13 +3,15 @@ use crate::types::{McRead, McRustRepr, McWrite};
|
|||||||
|
|
||||||
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub struct McString<const MAX_SIZE: usize> {
|
pub struct McString<const MAX_SIZE: usize> {
|
||||||
pub value: String,
|
pub value: String,
|
||||||
}
|
}
|
||||||
impl<const MAX_SIZE: usize> McString<MAX_SIZE> {
|
impl<const MAX_SIZE: usize> McString<MAX_SIZE> {
|
||||||
pub fn measure_size(s: &str) -> usize {
|
pub fn measure_size(s: &str) -> usize {
|
||||||
// 3. UTF-8 encoded byte length
|
// 3. UTF-8 encoded byte length
|
||||||
let utf8_len = s.bytes().len();
|
let utf8_len = s.len();
|
||||||
|
// let utf8_len = s.bytes().len();
|
||||||
|
|
||||||
// 5. Calculate total length (including VarInt prefix)
|
// 5. Calculate total length (including VarInt prefix)
|
||||||
let varint_size = VarInt(utf8_len as i32).get_size();
|
let varint_size = VarInt(utf8_len as i32).get_size();
|
||||||
@@ -17,36 +19,38 @@ impl<const MAX_SIZE: usize> McString<MAX_SIZE> {
|
|||||||
//TODO: This is not allowed
|
//TODO: This is not allowed
|
||||||
}
|
}
|
||||||
// println!("strlen: {}+({}?{})", varint_size, utf8_len, utf16_len);
|
// println!("strlen: {}+({}?{})", varint_size, utf8_len, utf16_len);
|
||||||
varint_size + utf8_len
|
// varint_size +
|
||||||
|
utf8_len
|
||||||
}
|
}
|
||||||
pub fn from_string(s: String) -> Self {
|
pub fn from_string(s: String) -> Self {
|
||||||
Self { value: s }
|
Self { value: s }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<const MAX_SIZE: usize> McRead for McString<MAX_SIZE> {
|
impl<const MAX_SIZE: usize> McRead for McString<MAX_SIZE> {
|
||||||
type Error = ();
|
async fn read_stream<T: AsyncRead + Unpin>(b: &mut T) -> Result<Self, String>
|
||||||
|
|
||||||
async fn read_stream<T: AsyncRead + Unpin>(b: &mut T) -> Result<Self, Self::Error>
|
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
let max_size = VarInt::read_stream(b).await.map_err(|x| {
|
let max_size = VarInt::read_stream(b).await.map_err(|x| {
|
||||||
dbg!(x);
|
dbg!(x);
|
||||||
|
"could not read size"
|
||||||
})?;
|
})?;
|
||||||
let size = *max_size as usize;
|
let size = *max_size as usize;
|
||||||
println!("Reading string of length: {}", size);
|
println!("Reading string of length: {}", size);
|
||||||
|
|
||||||
// Check if the size exceeds the maximum allowed length (n)
|
// Check if the size exceeds the maximum allowed length (n)
|
||||||
if size > (MAX_SIZE * 3) + 3 {
|
if size > (MAX_SIZE * 3) + 3 {
|
||||||
return Err(()); // Or a more specific error type
|
return Err("Too big string".to_string()); // Or a more specific error type
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut bytes = vec![0u8; size];
|
let mut bytes = vec![0u8; size];
|
||||||
let actual_size = b.read(&mut bytes).await.map_err(|x| {
|
let actual_size = b.read(&mut bytes).await.map_err(|x| {
|
||||||
dbg!(x);
|
dbg!(x);
|
||||||
|
"Error reading"
|
||||||
})?;
|
})?;
|
||||||
let value = String::from_utf8(bytes).map_err(|x| {
|
let value = String::from_utf8(bytes).map_err(|x| {
|
||||||
dbg!(x);
|
dbg!(x);
|
||||||
|
"Error parsing UTF8 string"
|
||||||
})?;
|
})?;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
size, actual_size,
|
size, actual_size,
|
||||||
|
|||||||
@@ -27,8 +27,7 @@ impl McWrite for VarInt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl McRead for VarInt {
|
impl McRead for VarInt {
|
||||||
type Error = String;
|
async fn read_stream<T: AsyncRead + Unpin>(b: &mut T) -> Result<Self, String> {
|
||||||
async fn read_stream<T: AsyncRead + Unpin>(b: &mut T) -> Result<Self, Self::Error> {
|
|
||||||
let value = read_stream(b, 32).await? as i32;
|
let value = read_stream(b, 32).await? as i32;
|
||||||
Ok(Self(value))
|
Ok(Self(value))
|
||||||
}
|
}
|
||||||
@@ -81,14 +80,13 @@ async fn write_varint<W: AsyncWrite + Unpin>(
|
|||||||
loop {
|
loop {
|
||||||
written += 1;
|
written += 1;
|
||||||
if (value & !SEGMENT_BITS) == 0 {
|
if (value & !SEGMENT_BITS) == 0 {
|
||||||
writer.write_u8(value as u8).await.unwrap();
|
writer.write_u8(value as u8).await?;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
writer
|
writer
|
||||||
.write_u8(((value & SEGMENT_BITS) | CONTINUE_BIT) as u8)
|
.write_u8(((value & SEGMENT_BITS) | CONTINUE_BIT) as u8)
|
||||||
.await
|
.await?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
value = (value as u32 >> 7) as i32; // Simulate Java's >>>
|
value = (value as u32 >> 7) as i32; // Simulate Java's >>>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,8 +34,7 @@ impl McWrite for VarLong {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl McRead for VarLong {
|
impl McRead for VarLong {
|
||||||
type Error = String;
|
async fn read_stream<T: AsyncRead + Unpin>(b: &mut T) -> Result<Self, String> {
|
||||||
async fn read_stream<T: AsyncRead + Unpin>(b: &mut T) -> Result<Self, Self::Error> {
|
|
||||||
let value = crate::types::var_int::read_stream(b, 64).await? as i64;
|
let value = crate::types::var_int::read_stream(b, 64).await? as i64;
|
||||||
Ok(Self(value))
|
Ok(Self(value))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user