feat: move the packets library over to use async

This commit is contained in:
Tamipes 2025-11-26 00:37:32 +01:00
parent 79ffeafc29
commit b75eec70e0
9 changed files with 163 additions and 71 deletions

13
Cargo.lock generated
View file

@ -915,6 +915,15 @@ version = "0.4.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
[[package]]
name = "matchers"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
dependencies = [
"regex-automata",
]
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.7.6" version = "2.7.6"
@ -1731,10 +1740,14 @@ version = "0.3.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5"
dependencies = [ dependencies = [
"matchers",
"nu-ansi-term", "nu-ansi-term",
"once_cell",
"regex-automata",
"sharded-slab", "sharded-slab",
"smallvec", "smallvec",
"thread_local", "thread_local",
"tracing",
"tracing-core", "tracing-core",
"tracing-log", "tracing-log",
] ]

View file

@ -19,7 +19,7 @@ tokio-stream = { version = "0.1.9", features = ["net"] }
# Error tracing? # Error tracing?
tracing = "0.1.36" tracing = "0.1.36"
tracing-subscriber = "0.3.17" tracing-subscriber = {version = "0.3.17", features = ["env-filter"]}
# Needed to parse data to yaml in kubectl # Needed to parse data to yaml in kubectl
serde = "1.0.130" serde = "1.0.130"

View file

@ -1,9 +1,13 @@
//! This is a simple imitation of the basic functionality of kubectl: //! This is a simple imitation of the basic functionality of kubectl:
//! kubectl {get, delete, apply, watch, edit} <resource> [name] //! kubectl {get, delete, apply, watch, edit} <resource> [name]
//! with labels and namespace selectors supported. //! with labels and namespace selectors supported.
use std::sync::Arc; use std::{net::SocketAddr, sync::Arc};
use tokio::net::{TcpListener, TcpStream}; use tokio::net::{TcpListener, TcpStream};
use tracing::instrument;
use tracing_subscriber::{prelude::*, EnvFilter};
use crate::packets::Packet;
mod KubeCache; mod KubeCache;
mod packets; mod packets;
@ -11,31 +15,59 @@ mod types;
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
tracing_subscriber::fmt::init(); // tracing_subscriber::fmt::init();
let fmt_layer = tracing_subscriber::fmt::layer()
.with_target(false)
.with_level(true);
let filter_layer = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")); // default to INFO
tracing_subscriber::registry()
.with(fmt_layer)
.with(filter_layer)
.init();
let commit_hash: &'static str = env!("COMMIT_HASH"); let commit_hash: &'static str = env!("COMMIT_HASH");
tracing::info!("COMMIT_HASH: {}", commit_hash); tracing::info!("COMMIT_HASH: {}", commit_hash);
let cache = KubeCache::Cache::create().unwrap(); let cache = KubeCache::Cache::create().unwrap();
let arcCache = Arc::new(cache); let arc_cache = Arc::new(cache);
tracing::info!("kube api initialized"); tracing::info!("kube api initialized");
let mut listener = TcpListener::bind("0.0.0.0:25565").await.unwrap(); let listener = TcpListener::bind("0.0.0.0:25565").await.unwrap();
tracing::info!("tcp server started"); tracing::info!("tcp server started");
loop { loop {
let (socket, _) = listener.accept().await.unwrap(); let (socket, addr) = listener.accept().await.unwrap();
let acc = arcCache.clone(); let acc = arc_cache.clone();
tokio::spawn(async move { tokio::spawn(async move {
if let Err(e) = process_socket(socket, acc).await { if let Err(e) = process_socket(socket, addr, acc).await {
tracing::error!("socket error: {e:?}"); tracing::error!("socket error: {e:?}");
} }
}); });
} }
} }
async fn process_socket(stream: TcpStream, cache: Arc<KubeCache::Cache>) -> Result<(), ()> { #[instrument(level = "trace", skip(cache, stream))]
async fn process_socket(
mut stream: TcpStream,
addr: SocketAddr,
cache: Arc<KubeCache::Cache>,
) -> Result<(), ()> {
tracing::info!(
addr = format!("{}:{}", addr.ip().to_string(), addr.port().to_string()),
"Client connected"
);
let client_packet = match Packet::parse(&mut stream).await {
Some(x) => x,
None => {
tracing::trace!("Client HANDSHAKE -> bad packet; Disconnecting...");
return Ok(());
}
};
tracing::info!(
addr = format!("{}:{}", addr.ip().to_string(), addr.port().to_string()),
"Client disconnected"
);
todo!() todo!()
} }
// ----- Debug tools ----- // ----- Debug tools -----

