├── src ├── utils │ ├── mod.rs │ ├── logger │ │ ├── mod.rs │ │ ├── log_lib.rs │ │ └── input.rs │ └── chat │ │ └── mod.rs ├── network │ ├── proto │ │ ├── packets │ │ │ ├── mod.rs │ │ │ ├── handshaking.rs │ │ │ └── status.rs │ │ ├── mod.rs │ │ ├── packet_read.rs │ │ └── packet_write.rs │ ├── mod.rs │ ├── network_client.rs │ ├── handler.rs │ └── server.rs ├── config │ └── mod.rs └── main.rs ├── .gitignore ├── README.md ├── .github └── FUNDING.yml └── Cargo.toml /src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod chat; 2 | pub mod logger; 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /latest.log 3 | /Cargo.lock 4 | /.idea 5 | latest.log -------------------------------------------------------------------------------- /src/network/proto/packets/mod.rs: -------------------------------------------------------------------------------- 1 | // Publish packets 2 | pub mod handshaking; 3 | pub mod status; 4 | -------------------------------------------------------------------------------- /src/utils/logger/mod.rs: -------------------------------------------------------------------------------- 1 | mod input; 2 | mod log_lib; 3 | 4 | pub use {input::start_input_handler, log_lib::setup_logger}; 5 | -------------------------------------------------------------------------------- /src/network/proto/mod.rs: -------------------------------------------------------------------------------- 1 | mod packet_read; 2 | mod packet_write; 3 | pub mod packets; 4 | 5 | pub use packet_read::PacketReader; 6 | pub use packet_write::PacketWriter; 7 | -------------------------------------------------------------------------------- /src/network/mod.rs: -------------------------------------------------------------------------------- 1 | mod handler; 2 | mod network_client; 3 | pub mod proto; 4 | mod server; 5 | 6 | pub use server::network_server_start; 7 | pub use server::{NET_SERVER_WORKS, SHUTDOWN_SERVER}; 8 | -------------------------------------------------------------------------------- /src/config/mod.rs: -------------------------------------------------------------------------------- 1 | // Server's protocol version 2 | pub const PROTOCOL_VERSION: u32 = 340; 3 | 4 | // Server's address parts(host and port) 5 | pub const ADDRESS_PORT: u16 = 25565; 6 | pub const ADDRESS: &str = "0.0.0.0"; 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### ULE - Minecraft's server core written in Rust 2 | ``` 3 | This's server core fully written in Rust-Lang and using more custom code 4 | for best perfomance and controlling. 5 | ``` 6 | 7 | If you want to [contribute - i'm exists on Patreon.](https://www.patreon.com/user?u=64366641) 8 | 9 | What's libraries using for server's core: 10 | - ahash ( best HashMap ) 11 | - lazy_static ( Global variables ) 12 | - serde ( Serializing and Deserializing structs) 13 | - serde_json ( convertor for JSON <-> Structs ) 14 | - log ( Logging framework ) 15 | - fern ( Logging framework's utilities ) 16 | - mio ( Single-threaded TCP and UDP server and client ) -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: distemi # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ule" 3 | version = "0.1.0" 4 | edition = "2021" 5 | publish = true 6 | authors = [ 7 | "Distemi " 8 | ] 9 | homepage = "https://github.com/Distemi/ULE" 10 | repository = "https://github.com/Distemi/ULE" 11 | readme = "README.md" 12 | 13 | [dependencies] 14 | # Fast HashMap and etc. 15 | ahash = "0.7.6" 16 | # Global variables 17 | lazy_static = "1.4.0" 18 | # Struct <-> JSON and so on 19 | serde = { version = "1.0.136", features = ["derive"] } 20 | serde_json = "1.0.78" 21 | # Logging utils 22 | log = "0.4.14" 23 | fern = { version = "0.6", features = ["colored"] } 24 | # Time 25 | chrono = "0.4.19" 26 | # Async 27 | async-std = "1.10.0" 28 | 29 | # Single threaded TCP and UDP server 30 | [dependencies.mio] 31 | version = "0.8.0" 32 | default-features = false 33 | features = [ 34 | "os-ext", 35 | "net" 36 | ] 37 | 38 | 39 | [profile.release] 40 | opt-level = "z" 41 | -------------------------------------------------------------------------------- /src/utils/chat/mod.rs: -------------------------------------------------------------------------------- 1 | // Chat's component 2 | #[derive(Debug, Serialize)] 3 | pub struct ChatMessage { 4 | // Chat's text 5 | pub text: String, 6 | // Simple style - bold. Skip to showing if empty 7 | #[serde(skip_serializing_if = "std::string::String::is_empty")] 8 | pub bold: String, 9 | // Child components of the component. Skip to showing if empty 10 | #[serde(skip_serializing_if = "Vec::is_empty")] 11 | pub extra: Vec, 12 | } 13 | 14 | impl ChatMessage { 15 | // Creating a component 16 | pub fn text(text: String) -> Self { 17 | Self { 18 | // Replacing a formatting from user-like to minecraft-like 19 | text: text.replace("&", "§"), 20 | // Empty style 21 | bold: String::new(), 22 | // Empty child components 23 | extra: vec![], 24 | } 25 | } 26 | // Updating bold style 27 | pub fn set_bold(&mut self, value: bool) { 28 | self.bold = value.to_string(); 29 | } 30 | // Creating component from str ( not String ) 31 | pub fn str(text: &str) -> Self { 32 | ChatMessage::text(String::from(text).replace("&", "§")) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/utils/logger/log_lib.rs: -------------------------------------------------------------------------------- 1 | use crate::Color; 2 | use fern::colors::ColoredLevelConfig; 3 | use std::fs; 4 | 5 | // Logger's initialize(fern, color and log) 6 | pub fn setup_logger() -> Result<(), fern::InitError> { 7 | // Removing latest log if exists 8 | fs::remove_file("latest.log"); 9 | // Setting colors 10 | let colors = ColoredLevelConfig::new() 11 | .info(Color::BrightBlack) 12 | .warn(Color::Yellow) 13 | .error(Color::Red) 14 | .trace(Color::BrightRed); 15 | // Setting fern 16 | fern::Dispatch::new() 17 | // Setting custom format to logging 18 | .format(move |out, message, record| { 19 | out.finish(format_args!( 20 | "{} [{}] {}", 21 | chrono::Local::now().format("[%m-%d %H:%M:%S]"), 22 | colors.color(record.level()), 23 | message 24 | )) 25 | }) 26 | // Setting log-level 27 | .level(log::LevelFilter::Info) 28 | // Setting target's logger 29 | .chain(std::io::stdout()) 30 | // Setting log's file 31 | .chain(fern::log_file("latest.log")?) 32 | // Applying settings 33 | .apply()?; 34 | // If successful setting - returning ok 35 | Ok(()) 36 | } 37 | -------------------------------------------------------------------------------- /src/network/proto/packets/handshaking.rs: -------------------------------------------------------------------------------- 1 | use crate::network::network_client::NetworkClient; 2 | use crate::network::proto::PacketReader; 3 | use crate::{SResult, SimpleError}; 4 | /// Trying to read [handshake](https://wiki.vg/index.php?title=Protocol&oldid=14204#Handshake) packet 5 | pub fn read_handshake_packet(client: &mut NetworkClient) -> SResult<(u32, String, u16, u32)> { 6 | // Read bytes from client 7 | let (ok, p, err) = match client.read() { 8 | Ok((ok, p)) => (ok, Some(p), None), 9 | Err(err) => (false, None, Some(err)), 10 | }; 11 | // If failed to read when... 12 | if !ok || err.is_some() { 13 | return Err(SimpleError( 14 | String::from("Failed to read packet"), 15 | if err.is_some() { err.unwrap().1 } else { None }, 16 | )); 17 | } 18 | // Reading packet 19 | let mut p: Vec = p.unwrap(); 20 | // Try to read Length and PacketID from packet(on handshaking stage only 0x00) 21 | p.read_base()?; 22 | // Reading version, address and etc. 23 | let ver = p.get_varint()? as u32; 24 | let address = p.get_string()?; 25 | let port = p.get_u16(); 26 | let next_state = p.get_varint()? as u32; 27 | // States can be only 1 - status, 2 - play 28 | if next_state >= 3 { 29 | return Err(SimpleError(String::from("Invalid client"), None)); 30 | } 31 | // Returning results 32 | Ok((ver, address, port, next_state)) 33 | } 34 | -------------------------------------------------------------------------------- /src/network/network_client.rs: -------------------------------------------------------------------------------- 1 | use crate::{SResult, SimpleError}; 2 | use mio::net::TcpStream; 3 | use std::io::{ErrorKind, Read}; 4 | 5 | // Connection's types 6 | pub enum ConnectionType { 7 | HANDSHAKING, 8 | STATUS, 9 | } 10 | 11 | // Network-base client 12 | pub struct NetworkClient { 13 | pub stream: TcpStream, 14 | pub conn_type: ConnectionType, 15 | } 16 | 17 | // Declare functions 18 | impl NetworkClient { 19 | // Function for reading input bytes 20 | pub fn read(&mut self) -> SResult<(bool, Vec)> { 21 | // Creating a buffer up to 4KB information 22 | let mut bytes = vec![0; 4096]; 23 | // Reading a bytes 24 | let (ok, err) = match self.stream.read(&mut bytes) { 25 | // Connection closed. Why exists? 26 | Ok(0) => (false, None), 27 | // Getting byte's length and resize buffer 28 | Ok(n) => { 29 | bytes.resize(n, 0); 30 | (true, None) 31 | } 32 | // Connection don't has a input bytes 33 | Err(ref err) if err.kind() == ErrorKind::WouldBlock => (false, None), 34 | // Failed to read bytes 35 | Err(err) => (false, Some(err)), 36 | }; 37 | // If Error exists when returning a error 38 | if err.is_some() { 39 | return Err(SimpleError(String::from("Failed to read packet"), err)); 40 | } 41 | // Returning a result of reading 42 | Ok((ok, bytes)) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/utils/logger/input.rs: -------------------------------------------------------------------------------- 1 | use crate::network::{NET_SERVER_WORKS, SHUTDOWN_SERVER}; 2 | use std::time::Duration; 3 | use std::{io, process, thread}; 4 | 5 | // Loop for handling input 6 | pub fn start_input_handler() -> std::io::Result<()> { 7 | // Input buffer 8 | let mut inp = String::new(); 9 | // STDIN - os input 10 | let stdin = io::stdin(); 11 | // loop for infinity handling 12 | loop { 13 | // Before write buffer we need to clear buffer 14 | inp.clear(); 15 | // Reading a line 16 | stdin.read_line(&mut inp)?; 17 | // Clearing input's buffer 18 | inp = inp.replace("\n", ""); 19 | // Simple realisation of stop command, but in updates be removed from here in another place 20 | if inp.starts_with("stop") { 21 | // Sending status to shutdown network server 22 | *SHUTDOWN_SERVER.lock().unwrap() = true; 23 | info!("Stopping server..."); 24 | // Running process killing in 6 secs if failed to common shutdown 25 | thread::spawn(|| { 26 | thread::sleep(Duration::from_secs(6)); 27 | process::exit(0); 28 | }); 29 | // Waiting for shutdown network's server 30 | loop { 31 | if *NET_SERVER_WORKS.lock().unwrap() == true { 32 | thread::sleep(Duration::from_millis(25)); 33 | } else { 34 | break; 35 | } 36 | } 37 | // Disabling the input 38 | return Ok(()); 39 | } 40 | // If it's not stop command - when display buffer, but in updates be removed 41 | info!("Entered: {}", inp); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/network/proto/packets/status.rs: -------------------------------------------------------------------------------- 1 | use crate::config::PROTOCOL_VERSION; 2 | use crate::network::proto::packet_write::PacketWriter; 3 | use crate::utils::chat::ChatMessage; 4 | 5 | // Structs for status MOTD response 6 | #[derive(Debug, Serialize)] 7 | pub struct ListPingResponse { 8 | pub version: ListPingResponseVersion, 9 | pub players: ListPingResponsePlayers, 10 | pub description: ChatMessage, 11 | } 12 | 13 | #[derive(Debug, Serialize)] 14 | pub struct ListPingResponseVersion { 15 | pub name: String, 16 | pub protocol: u32, 17 | } 18 | 19 | #[derive(Debug, Serialize)] 20 | pub struct ListPingResponsePlayers { 21 | pub max: u32, 22 | pub online: u32, 23 | pub sample: Vec, 24 | } 25 | 26 | #[derive(Debug, Serialize)] 27 | pub struct ListPingResponsePlayerSample { 28 | pub name: String, 29 | pub id: String, 30 | } 31 | /// Build packet's bytes as result 32 | pub fn create_server_list_ping_response() -> Vec { 33 | // Initialize empty byte's vector 34 | let mut bytes = Vec::new(); 35 | // Generating String and convert to bytes. 36 | // String generated as JSON by serde and serde_json libraries 37 | bytes.write_string( 38 | serde_json::to_string(&ListPingResponse { 39 | version: ListPingResponseVersion { 40 | name: String::from("ULE"), 41 | protocol: PROTOCOL_VERSION, 42 | }, 43 | players: ListPingResponsePlayers { 44 | max: 10, 45 | online: 0, 46 | sample: vec![], 47 | }, 48 | // Some clients can read colors and so on without convert into JSON 49 | description: ChatMessage::str("&a&lHello!"), 50 | }) 51 | .unwrap(), 52 | ); 53 | // Build completed packet. Server List Ping - PacketID is 0x00 54 | bytes.create_packet(0x00) 55 | } 56 | -------------------------------------------------------------------------------- /src/network/handler.rs: -------------------------------------------------------------------------------- 1 | use crate::network::network_client::ConnectionType::STATUS; 2 | use crate::network::network_client::NetworkClient; 3 | use crate::network::proto::packets::handshaking::read_handshake_packet; 4 | use crate::network::proto::packets::status::create_server_list_ping_response; 5 | use crate::network::proto::PacketReader; 6 | use crate::SResult; 7 | use mio::event::Event; 8 | use std::io::Write; 9 | 10 | // Handshaking connection's stage 11 | pub fn handshaking(conn: &mut NetworkClient, event: &Event) -> SResult { 12 | // Checking if we can read the package 13 | if !event.is_readable() { 14 | return Ok(false); 15 | } 16 | // Reading packet 17 | let handshake = read_handshake_packet(conn); 18 | // Checking if is error 19 | if handshake.is_err() { 20 | return Ok(true); 21 | } 22 | // Getting results 23 | let (_, _, _, next_state) = handshake.unwrap(); 24 | // Change types 25 | conn.conn_type = match next_state { 26 | 1 => STATUS, 27 | _ => STATUS, 28 | }; 29 | Ok(false) 30 | } 31 | 32 | // Status connection's stage 33 | pub fn status_handler(conn: &mut NetworkClient, event: &Event) -> SResult { 34 | // Checking if we can read and write 35 | if !event.is_readable() || !event.is_writable() { 36 | return Ok(false); 37 | } 38 | // Getting a input's bytes 39 | let (ok, p, err) = match conn.read() { 40 | Ok((ok, p)) => (ok, Some(p), None), 41 | Err(err) => (false, None, Some(err)), 42 | }; 43 | // Checking if a read or not 44 | if !ok { 45 | return Ok(err.is_some()); 46 | } 47 | // Packet's bytes 48 | let mut p: Vec = p.unwrap(); 49 | // Cloning bytes(for ping-pong) 50 | let bytes = p.clone(); 51 | // Reading a packet's length(and remove...) and PacketID 52 | let (_, pid) = p.read_base()?; 53 | match pid { 54 | // Is Ping List 55 | 0x00 => { 56 | drop(bytes); 57 | conn.stream.write_all(&*create_server_list_ping_response()); 58 | } 59 | // Is Ping-Pong 60 | 0x01 => { 61 | conn.stream.write_all(bytes.as_slice()); 62 | match conn.stream.peer_addr() { 63 | Ok(v) => info!("Server pinged from {}", v), 64 | Err(_) => { 65 | info!("Server pinged.") 66 | } 67 | } 68 | } 69 | _ => {} 70 | } 71 | Ok(false) 72 | } 73 | -------------------------------------------------------------------------------- /src/network/proto/packet_read.rs: -------------------------------------------------------------------------------- 1 | use crate::{SResult, SimpleError}; 2 | 3 | /// Reader [Vec] of bytes 4 | pub trait PacketReader { 5 | // 1-Byte 6 | fn get_u8(&mut self) -> u8; 7 | fn get_i8(&mut self) -> i8; 8 | // 2-Byte 9 | fn get_u16(&mut self) -> u16; 10 | fn get_i16(&mut self) -> i16; 11 | // 4-Byte 12 | fn get_varint(&mut self) -> SResult; 13 | // 8-Byte 14 | fn get_i64(&mut self) -> i64; 15 | // Another 16 | fn get_string(&mut self) -> SResult; 17 | fn read_base(&mut self) -> SResult<(i32, i32)>; 18 | } 19 | 20 | // Apply reader to Vec 21 | impl PacketReader for Vec { 22 | // Read a single byte as u8 ( 8-Bit Unsigned Integer ) 23 | fn get_u8(&mut self) -> u8 { 24 | self.remove(0) 25 | } 26 | 27 | // Read a single byte as i8 ( 8-Bit Integer ) 28 | fn get_i8(&mut self) -> i8 { 29 | self.remove(1) as i8 30 | } 31 | 32 | // Read a two bytes as u16 ( 16-Bit Unsigned Integer ) 33 | fn get_u16(&mut self) -> u16 { 34 | u16::from_be_bytes([self.get_u8(), self.get_u8()]) 35 | } 36 | 37 | // Read a two bytes as i16 ( 16-Bit Integer ) 38 | fn get_i16(&mut self) -> i16 { 39 | i16::from_be_bytes([self.get_u8(), self.get_u8()]) 40 | } 41 | 42 | // Read a VarInt ( Dynamic-length 32-Bit Integer ) 43 | fn get_varint(&mut self) -> SResult { 44 | // Result variable 45 | let mut ans = 0; 46 | // Read up to 4 bytes 47 | for i in 0..4 { 48 | // Read one byte 49 | let buf = self.get_u8(); 50 | // Calculate res with bit moving and another 51 | ans |= ((buf & 0b0111_1111) as i32) << 7 * i; 52 | // If it's limit when stop reading 53 | if buf & 0b1000_0000 == 0 { 54 | break; 55 | } 56 | } 57 | // Return result as successful 58 | Ok(ans) 59 | } 60 | 61 | // Read a Long ( 64-Bit Integer ) 62 | fn get_i64(&mut self) -> i64 { 63 | // Yes, read 8 bytes 64 | i64::from_be_bytes([ 65 | self.get_u8(), 66 | self.get_u8(), 67 | self.get_u8(), 68 | self.get_u8(), 69 | self.get_u8(), 70 | self.get_u8(), 71 | self.get_u8(), 72 | self.get_u8(), 73 | ]) 74 | } 75 | 76 | // Read a String ( VarInt as len; bytes[::len] ) 77 | fn get_string(&mut self) -> SResult { 78 | // Getting string-length 79 | let len = self.get_varint()?; 80 | // Create String's bytes buffer 81 | let mut buf = Vec::new(); 82 | // Reading Bytes 83 | for _ in 0..len { 84 | buf.push(self.get_u8()) 85 | } 86 | // Convert Bytes to UTF8 String 87 | match String::from_utf8(buf) { 88 | Ok(v) => Ok(v), 89 | Err(_) => Err(SimpleError(String::from("Failed to parse chars"), None)), 90 | } 91 | } 92 | // Read first two VarInt(Packet's length and id) 93 | fn read_base(&mut self) -> SResult<(i32, i32)> { 94 | let len = self.get_varint()?; 95 | let pid = self.get_varint()?; 96 | Ok((len, pid)) 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_must_use)] 2 | use crate::config::{ADDRESS, ADDRESS_PORT}; 3 | use crate::logger::start_input_handler; 4 | use crate::network::network_server_start; 5 | use fern::colors::Color; 6 | use std::error::Error; 7 | use std::process; 8 | use std::sync::mpsc::channel; 9 | use std::sync::Arc; 10 | use std::time::SystemTime; 11 | use std::{fmt, thread}; 12 | use utils::logger; 13 | 14 | // Use a macros from serde(Serialize and Deserialize), log(Logging) and lazy_static(Global variables) 15 | #[macro_use] 16 | extern crate serde; 17 | #[macro_use] 18 | extern crate log; 19 | #[macro_use] 20 | extern crate lazy_static; 21 | 22 | pub mod config; 23 | pub mod network; 24 | pub mod utils; 25 | 26 | // Main function of application 27 | fn main() { 28 | let start = SystemTime::now(); 29 | // Initialize logger 30 | println!("Starting ULE v1.0.0..."); 31 | if let Err(err) = logger::setup_logger() { 32 | eprintln!("Failed to initialize logger: {}", err); 33 | process::exit(1); 34 | } 35 | // Creating channel for multithreading communication with main's thread and network's thread 36 | let (tx, rx) = channel::(); 37 | // Generate server's address and make it accessible with thread safe 38 | let address = Arc::new(String::from(format!( 39 | "{}:{}", 40 | ADDRESS, 41 | ADDRESS_PORT.to_string() 42 | ))); 43 | // Start network in another thread 44 | thread::spawn({ 45 | let address = address.to_string(); 46 | move || { 47 | // Start network 48 | // If failed to start when return error 49 | if let Err(err) = network_server_start(address, &tx) { 50 | error!("{}", err); 51 | tx.send(false); 52 | } 53 | } 54 | }); 55 | // Wait for status from server's network 56 | if rx.recv().unwrap_or(false) { 57 | // If Server successful started 58 | info!("Server started at {}", address); 59 | // Showing about the full launch and showing the time to start 60 | { 61 | let elapsed = start.elapsed().unwrap(); 62 | info!( 63 | "The server was successfully started in {}", 64 | if elapsed.as_secs() >= 1 { 65 | format!("{}s", elapsed.as_secs()) 66 | } else if elapsed.as_millis() >= 1 { 67 | format!("{}ms", elapsed.as_millis()) 68 | } else { 69 | format!("{}ns", elapsed.as_nanos()) 70 | } 71 | ); 72 | drop(elapsed); 73 | drop(start); 74 | }; 75 | } else { 76 | // If Failed to start Server 77 | error!("Failed to start server on {}.", address); 78 | process::exit(1); 79 | } 80 | // Remove channel 81 | std::mem::drop(rx); 82 | // Start console input handler(input commands) 83 | start_input_handler(); 84 | } 85 | 86 | // Custom error(yes, not std::io:Error) 87 | #[derive(Debug)] 88 | pub struct SimpleError(String, Option); 89 | 90 | impl Error for SimpleError {} 91 | 92 | impl fmt::Display for SimpleError { 93 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 94 | // Check is error provided 95 | if self.1.is_some() { 96 | write!(f, "{}: {:?}", self.0, self.1) 97 | } else { 98 | write!(f, "{}", self.0) 99 | } 100 | } 101 | } 102 | 103 | // Custom Result with custom Error 104 | pub type SResult = Result; 105 | -------------------------------------------------------------------------------- /src/network/proto/packet_write.rs: -------------------------------------------------------------------------------- 1 | /// Writer [Vec] of bytes 2 | pub trait PacketWriter { 3 | // 1-Byte 4 | fn write_u8(&mut self, value: u8); 5 | fn write_i8(&mut self, value: i8); 6 | // 2-Byte 7 | fn write_u16(&mut self, value: u16); 8 | fn write_i16(&mut self, value: i16); 9 | // 4-Byte 10 | fn write_varint(&mut self, value: i32); 11 | // 8-Byte 12 | fn write_i64(&mut self, value: i64); 13 | // Another 14 | fn write_vec_bytes(&mut self, bytes: Vec); 15 | fn write_string(&mut self, value: String); 16 | fn create_packet(&mut self, pid: i32) -> Vec; 17 | } 18 | 19 | impl PacketWriter for Vec { 20 | // Writing byte 21 | fn write_u8(&mut self, value: u8) { 22 | self.push(value); 23 | } 24 | 25 | // Writing byte 26 | fn write_i8(&mut self, value: i8) { 27 | self.push(value as u8) 28 | } 29 | 30 | // Writing 2-byte unsigned integer 31 | fn write_u16(&mut self, value: u16) { 32 | self.extend_from_slice(&value.to_be_bytes()); 33 | } 34 | 35 | // Writing 2-byte unsigned integer 36 | fn write_i16(&mut self, value: i16) { 37 | self.extend_from_slice(&value.to_be_bytes()); 38 | } 39 | 40 | // Writing bytes as VarInt 41 | fn write_varint(&mut self, mut value: i32) { 42 | // Bytes buffer 43 | let mut buf = vec![0u8; 1]; 44 | // Byte's length 45 | let mut n = 0; 46 | // Converts value to bytes 47 | loop { 48 | // Break if it's limit 49 | if value <= 127 || n >= 8 { 50 | break; 51 | } 52 | // Pushing a byte to buffer 53 | buf.insert(n, (0x80 | (value & 0x7F)) as u8); 54 | // Moving value's bits on 7 55 | value >>= 7; 56 | value -= 1; 57 | n += 1; 58 | } 59 | // Pushing byte, because it lower that 256(<256) 60 | buf.insert(n, value as u8); 61 | n += 1; 62 | // Pushing converted bytes into byte's buffer 63 | self.extend_from_slice(&buf.as_slice()[..n]) 64 | } 65 | 66 | // Writing Long ( 64-Bit Integer ) 67 | fn write_i64(&mut self, value: i64) { 68 | self.extend_from_slice(value.to_be_bytes().as_slice()) 69 | } 70 | 71 | // Alias of extend_from_slice, but works with Vec, not Slice 72 | fn write_vec_bytes(&mut self, mut bytes: Vec) { 73 | self.append(&mut bytes); 74 | } 75 | 76 | // Write String (VarInt as len and string's bytes) 77 | fn write_string(&mut self, value: String) { 78 | // Getting String as Bytes 79 | let bytes = value.as_bytes(); 80 | // Writing to buffer a length as VarInt 81 | self.write_varint(bytes.len() as i32); 82 | // Writing to buffer a string's bytes 83 | self.extend_from_slice(bytes); 84 | } 85 | 86 | // Packet's base builder 87 | fn create_packet(&mut self, pid: i32) -> Vec { 88 | // Creating empty packet's buffer 89 | let mut packet = Vec::new(); 90 | // Creating length's bytes buffer and fill it as VarInt 91 | let mut len_bytes: Vec = Vec::new(); 92 | len_bytes.write_varint(pid); 93 | // Writing full packet's length(content + length's bytes) 94 | packet.write_varint((self.len() + len_bytes.len()) as i32); 95 | // Writing length bytes 96 | packet.extend_from_slice(len_bytes.as_slice()); 97 | // Drop(Free) length bytes buffer 98 | drop(len_bytes); 99 | // Writing some packet's content 100 | packet.extend_from_slice(self.as_slice()); 101 | // Returning result 102 | packet 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/network/server.rs: -------------------------------------------------------------------------------- 1 | use crate::network::handler::{handshaking, status_handler}; 2 | use crate::network::network_client::ConnectionType::HANDSHAKING; 3 | use crate::network::network_client::NetworkClient; 4 | use ahash::AHashMap; 5 | use mio::net::TcpListener; 6 | use mio::{Events, Interest, Poll, Token}; 7 | use std::io; 8 | use std::sync::mpsc::Sender; 9 | use std::sync::Mutex; 10 | use std::time::Duration; 11 | 12 | // Declare global variables 13 | lazy_static! { 14 | // Server need to shut down? (true - yes, needs to shutdown network server). 15 | pub static ref SHUTDOWN_SERVER: Mutex = Mutex::new(false); 16 | // Server's works status. 17 | pub static ref NET_SERVER_WORKS: Mutex = Mutex::new(true); 18 | } 19 | 20 | // Server's Token(ID) 21 | const SERVER: Token = Token(0); 22 | 23 | // Next Token 24 | fn next(current: &mut Token) -> Token { 25 | let next = current.0; 26 | current.0 += 1; 27 | Token(next) 28 | } 29 | 30 | // Start a network server 31 | pub fn network_server_start(address: String, tx: &Sender) -> std::io::Result<()> { 32 | // Creating Network Pool 33 | let mut poll = Poll::new()?; 34 | // Creating Network Events Pool 35 | let mut events = Events::with_capacity(128); 36 | // Converting String's address to SocketAddr 37 | let addr = address.parse().unwrap(); 38 | // Starting a Network Listener 39 | let mut server = TcpListener::bind(addr)?; 40 | // Register server's Token 41 | poll.registry() 42 | .register(&mut server, SERVER, Interest::READABLE)?; 43 | 44 | // Creating a list of connections 45 | let mut connections: AHashMap = AHashMap::new(); 46 | // Creating a variable with latest token. 47 | let mut unique_token = Token(SERVER.0 + 1); 48 | // Send over the channel that the server has been successfully started 49 | tx.send(true); 50 | 51 | // Network Events getting timeout 52 | let timeout = Some(Duration::from_millis(10)); 53 | // Infinity loop(while true) to handing events 54 | loop { 55 | // Checks whether it is necessary to shutdown the network server 56 | if *SHUTDOWN_SERVER.lock().unwrap() { 57 | *NET_SERVER_WORKS.lock().unwrap() = false; 58 | info!("Network Server Stopped!"); 59 | return Ok(()); 60 | } 61 | // Getting a events from pool to event's pool with timeout 62 | poll.poll(&mut events, timeout)?; 63 | // Handing a events 64 | for event in events.iter() { 65 | // Handing event by token 66 | match event.token() { 67 | // If it server's event 68 | // Reading a all incoming connection 69 | SERVER => loop { 70 | // Accepting connection 71 | let (mut connection, _) = match server.accept() { 72 | // If successful 73 | Ok(v) => v, 74 | // If not exists incoming connection 75 | Err(e) if e.kind() == io::ErrorKind::WouldBlock => { 76 | break; 77 | } 78 | // If failed to get incoming connection 79 | Err(e) => { 80 | return Err(e); 81 | } 82 | }; 83 | 84 | // Generating new token for this connection 85 | let token = next(&mut unique_token); 86 | // Registering connection with token 87 | poll.registry().register( 88 | &mut connection, 89 | token, 90 | Interest::READABLE.add(Interest::WRITABLE), 91 | )?; 92 | // Pushing connection into connection's list 93 | connections.insert( 94 | token, 95 | NetworkClient { 96 | stream: connection, 97 | conn_type: HANDSHAKING, 98 | }, 99 | ); 100 | }, 101 | // Handing event from client 102 | token => { 103 | // Handing event by connection's stage 104 | let done = if let Some(connection) = connections.get_mut(&token) { 105 | let m = match &connection.conn_type { 106 | HANDSHAKING => handshaking, 107 | _ => status_handler, 108 | }; 109 | // Trying to handing 110 | m(connection, &event).unwrap_or(false) 111 | } else { 112 | false 113 | }; 114 | // If needs to close connection - removing from list, unregister and close connection's stream 115 | if done { 116 | if let Some(mut connection) = connections.remove(&token) { 117 | poll.registry().deregister(&mut connection.stream)?; 118 | connections.remove(&token); 119 | } 120 | } 121 | } 122 | } 123 | } 124 | } 125 | } 126 | --------------------------------------------------------------------------------