diff --git a/src/http.rs b/src/http.rs index 90e0d49..131c96e 100644 --- a/src/http.rs +++ b/src/http.rs @@ -8,7 +8,7 @@ use std::{ use chrono::Local; -use crate::thread::ThreadPool; +use crate::ThreadPool; #[derive(Clone, Copy)] pub enum StatusCode { diff --git a/src/leb128.rs b/src/leb128.rs index 60247ad..7f7b091 100644 --- a/src/leb128.rs +++ b/src/leb128.rs @@ -1,34 +1,38 @@ const CONTINUE_BIT: u8 = 0x80; -pub fn write_leb128(buffer: &mut Vec, mut value: u64) -> usize { - let mut size: usize = 0; - loop { - let mut byte: u8 = (value & (std::u8::MAX as u64)).try_into().unwrap(); - value >>= 7; - if value != 0 { - byte |= CONTINUE_BIT; +pub struct LEB128; + +impl LEB128 { + pub fn write_leb128(buffer: &mut Vec, mut value: u64) -> usize { + let mut size: usize = 0; + loop { + let mut byte: u8 = (value & (std::u8::MAX as u64)).try_into().unwrap(); + value >>= 7; + if value != 0 { + byte |= CONTINUE_BIT; + } + + buffer.push(byte); + size += 1; + + if value == 0 { + return size; + } } + } - buffer.push(byte); - size += 1; - - if value == 0 { - return size; + pub fn read_leb128(buffer: &[u8]) -> (u32, usize) { + let mut result: u32 = 0; + let mut shift: usize = 0; + let mut offset: usize = 0; + loop { + let byte: u8 = buffer[offset]; + result |= ((byte & (std::i8::MAX as u8)) as u32) << (shift as u32); + offset += 1; + if byte & CONTINUE_BIT == 0 || offset == 4 { + return (result, offset); + } + shift += 7; } } } - -pub fn read_leb128(buffer: &[u8]) -> (u32, usize) { - let mut result: u32 = 0; - let mut shift: usize = 0; - let mut offset: usize = 0; - loop { - let byte: u8 = buffer[offset]; - result |= ((byte & (std::i8::MAX as u8)) as u32) << (shift as u32); - offset += 1; - if byte & CONTINUE_BIT == 0 || offset == 4 { - return (result, offset); - } - shift += 7; - } -} diff --git a/src/lib.rs b/src/lib.rs index 954b787..6139176 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,88 @@ +use std::{sync::{mpsc, Arc, Mutex}, thread}; + pub mod leb128; pub mod status; -pub mod thread; pub mod http; pub mod dns; +pub use status::MinecraftStatus; + +pub struct ThreadPool { + workers: Vec, + sender: Option>, +} + +type Job = Box; + +impl ThreadPool { + // Create a new ThreadPool with `size` available threads. + // + // # Panics + // + // `new` will panic if `size` is zero. + pub fn new(size: usize) -> ThreadPool { + assert!(size > 0); + + let (sender, receiver) = mpsc::channel(); + + let receiver = Arc::new(Mutex::new(receiver)); + + let mut workers = Vec::with_capacity(size); + + for id in 0..size { + workers.push(ThreadWorker::new(id, Arc::clone(&receiver))); + } + + ThreadPool { + workers, + sender: Some(sender) + } + } + + pub fn execute(&self, f: F) + where + F: FnOnce() + Send + 'static + { + let job = Box::new(f); + + self.sender.as_ref().unwrap().send(job).unwrap(); + } +} + +impl Drop for ThreadPool { + fn drop(&mut self) { + drop(self.sender.take()); + + for worker in &mut self.workers.drain(..) { + println!("Shutting down worker {}", worker.id); + + worker.thread.join().unwrap(); + } + } +} + +struct ThreadWorker { + id: usize, + thread: thread::JoinHandle<()>, +} + +impl ThreadWorker { + fn new(id: usize, receiver: Arc>>) -> ThreadWorker { + let thread = thread::spawn(move || loop { + let msg = receiver.lock().unwrap().recv(); + + match msg { + Ok(job) => { + // println!("Job received by worker {id}"); + job(); + } + Err(_) => { + // println!("Worker {id} disconnected. Shutting down..."); + break; + } + } + }); + + ThreadWorker { id, thread } + } +} + diff --git a/src/main.rs b/src/main.rs index fddb15f..46ba212 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,11 @@ -use std::io::Result; +use std::io::{Result}; use std::net::{IpAddr, ToSocketAddrs}; use std::str::FromStr; -use std::env; +use std::{env}; use mcstatusface::http::{HttpServer, StatusCode}; -use mcstatusface::status::MinecraftStatus; -use mcstatusface::dns::resolve_srv_port; +use mcstatusface::{MinecraftStatus}; +use mcstatusface::dns::{resolve_srv_port}; #[derive(serde::Serialize)] struct MinecraftStatusResponse<'a> { diff --git a/src/status.rs b/src/status.rs index 7d28f96..65c6eb3 100644 --- a/src/status.rs +++ b/src/status.rs @@ -1,7 +1,7 @@ use std::io::{Error, ErrorKind, Read, Write, Result}; use std::net::{SocketAddr, TcpStream}; -use crate::leb128::{read_leb128, write_leb128}; +use crate::leb128::LEB128; #[derive(serde::Serialize, serde::Deserialize)] pub struct MinecraftVersion { @@ -67,11 +67,11 @@ impl MinecraftStatus { // println!("Sending payload..."); send_buffer.push(0x00); - write_leb128(&mut send_buffer, 769); // 1.21.4 - write_leb128(&mut send_buffer, address.ip().to_string().len().try_into().unwrap()); + LEB128::write_leb128(&mut send_buffer, 769); // 1.21.4 + LEB128::write_leb128(&mut send_buffer, address.ip().to_string().len().try_into().unwrap()); send_buffer.extend_from_slice(address.ip().to_string().as_bytes()); send_buffer.extend_from_slice(&address.port().to_be_bytes()); - write_leb128(&mut send_buffer, 1); + LEB128::write_leb128(&mut send_buffer, 1); send_packet(&mut stream, &send_buffer).unwrap(); send_packet(&mut stream, &[0x00]).unwrap(); @@ -89,7 +89,7 @@ impl MinecraftStatus { if len > 0 { if msg_len == 0 { let mut val: u32; - (val, offset) = read_leb128(&recv_buffer); + (val, offset) = LEB128::read_leb128(&recv_buffer); msg_len = val as usize; if recv_buffer[offset] != 0x00 { @@ -98,7 +98,7 @@ impl MinecraftStatus { offset += 1; // skip message type bit let offset2: usize; - (val, offset2) = read_leb128(&recv_buffer[offset..]); + (val, offset2) = LEB128::read_leb128(&recv_buffer[offset..]); object_len = val as usize; offset += offset2; } @@ -151,7 +151,7 @@ fn _description(description: &MinecraftDescription) -> String { fn send_packet(stream: &mut TcpStream, data: &[u8]) -> Result<()> { let mut packet: Vec = Vec::new(); - write_leb128(&mut packet, data.len() as u64); + LEB128::write_leb128(&mut packet, data.len() as u64); packet.extend_from_slice(&data); stream.write(&packet).unwrap(); diff --git a/src/thread.rs b/src/thread.rs deleted file mode 100644 index a6cae8f..0000000 --- a/src/thread.rs +++ /dev/null @@ -1,81 +0,0 @@ -use std::{sync::{mpsc, Arc, Mutex}, thread}; - -pub struct ThreadPool { - workers: Vec, - sender: Option>, -} - -type Job = Box; - -impl ThreadPool { - // Create a new ThreadPool with `size` available threads. - // - // # Panics - // - // `new` will panic if `size` is zero. - pub fn new(size: usize) -> ThreadPool { - assert!(size > 0); - - let (sender, receiver) = mpsc::channel(); - - let receiver = Arc::new(Mutex::new(receiver)); - - let mut workers = Vec::with_capacity(size); - - for id in 0..size { - workers.push(ThreadWorker::new(id, Arc::clone(&receiver))); - } - - ThreadPool { - workers, - sender: Some(sender) - } - } - - pub fn execute(&self, f: F) - where - F: FnOnce() + Send + 'static - { - let job = Box::new(f); - - self.sender.as_ref().unwrap().send(job).unwrap(); - } -} - -impl Drop for ThreadPool { - fn drop(&mut self) { - drop(self.sender.take()); - - for worker in &mut self.workers.drain(..) { - worker.thread.join().expect( - format!("Error in worker {}", worker.id).as_str()); - } - } -} - -struct ThreadWorker { - id: usize, - thread: thread::JoinHandle<()>, -} - -impl ThreadWorker { - fn new(id: usize, receiver: Arc>>) -> ThreadWorker { - let thread = thread::spawn(move || loop { - let msg = receiver.lock().unwrap().recv(); - - match msg { - Ok(job) => { - // println!("Job received by worker {id}"); - job(); - } - Err(_) => { - // println!("Worker {id} disconnected. Shutting down..."); - break; - } - } - }); - - ThreadWorker { id, thread } - } -} -