mirror of
https://github.com/OMGeeky/mc-server-rs-sample.git
synced 2025-12-26 17:02:27 +01:00
try to fix some status response stuff
This commit is contained in:
46
Cargo.lock
generated
46
Cargo.lock
generated
@@ -123,6 +123,12 @@ version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.162"
|
||||
@@ -145,6 +151,8 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tokio-util",
|
||||
@@ -274,12 +282,50 @@ version = "0.1.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.215"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.215"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.132"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.2"
|
||||
|
||||
@@ -10,3 +10,5 @@ tokio = { version = "1.41.1", features = ["rt", "rt-multi-thread", "macros", "fu
|
||||
|
||||
tokio-util = { version = "0.7.0", features = ["full"] }
|
||||
tokio-stream = "0.1"
|
||||
serde = "1.0"
|
||||
serde_json = "1.0"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#![allow(unused)]
|
||||
pub mod protocols;
|
||||
pub mod types;
|
||||
pub mod utils;
|
||||
@@ -5,10 +6,10 @@ pub mod utils;
|
||||
use crate::types::string::McString;
|
||||
use crate::types::var_int::VarInt;
|
||||
use crate::types::{McRead, McRustRepr};
|
||||
use crate::utils::RWStreamWithLimit;
|
||||
use crate::utils::{MyAsyncReadExt, RWStreamWithLimit};
|
||||
use num_derive::FromPrimitive;
|
||||
use num_traits::{FromPrimitive, ToPrimitive};
|
||||
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite};
|
||||
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
||||
use tokio::net::TcpStream;
|
||||
|
||||
#[tokio::main]
|
||||
@@ -38,6 +39,7 @@ enum ConnectionState {
|
||||
Status = 1,
|
||||
Login = 2,
|
||||
Transfer = 3,
|
||||
///Internal use
|
||||
Closed = -1,
|
||||
}
|
||||
struct Connection {
|
||||
@@ -87,6 +89,7 @@ impl Connection {
|
||||
}
|
||||
Err(e) => {
|
||||
self.connection_state = ConnectionState::Closed;
|
||||
dbg!(&self.tcp_stream.shutdown().await);
|
||||
println!("Got an error during package handling: {e}");
|
||||
}
|
||||
}
|
||||
@@ -106,7 +109,7 @@ impl Connection {
|
||||
.await
|
||||
.map_err(|_| "Could not read string".to_string())?;
|
||||
println!("address: '{}'", address.as_rs());
|
||||
stream.read_exact(&mut [0, 2]).await.unwrap(); //server port. Unused
|
||||
stream.discard(2).await.unwrap(); //server port. Unused
|
||||
let next_state_id = VarInt::read_stream(stream).await?;
|
||||
println!("next state: {}", next_state_id.as_rs());
|
||||
let next_state = FromPrimitive::from_i32(next_state_id.to_rs());
|
||||
|
||||
@@ -3,22 +3,23 @@ use num_derive::FromPrimitive;
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
|
||||
#[derive(FromPrimitive)]
|
||||
pub enum Protocols {
|
||||
pub enum Protocol {
|
||||
Status = 0x00,
|
||||
Ping = 0x01,
|
||||
CustomReportDetails = 0x7a,
|
||||
}
|
||||
pub async fn handle<T: AsyncRead + AsyncWrite + Unpin>(
|
||||
protocol: Protocols,
|
||||
protocol: Protocol,
|
||||
stream: &mut RWStreamWithLimit<'_, T>,
|
||||
// bytes_left_in_package: &mut i32,
|
||||
) -> Result<(), bool> {
|
||||
match protocol {
|
||||
Protocols::Status => status::Protocol::handle(stream).await?,
|
||||
Protocols::Ping => {}
|
||||
Protocols::CustomReportDetails => custom_report_details::Protocol::handle(stream).await?,
|
||||
Protocol::Status => status::Protocol::handle(stream).await?,
|
||||
Protocol::Ping => ping::Protocol::handle(stream).await?,
|
||||
Protocol::CustomReportDetails => custom_report_details::Protocol::handle(stream).await?,
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
mod custom_report_details;
|
||||
mod ping;
|
||||
mod status;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::types::string::McString;
|
||||
use crate::types::var_int::VarInt;
|
||||
use crate::types::McRead;
|
||||
use crate::utils::RWStreamWithLimit;
|
||||
@@ -10,33 +11,22 @@ impl Protocol {
|
||||
stream: &mut RWStreamWithLimit<'_, T>,
|
||||
// bytes_left_in_package: &mut i32,
|
||||
) -> Result<(), bool> {
|
||||
println!("Some custom report detail stuff...");
|
||||
let count = VarInt::read_stream(stream).await.map_err(|x| {
|
||||
dbg!(x);
|
||||
true
|
||||
})?;
|
||||
dbg!(&count);
|
||||
let string_size = VarInt::read_stream(stream).await.map_err(|x| {
|
||||
dbg!(x);
|
||||
true
|
||||
})?;
|
||||
dbg!(&string_size);
|
||||
stream.discard_unread().await.map_err(|x| {
|
||||
dbg!(x);
|
||||
true
|
||||
})?;
|
||||
// for i in 0..*count {
|
||||
// let title = McString::read_stream(stream).await.map_err(|x| {
|
||||
// dbg!(x);
|
||||
// })?;
|
||||
// let description = McString::read_stream(stream).await.map_err(|x| {
|
||||
// dbg!(x);
|
||||
// })?;
|
||||
// println!(
|
||||
// "Read title & description fo some custom report ({i}): {}\n{}",
|
||||
// title.as_rs(),
|
||||
// description.as_rs()
|
||||
// );
|
||||
// }
|
||||
Ok(())
|
||||
for i in 0..*count {
|
||||
McString::<128>::read_stream(stream).await.map_err(|x| {
|
||||
dbg!(x);
|
||||
true
|
||||
})?;
|
||||
McString::<4096>::read_stream(stream).await.map_err(|x| {
|
||||
dbg!(x);
|
||||
true
|
||||
})?;
|
||||
}
|
||||
Err(true)
|
||||
}
|
||||
}
|
||||
|
||||
29
src/protocols/ping.rs
Normal file
29
src/protocols/ping.rs
Normal file
@@ -0,0 +1,29 @@
|
||||
use crate::types::var_int::VarInt;
|
||||
use crate::types::var_long::VarLong;
|
||||
use crate::types::{McRead, McWrite};
|
||||
use crate::utils::RWStreamWithLimit;
|
||||
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
||||
|
||||
pub struct Protocol {}
|
||||
|
||||
impl Protocol {
|
||||
pub async fn handle<T: AsyncRead + AsyncWrite + Unpin>(
|
||||
stream: &mut RWStreamWithLimit<'_, T>,
|
||||
) -> Result<(), bool> {
|
||||
println!("Ping");
|
||||
let v = stream.read_i64().await.map_err(|e| {
|
||||
dbg!(e);
|
||||
false
|
||||
})?;
|
||||
VarInt(0x01).write_stream(stream).await.map_err(|x| {
|
||||
dbg!(x);
|
||||
false
|
||||
})?;
|
||||
stream.write_i64(v).await.map_err(|e| {
|
||||
dbg!(e);
|
||||
false
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,58 +1,83 @@
|
||||
use crate::types::string::McString;
|
||||
use crate::types::var_int::VarInt;
|
||||
use crate::types::var_long::VarLong;
|
||||
use crate::types::McWrite;
|
||||
use crate::utils::RWStreamWithLimit;
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
use serde_json::json;
|
||||
use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt, BufWriter};
|
||||
|
||||
pub struct Protocol {}
|
||||
|
||||
impl Protocol {
|
||||
pub async fn handle<T: AsyncRead + AsyncWrite + Unpin>(
|
||||
stream: &mut RWStreamWithLimit<'_, T>,
|
||||
// bytes_left_in_package: &mut i32,
|
||||
) -> Result<(), bool> {
|
||||
println!("Status");
|
||||
VarInt(0x01).write_stream(stream).await.map_err(|x| {
|
||||
stream.discard_unread().await.map_err(|x| {
|
||||
dbg!(x);
|
||||
false
|
||||
})?;
|
||||
let string = Self::get_sample_result();
|
||||
let mut total_size = 0;
|
||||
let mut v = Vec::new();
|
||||
let mut writer = BufWriter::new(&mut v);
|
||||
|
||||
//Package ID
|
||||
total_size += VarInt(0x00).write_stream(&mut writer).await.map_err(|x| {
|
||||
dbg!(x);
|
||||
false
|
||||
})?;
|
||||
|
||||
McString::<32767>::from_string(Self::get_sample_result())
|
||||
//Status JSON
|
||||
total_size += McString::<32767>::from_string(string)
|
||||
.write_stream(&mut writer)
|
||||
.await
|
||||
.map_err(|x| {
|
||||
dbg!(x);
|
||||
false
|
||||
})?;
|
||||
writer.flush().await.unwrap();
|
||||
|
||||
println!("total size: {}: {:?}", total_size, &v);
|
||||
//Size in front
|
||||
VarInt(total_size as i32)
|
||||
.write_stream(stream)
|
||||
.await
|
||||
.map_err(|x| {
|
||||
dbg!(x);
|
||||
false
|
||||
})?;
|
||||
// stream.discard_unread().await.map_err(|x| {
|
||||
// dbg!(x);
|
||||
// false
|
||||
// })?;
|
||||
// *bytes_left_in_package = 0;
|
||||
//actually write the content to the stream, not just a local buffer
|
||||
stream.write_all(&v).await.map_err(|x| {
|
||||
dbg!(x);
|
||||
false
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_sample_result() -> String {
|
||||
"{
|
||||
\"version\": {
|
||||
\"name\": \"1.21.2\",
|
||||
\"protocol\": 768
|
||||
json!({
|
||||
"version": {
|
||||
"name": "1.21.2",
|
||||
"protocol": 768
|
||||
},
|
||||
\"players\": {
|
||||
\"max\": 100,
|
||||
\"online\": 5,
|
||||
\"sample\": [
|
||||
"players": {
|
||||
"max": 100,
|
||||
"online": 5,
|
||||
"sample": [
|
||||
{
|
||||
\"name\": \"thinkofdeath\",
|
||||
\"id\": \"4566e69f-c907-48ee-8d71-d7ba5aa00d20\"
|
||||
}
|
||||
]
|
||||
"name": "thinkofdeath",
|
||||
"id": "4566e69f-c907-48ee-8d71-d7ba5aa00d20",
|
||||
},
|
||||
],
|
||||
},
|
||||
\"description\": {
|
||||
\"text\": \"Hello, world!\"
|
||||
"description": {
|
||||
"text": "Hello, world!"
|
||||
},
|
||||
\"favicon\": \"data:image/png;base64,<data>\",
|
||||
\"enforcesSecureChat\": false
|
||||
}"
|
||||
// "favicon": "data:image/png;base64,<data>",
|
||||
"enforcesSecureChat": false,
|
||||
})
|
||||
.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,17 @@ pub struct McString<const MAX_SIZE: usize> {
|
||||
pub value: String,
|
||||
}
|
||||
impl<const MAX_SIZE: usize> McString<MAX_SIZE> {
|
||||
fn measure_size(s: &str) -> usize {
|
||||
s.len()
|
||||
pub fn measure_size(s: &str) -> usize {
|
||||
// 3. UTF-8 encoded byte length
|
||||
let utf8_len = s.bytes().len();
|
||||
|
||||
// 5. Calculate total length (including VarInt prefix)
|
||||
let varint_size = VarInt(utf8_len as i32).get_size();
|
||||
if varint_size > 3 {
|
||||
//TODO: This is not allowed
|
||||
}
|
||||
// println!("strlen: {}+({}?{})", varint_size, utf8_len, utf16_len);
|
||||
varint_size + utf8_len
|
||||
}
|
||||
pub fn from_string(s: String) -> Self {
|
||||
Self { value: s }
|
||||
@@ -25,6 +34,7 @@ impl<const MAX_SIZE: usize> McRead for McString<MAX_SIZE> {
|
||||
dbg!(x);
|
||||
})?;
|
||||
let size = *max_size as usize;
|
||||
println!("Reading string of length: {}", size);
|
||||
|
||||
// Check if the size exceeds the maximum allowed length (n)
|
||||
if size > (MAX_SIZE * 3) + 3 {
|
||||
@@ -35,10 +45,14 @@ impl<const MAX_SIZE: usize> McRead for McString<MAX_SIZE> {
|
||||
let actual_size = b.read(&mut bytes).await.map_err(|x| {
|
||||
dbg!(x);
|
||||
})?;
|
||||
assert_eq!(size, actual_size);
|
||||
let value = String::from_utf8(bytes).map_err(|x| {
|
||||
dbg!(x);
|
||||
})?;
|
||||
assert_eq!(
|
||||
size, actual_size,
|
||||
"Did not read all that was to read {}",
|
||||
value
|
||||
);
|
||||
Ok(Self { value })
|
||||
}
|
||||
}
|
||||
@@ -54,10 +68,12 @@ impl<const MAX_SIZE: usize> McWrite for McString<MAX_SIZE> {
|
||||
{
|
||||
let buf = self.value.as_bytes();
|
||||
let length = Self::measure_size(&self.value);
|
||||
VarInt(length as i32).write_stream(stream).await?;
|
||||
|
||||
println!("string length: {}", length);
|
||||
let length_var_int = VarInt(length as i32);
|
||||
let written = length_var_int.write_stream(stream).await?;
|
||||
println!("Writing String to stream: '{}'", self.value);
|
||||
stream.write_all(buf).await?;
|
||||
Ok(length)
|
||||
Ok(buf.len() + written)
|
||||
}
|
||||
}
|
||||
impl<const MAX_SIZE: usize> McRustRepr for McString<MAX_SIZE> {
|
||||
|
||||
18
src/utils.rs
18
src/utils.rs
@@ -1,3 +1,4 @@
|
||||
use std::cmp::min;
|
||||
use std::io::ErrorKind;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
@@ -8,6 +9,23 @@ pub struct RWStreamWithLimit<'a, T: AsyncRead + AsyncWrite> {
|
||||
read_bytes_left: usize,
|
||||
}
|
||||
|
||||
impl<'a, T: AsyncRead + AsyncWrite + Unpin> RWStreamWithLimit<'a, T> {
|
||||
pub(crate) async fn discard(&mut self, bytes: usize) -> std::io::Result<usize> {
|
||||
let bytes = min(bytes, self.read_bytes_left);
|
||||
let read = self.stream.read_exact(&mut vec![0; bytes]).await?;
|
||||
self.read_bytes_left -= read;
|
||||
Ok(read)
|
||||
}
|
||||
}
|
||||
pub(crate) trait MyAsyncReadExt {
|
||||
async fn discard(&mut self, bytes: usize) -> std::io::Result<usize>;
|
||||
}
|
||||
impl<T: AsyncRead + Unpin> MyAsyncReadExt for T {
|
||||
async fn discard(&mut self, bytes: usize) -> std::io::Result<usize> {
|
||||
self.read_exact(&mut vec![0; bytes]).await
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: AsyncRead + AsyncWrite + Unpin> RWStreamWithLimit<'a, T> {
|
||||
pub(crate) fn new(stream: &'a mut T, read_limit: usize) -> Self {
|
||||
Self {
|
||||
|
||||
Reference in New Issue
Block a user