View file

@ -1,4 +1,4 @@
use std::io::Write; use tokio::{io::AsyncWriteExt, net::TcpStream};
use crate::{ use crate::{
packets::{Packet, SendPacket}, packets::{Packet, SendPacket},
@ -13,19 +13,18 @@ pub struct Disconnect {
} }
impl Disconnect { impl Disconnect {
pub fn parse(packet: Packet) -> Option<Disconnect> { pub async fn parse(packet: Packet) -> Option<Disconnect> {
let mut reader = packet.data.into_iter();
Some(Disconnect { Some(Disconnect {
all: packet.all, all: packet.all,
reason: VarString::parse(&mut reader)?, reason: VarString::parse(&mut packet.data.clone()).await?,
}) })
} }
pub fn get_string(&self) -> String { pub fn get_string(&self) -> String {
self.reason.get_value() self.reason.get_value()
} }
pub fn set_reason(reason: String) -> Option<Disconnect> { pub async fn set_reason(reason: String) -> Option<Disconnect> {
let vec = VarString::from(reason).move_data()?; let vec = VarString::from(reason).move_data()?;
Disconnect::parse(Packet::from_bytes(0, vec)?) Disconnect::parse(Packet::from_bytes(0, vec)?).await
} }
pub fn get_all(&self) -> Vec<u8> { pub fn get_all(&self) -> Vec<u8> {
self.all.clone() self.all.clone()
@ -33,9 +32,9 @@ impl Disconnect {
} }
impl SendPacket for Disconnect { impl SendPacket for Disconnect {
fn send_packet(&self, stream: &mut std::net::TcpStream) -> std::io::Result<()> { async fn send_packet(&self, stream: &mut TcpStream) -> std::io::Result<()> {
stream.write_all(&self.all)?; stream.write_all(&self.all).await?;
stream.flush()?; stream.flush().await?;
Ok(()) Ok(())
} }
} }

View file

@ -1,7 +1,8 @@
use std::{collections::HashMap, io::Write}; use std::collections::HashMap;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use serde_json::Value; use serde_json::Value;
use tokio::{io::AsyncWriteExt, net::TcpStream};
use crate::{ use crate::{
packets::{Packet, SendPacket}, packets::{Packet, SendPacket},
@ -117,11 +118,10 @@ pub struct StatusResponse {
} }
impl StatusResponse { impl StatusResponse {
pub fn parse(packet: Packet) -> Option<StatusResponse> { pub async fn parse(packet: Packet) -> Option<StatusResponse> {
let mut reader = packet.data.into_iter();
Some(StatusResponse { Some(StatusResponse {
all: packet.all, all: packet.all,
json: VarString::parse(&mut reader)?, json: VarString::parse(&mut packet.data.clone()).await?,
}) })
} }
pub fn get_string(&self) -> String { pub fn get_string(&self) -> String {
@ -137,9 +137,11 @@ impl StatusResponse {
} }
None None
} }
pub fn set_json(json: Box<dyn StatusTrait>) -> StatusResponse { pub async fn set_json(json: Box<dyn StatusTrait>) -> StatusResponse {
let vec = VarString::from(json.get_string()).move_data().unwrap(); let vec = VarString::from(json.get_string()).move_data().unwrap();
StatusResponse::parse(Packet::from_bytes(0, vec).unwrap()).unwrap() StatusResponse::parse(Packet::from_bytes(0, vec).unwrap())
.await
.unwrap()
} }
pub fn get_all(&self) -> Vec<u8> { pub fn get_all(&self) -> Vec<u8> {
self.all.clone() self.all.clone()
@ -147,9 +149,9 @@ impl StatusResponse {
} }
impl SendPacket for StatusResponse { impl SendPacket for StatusResponse {
fn send_packet(&self, stream: &mut std::net::TcpStream) -> std::io::Result<()> { async fn send_packet(&self, stream: &mut TcpStream) -> std::io::Result<()> {
stream.write_all(&self.all)?; stream.write_all(&self.all).await?;
stream.flush()?; stream.flush().await?;
Ok(()) Ok(())
} }
} }

View file

@ -1,7 +1,10 @@
use std::{ // use std::io::{self, Read, Write};
io::{self, Read, Write},
net::TcpStream, use tokio::io;
}; use tokio::io::AsyncReadExt;
use tokio::io::AsyncWriteExt;
use tokio::net::TcpStream;
use tracing::instrument;
use crate::types::VarInt; use crate::types::VarInt;
pub mod clientbound; pub mod clientbound;
@ -15,12 +18,12 @@ pub struct Packet {
pub all: Vec<u8>, pub all: Vec<u8>,
} }
pub trait SendPacket { pub trait SendPacket {
fn send_packet(&self, stream: &mut TcpStream) -> io::Result<()>; async fn send_packet(&self, stream: &mut TcpStream) -> io::Result<()>;
} }
impl SendPacket for Packet { impl SendPacket for Packet {
fn send_packet(&self, stream: &mut TcpStream) -> io::Result<()> { async fn send_packet(&self, stream: &mut TcpStream) -> io::Result<()> {
stream.write_all(&self.all)?; stream.write_all(&self.all).await?;
Ok(()) Ok(())
} }
} }
@ -53,14 +56,14 @@ impl Packet {
all, all,
}) })
} }
pub fn parse(buf: &mut TcpStream) -> Option<Packet> { #[instrument(level = "trace")]
let bytes_iter = &mut buf.bytes().into_iter().map(|x| x.unwrap()); pub async fn parse(buf: &mut TcpStream) -> Option<Packet> {
let length = VarInt::parse(bytes_iter)?; let length = VarInt::parse(buf).await?;
// println!("---length: {length}"); tracing::trace!(length = length.get_int());
let id = match VarInt::parse(bytes_iter) { let id = match VarInt::parse(buf).await {
Some(x) => x, Some(x) => x,
None => { None => {
println!("Packet id problem(it was None)! REEEEEEEEEEEEEEEEEEEE"); tracing::error!("Packet id problem(it was None)! REEEEEEEEEEEEEEEEEEEE");
panic!(); panic!();
// return None; // return None;
} }
@ -71,7 +74,7 @@ impl Packet {
} }
let mut data: Vec<u8> = vec![0; length.get_int() as usize - id.get_data().len()]; let mut data: Vec<u8> = vec![0; length.get_int() as usize - id.get_data().len()];
match buf.read_exact(&mut data) { match buf.read_exact(&mut data).await {
Ok(_) => { Ok(_) => {
// data_id.append(&mut data.clone()); // data_id.append(&mut data.clone());
// data_length.append(&mut data_id); // data_length.append(&mut data_id);

View file

@ -1,6 +1,4 @@
use std::io::Write; use tokio::{io::AsyncWriteExt, net::TcpStream};
use nix::NixPath;
use crate::{ use crate::{
packets::{Packet, SendPacket}, packets::{Packet, SendPacket},
@ -17,12 +15,12 @@ pub struct Handshake {
} }
impl Handshake { impl Handshake {
pub fn parse(packet: Packet) -> Option<Handshake> { pub async fn parse(packet: Packet) -> Option<Handshake> {
let mut reader = packet.data.clone().into_iter(); let mut reader = packet.data.clone();
let protocol_version = VarInt::parse(&mut reader)?; let protocol_version = VarInt::parse(&mut reader).await?;
let server_address = VarString::parse(&mut reader)?; let server_address = VarString::parse(&mut reader).await?;
let server_port = UShort::parse(&mut reader)?; let server_port = UShort::parse(&mut reader).await?;
let next_state = VarInt::parse(&mut reader)?; let next_state = VarInt::parse(&mut reader).await?;
Some(Handshake { Some(Handshake {
protocol_version, protocol_version,
server_address, server_address,
@ -62,9 +60,9 @@ impl Handshake {
} }
impl SendPacket for Handshake { impl SendPacket for Handshake {
fn send_packet(&self, stream: &mut std::net::TcpStream) -> std::io::Result<()> { async fn send_packet(&self, stream: &mut TcpStream) -> std::io::Result<()> {
stream.write_all(&self.all)?; stream.write_all(&self.all).await?;
stream.flush()?; stream.flush().await?;
Ok(()) Ok(())
} }
} }

View file

@ -1,5 +1,7 @@
use std::io::Write; use std::io::Write;
use tokio::{io::AsyncWriteExt, net::TcpStream};
use crate::packets::{Packet, SendPacket}; use crate::packets::{Packet, SendPacket};
/// id: 0x00 /// id: 0x00
@ -14,9 +16,9 @@ impl StatusRequest {
} }
impl SendPacket for StatusRequest { impl SendPacket for StatusRequest {
fn send_packet(&self, stream: &mut std::net::TcpStream) -> std::io::Result<()> { async fn send_packet(&self, stream: &mut TcpStream) -> std::io::Result<()> {
stream.write_all(&self.all)?; stream.write_all(&self.all).await?;
stream.flush()?; stream.flush().await?;
Ok(()) Ok(())
} }
} }

View file

@ -1,8 +1,38 @@
use std::fmt::Display; use std::fmt::Display;
use tokio::{
io::{self, AsyncRead, AsyncReadExt},
net::TcpStream,
};
const SEGMENT_BITS: u8 = 0x7F; const SEGMENT_BITS: u8 = 0x7F;
const CONTINUE_BIT: u8 = 0x80; const CONTINUE_BIT: u8 = 0x80;
pub trait TamiReader {
async fn next_byte(&mut self) -> io::Result<Option<u8>>;
}
impl TamiReader for TcpStream {
async fn next_byte(&mut self) -> io::Result<Option<u8>> {
let mut buf: [u8; 1] = [0];
let n = self.read(&mut buf).await?;
if n == 0 {
return Ok(None);
}
Ok(Some(buf[0]))
}
}
impl TamiReader for Vec<u8> {
async fn next_byte(&mut self) -> io::Result<Option<u8>> {
if self.is_empty() {
return Ok(None);
} else {
return Ok(Some(self.remove(0)));
}
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct VarInt { pub struct VarInt {
value: i32, value: i32,
@ -28,14 +58,18 @@ impl VarInt {
pub fn move_data(self) -> Vec<u8> { pub fn move_data(self) -> Vec<u8> {
self.data self.data
} }
pub fn read<I>(data: &mut I) -> Option<i32> pub async fn read<I>(data: &mut I) -> Option<i32>
where where
I: Iterator<Item = u8>, I: TamiReader,
{ {
let mut value: i32 = 0; let mut value: i32 = 0;
let mut position = 0; let mut position = 0;
for current_byte in data { loop {
let current_byte = match data.next_byte().await {
Ok(x) => x?,
Err(e) => return None,
};
value |= ((current_byte & SEGMENT_BITS) as i32) << position; value |= ((current_byte & SEGMENT_BITS) as i32) << position;
if current_byte & CONTINUE_BIT == 0 { if current_byte & CONTINUE_BIT == 0 {
@ -49,16 +83,16 @@ impl VarInt {
} }
Some(value) Some(value)
} }
pub fn parse<I>(reader: &mut I) -> Option<VarInt> pub async fn parse<I>(reader: &mut I) -> Option<VarInt>
where where
I: Iterator<Item = u8>, I: TamiReader,
{ {
let mut value: i32 = 0; let mut value: i32 = 0;
let mut position = 0; let mut position = 0;
let mut vec = Vec::new(); let mut vec = Vec::new();
for current_byte in reader { loop {
let current_byte = current_byte; let current_byte = reader.next_byte().await.ok()??;
vec.push(current_byte); vec.push(current_byte);
value |= ((current_byte & SEGMENT_BITS) as i32) << position; value |= ((current_byte & SEGMENT_BITS) as i32) << position;
@ -121,14 +155,17 @@ impl VarString {
pub fn from(string: String) -> VarString { pub fn from(string: String) -> VarString {
VarString { value: string } VarString { value: string }
} }
pub fn parse<I>(data: &mut I) -> Option<VarString> pub async fn parse<I>(data: &mut I) -> Option<VarString>
where where
I: Iterator<Item = u8>, I: TamiReader,
{ {
let length = VarInt::read(data)?; let length = VarInt::read(data).await?;
let mut vec = Vec::new(); let mut vec = Vec::new();
for _ in 0..length { for _ in 0..length {
vec.push(data.next()?); vec.push(match data.next_byte().await {
Ok(x) => x?,
Err(e) => return None,
});
} }
Some(VarString { Some(VarString {
value: String::from_utf8(vec).ok()?, value: String::from_utf8(vec).ok()?,
@ -147,14 +184,20 @@ impl UShort {
pub fn get_data(&self) -> Vec<u8> { pub fn get_data(&self) -> Vec<u8> {
self.data.clone() self.data.clone()
} }
pub fn parse<I>(data: &mut I) -> Option<UShort> pub async fn parse<I>(data: &mut I) -> Option<UShort>
where where
I: Iterator<Item = u8>, I: TamiReader,
{ {
let mut vec = vec![data.next()?]; let mut vec = vec![match data.next_byte().await {
Ok(x) => x?,
Err(e) => return None,
}];
let mut int: u16 = vec[0] as u16; let mut int: u16 = vec[0] as u16;
int = int << 8; int = int << 8;
vec.push(data.next()?); vec.push(match data.next_byte().await {
Ok(x) => x?,
Err(_) => return None,
});
int |= vec[1] as u16; int |= vec[1] as u16;
Some(UShort { Some(UShort {
value: int, value: int,