diff --git a/.gitignore b/.gitignore index ea8c4bf..dc1d3d3 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ /target +/.vscode + +Cargo.lock \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index 28ed5ab..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,415 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "autocfg" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bumpalo" -version = "3.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - -[[package]] -name = "cc" -version = "1.0.98" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "wasm-bindgen", - "windows-targets", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" - -[[package]] -name = "cpufeatures" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" -dependencies = [ - "libc", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - -[[package]] -name = "js-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "keccak" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" -dependencies = [ - "cpufeatures", -] - -[[package]] -name = "libc" -version = "0.2.155" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" - -[[package]] -name = "log" -version = "0.4.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "proc-macro2" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rust-blockchain" -version = "0.1.0" -dependencies = [ - "chrono", - "serde", - "serde_json", - "sha3", -] - -[[package]] -name = "ryu" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" - -[[package]] -name = "serde" -version = "1.0.202" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.202" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha3" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" -dependencies = [ - "digest", - "keccak", -] - -[[package]] -name = "syn" -version = "2.0.65" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2863d96a84c6439701d7a38f9de935ec562c8832cc55d1dde0f513b52fad106" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasm-bindgen" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" - -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" diff --git a/Cargo.toml b/Cargo.toml index 2a71a19..941b3eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,3 +10,4 @@ chrono = "0.4.38" serde = { version = "1.0.202", features = ["derive"] } serde_json = "1.0.117" sha3 = "0.10.8" +tokio = { version = "1.37.0", features = ["full"] } diff --git a/configs/server_config.txt b/configs/server_config.txt new file mode 100644 index 0000000..695a094 --- /dev/null +++ b/configs/server_config.txt @@ -0,0 +1,3 @@ +server_address:127.0.0.1 +port:2434 +difficulty:1 \ No newline at end of file diff --git a/src/block.rs b/src/block.rs index 92c4665..9e77648 100644 --- a/src/block.rs +++ b/src/block.rs @@ -3,6 +3,7 @@ use std::time::{Duration, Instant}; use chrono::Utc; use serde::{Deserialize, Serialize}; use sha3::{Digest, Sha3_512}; +use tokio::sync::broadcast::Sender; use crate::blockchain::BlockChain; @@ -28,8 +29,14 @@ impl Block { format!("{:x}", hash) } - pub fn new(index: u64, data: String, previous_hash: String, instant: Instant) -> Self { - Block { + pub fn new( + index: u64, + data: String, + previous_hash: String, + instant: Instant, + block_data_channel_sender: Sender, + ) -> Self { + let block = Block { index, timestamp: Utc::now().timestamp_millis() as u64, data, @@ -37,7 +44,9 @@ impl Block { previous_hash, hash: String::new(), hash_time_cost: instant.elapsed(), - } + }; + let _ = block_data_channel_sender.send(block.clone()); + block } pub fn mine(&mut self, blockhain: BlockChain) -> Self { diff --git a/src/blockchain.rs b/src/blockchain.rs index a6a450c..d04e60e 100644 --- a/src/blockchain.rs +++ b/src/blockchain.rs @@ -1,10 +1,12 @@ use std::time::{Duration, Instant}; use chrono::Utc; +use serde::{Deserialize, Serialize}; +use tokio::sync::broadcast::Sender; use crate::block::Block; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct BlockChain { pub genesis_block: Block, pub chain: Vec, @@ -32,12 +34,18 @@ impl BlockChain { } } - pub fn add_block(&mut self, data: String, instant: Instant) { + pub fn add_block( + &mut self, + data: String, + instant: Instant, + block_data_channel_sender: Sender, + ) { let new_block = Block::new( self.chain.len() as u64, data, self.chain[&self.chain.len() - 1].hash.clone(), instant, + block_data_channel_sender, ) .mine(self.clone()); self.chain.push(new_block); diff --git a/src/lib.rs b/src/lib.rs index 3123eb7..89c2c4d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,17 @@ +use std::net::IpAddr; + pub mod block; pub mod blockchain; +pub mod network; +mod test; +pub mod utils; + +pub enum Runner { + Server, + Client, +} +pub struct ServerConfig { + pub server_address: IpAddr, + pub port: u16, + pub difficulty: u8, +} diff --git a/src/main.rs b/src/main.rs index eb88fa8..9cbe3c0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,24 +1,36 @@ -use std::time::Instant; +use rust_blockchain::{ + blockchain::BlockChain, + network::start_network, + utils::{read_server_config, take_args}, + Runner, +}; +use tokio::sync::broadcast; -use rust_blockchain::blockchain::BlockChain; - -fn main() { +#[tokio::main] +async fn main() { println!("Hello, world!"); - let difficulty = 1; - - let mut blockchain = BlockChain::new(difficulty); - let instant = Instant::now(); - BlockChain::add_block(&mut blockchain, "T".to_string(), Instant::now()); - BlockChain::add_block(&mut blockchain, "a".to_string(), Instant::now()); - BlockChain::add_block(&mut blockchain, "h".to_string(), Instant::now()); - BlockChain::add_block(&mut blockchain, "i".to_string(), Instant::now()); - BlockChain::add_block(&mut blockchain, "n".to_string(), Instant::now()); - BlockChain::add_block(&mut blockchain, "l".to_string(), Instant::now()); - BlockChain::add_block(&mut blockchain, "i".to_string(), Instant::now()); - println!( - "\t ⛏️⛏️⛏️ | Mined | ⛏️⛏️⛏️\n\n\tElapsed: {:?}\n\n{:#?}", - instant.elapsed(), - blockchain - ); + match take_args() { + Some(runner) => match runner { + Runner::Server => server().await, + Runner::Client => todo!(), + }, + None => return, + }; +} + +async fn server() { + let server_config = match read_server_config() { + Some(server_config) => server_config, + None => return, + }; + + let blockchain = BlockChain::new(server_config.difficulty.into()); + let block_data_channel_sender = broadcast::channel(1).0; + start_network( + server_config, + &blockchain, + block_data_channel_sender.subscribe(), + ) + .await; } diff --git a/src/network.rs b/src/network.rs new file mode 100644 index 0000000..c375599 --- /dev/null +++ b/src/network.rs @@ -0,0 +1,81 @@ +use tokio::{ + io::AsyncWriteExt, + net::{TcpListener, TcpStream}, + sync::broadcast::Receiver, +}; + +use crate::{block::Block, blockchain::BlockChain, ServerConfig}; + +pub async fn start_network( + server_config: ServerConfig, + blockchain: &BlockChain, + block_data_channel_receiver: Receiver, +) { + let listener_socket = match TcpListener::bind(format!( + "{}:{}", + server_config.server_address, server_config.port + )) + .await + { + Ok(listener_socket) => listener_socket, + Err(_) => return, + }; + + loop { + match listener_socket.accept().await { + Ok(connection) => { + tokio::spawn(sync( + connection.0, + blockchain.clone(), + block_data_channel_receiver.resubscribe(), + )); + } + Err(_) => {} + } + } +} + +async fn sync( + tcp_stream: TcpStream, + blockchain: BlockChain, + block_data_channel_receiver: Receiver, +) { + let tcp_stream = send_blockchain(tcp_stream, blockchain).await; + send_block(tcp_stream, block_data_channel_receiver).await; +} + +async fn send_blockchain(mut tcp_stream: TcpStream, blockchain: BlockChain) -> TcpStream { + let blockchain_data = serde_json::json!({ + "blockchain": blockchain + }) + .to_string(); + match tcp_stream.write_all(&blockchain_data.as_bytes()).await { + Ok(_) => match tcp_stream.flush().await { + Ok(_) => {} + Err(_) => {} + }, + Err(_) => {} + } + tcp_stream +} + +async fn send_block(mut tcp_stream: TcpStream, mut block_data_channel_receiver: Receiver) { + loop { + match block_data_channel_receiver.recv().await { + Ok(block) => { + let block_data = serde_json::json!({ + "block": block + }) + .to_string(); + match tcp_stream.write_all(&block_data.as_bytes()).await { + Ok(_) => match tcp_stream.flush().await { + Ok(_) => {} + Err(_) => {} + }, + Err(_) => {} + } + } + Err(_) => {} + } + } +} diff --git a/src/test.rs b/src/test.rs new file mode 100644 index 0000000..3c8f4a9 --- /dev/null +++ b/src/test.rs @@ -0,0 +1,52 @@ +#[cfg(test)] +use crate::blockchain::BlockChain; +#[cfg(test)] +use std::time::Duration; +#[cfg(test)] +use std::time::Instant; +#[cfg(test)] +use tokio::sync::broadcast::channel; + +#[tokio::test] +async fn create_blockchain() { + let blockchain = BlockChain::new(1); + assert_eq!(blockchain.difficulty, 1); + assert_eq!(blockchain.genesis_block.data, "Tahinli"); + assert_eq!(blockchain.genesis_block.hash, ""); + assert_eq!(blockchain.genesis_block.index, 0); + assert_eq!(blockchain.genesis_block.previous_hash, ""); + assert_eq!(blockchain.genesis_block.proof_of_work, 0); + assert_eq!( + blockchain.genesis_block.hash_time_cost, + Duration::from_secs(0) + ); + assert_eq!(blockchain.chain.len(), 1); + assert_eq!(blockchain.chain[0].data, "Tahinli"); + assert_eq!(blockchain.chain[0].hash, ""); + assert_eq!(blockchain.chain[0].index, 0); + assert_eq!(blockchain.chain[0].previous_hash, ""); + assert_eq!(blockchain.chain[0].proof_of_work, 0); + assert_eq!(blockchain.chain[0].hash_time_cost, Duration::from_secs(0)); +} +#[tokio::test] +async fn create_block() { + let instant = Instant::now(); + let mut blockchain = BlockChain::new(1); + let block_data_channel_sender = channel(1).0; + BlockChain::add_block( + &mut blockchain, + "Ahmet Kaan Gümüş".to_string(), + instant, + block_data_channel_sender.clone(), + ); + assert_eq!(blockchain.chain[0].data, "Tahinli"); + assert_eq!(blockchain.chain[0].hash, ""); + assert_eq!(blockchain.chain[0].index, 0); + assert_eq!(blockchain.chain[0].previous_hash, ""); + assert_eq!(blockchain.chain[0].proof_of_work, 0); + assert_eq!(blockchain.chain[0].hash_time_cost, Duration::from_secs(0)); + assert_eq!(blockchain.chain[1].data, "Ahmet Kaan Gümüş"); + assert_eq!(blockchain.chain[1].previous_hash, ""); + assert_eq!(blockchain.chain[1].index, 1); + assert_eq!(blockchain.chain.len(), 2); +} diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..ee0b880 --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,57 @@ +use std::{env, fs::File, io::Read}; + +use crate::{Runner, ServerConfig}; + +pub fn take_args() -> Option { + let args: Vec = env::args().collect(); + if args.len() > 1 { + match &args[1][..] { + "--server" => Some(Runner::Server), + "--client" => Some(Runner::Client), + _ => None, + } + } else { + None + } +} + +pub fn read_server_config() -> Option { + let mut server_config_file = match File::open("configs/server_config.txt") { + Ok(server_config_file) => server_config_file, + Err(_) => return None, + }; + let mut server_configs = String::new(); + match server_config_file.read_to_string(&mut server_configs) { + Ok(_) => { + let server_configs: Vec = + server_configs.split("\n").map(|x| x.to_string()).collect(); + let server_address = match server_configs[0].split(":").last() { + Some(server_address_unchecked) => match server_address_unchecked.parse() { + Ok(server_address) => server_address, + Err(_) => return None, + }, + None => return None, + }; + let port = match server_configs[1].split(":").last() { + Some(port_unchecked) => match port_unchecked.parse() { + Ok(port) => port, + Err(_) => return None, + }, + None => return None, + }; + let difficulty = match server_configs[2].split(":").last() { + Some(difficulty_unchecked) => match difficulty_unchecked.parse() { + Ok(difficulty) => difficulty, + Err(_) => return None, + }, + None => return None, + }; + Some(ServerConfig { + server_address, + port, + difficulty, + }) + } + Err(_) => None, + } +}