diff --git a/Cargo.toml b/Cargo.toml index 3ed6364..2950d0d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,44 +1,2 @@ -[package] -name = "RustySamovar" -version = "0.1.0" -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[features] -raw_packet_dump = [] - -[dependencies] -kcp = { path = "kcp" } -mhycrypt = { path = "mhycrypt" } -proto = { path = "proto" } -lua_serde = { path = "lua_serde" } -packet-processor-macro = { path = "packet-processor-macro" } -packet-processor = { path = "packet-processor" } -rs-ipc = { path = "rs-ipc" } -excel-hash-wrapper-macro = { path = "excel-hash-wrapper-macro" } - -prost = "0.8" -bytes = "1.1.0" -base64 = "0.13.0" -tokio = { version = "1", features = ["full"] } -futures = "0.3" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -pretty_env_logger = "0.4" -num-traits = "0.2" -num-derive = "0.3" -pretty-hex = "0.2" -sea-orm = { version = "0.7", features = [ "sqlx-all", "runtime-async-std-native-tls", "debug-print" ] } -#hostname = "0.3" -#local-ip-address = "0.4" -chrono = "0.4" -rand = "0.8" -tracing = "0.1" -tracing-subscriber = { version = "0.3", features = ["env-filter"] } - -[target.'cfg(windows)'.dependencies] -openssl = { version = "0.10", features = ["vendored"] } - -[target.'cfg(unix)'.dependencies] -openssl = "0.10" +[workspace] +members = ["RustySamovar", "Kalitka"] diff --git a/Kalitka/Cargo.toml b/Kalitka/Cargo.toml new file mode 100644 index 0000000..f066fb4 --- /dev/null +++ b/Kalitka/Cargo.toml @@ -0,0 +1,46 @@ +[package] +name = "Kalitka" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[features] +raw_packet_dump = [] + +[dependencies] +kcp = { path = "../kcp" } +mhycrypt = { path = "../mhycrypt" } +proto = { path = "../proto" } +#lua_serde = { path = "../lua_serde" } +packet-processor-macro = { path = "../packet-processor-macro" } +packet-processor = { path = "../packet-processor" } +rs-ipc = { path = "../rs-ipc" } +#excel-hash-wrapper-macro = { path = "../excel-hash-wrapper-macro" } +rs-nodeconf = { path = "../rs-nodeconf" } +rs-utils = { path = "../rs-utils" } + +prost = "0.8" +bytes = "1.1.0" +base64 = "0.13.0" +#tokio = { version = "1", features = ["full"] } +#futures = "0.3" +#serde = { version = "1.0", features = ["derive"] } +#serde_json = "1.0" +pretty_env_logger = "0.4" +num-traits = "0.2" +num-derive = "0.3" +pretty-hex = "0.2" +#sea-orm = { version = "0.7", features = [ "sqlx-all", "runtime-async-std-native-tls", "debug-print" ] } +#hostname = "0.3" +#local-ip-address = "0.4" +chrono = "0.4" +rand = "0.8" +tracing = "0.1" +tracing-subscriber = { version = "0.3", features = ["env-filter"] } + +[target.'cfg(windows)'.dependencies] +openssl = { version = "0.10", features = ["vendored"] } + +[target.'cfg(unix)'.dependencies] +openssl = "0.10" diff --git a/Kalitka/src/main.rs b/Kalitka/src/main.rs new file mode 100644 index 0000000..6ec1526 --- /dev/null +++ b/Kalitka/src/main.rs @@ -0,0 +1,27 @@ +extern crate pretty_env_logger; + +extern crate tracing_subscriber; + +#[macro_use] +extern crate num_derive; + +use std::thread; + +mod server; +mod utils; + +use server::NetworkServer; + +fn main() { + //pretty_env_logger::init(); + + //let mut rt_main = tokio::runtime::Runtime::new().unwrap(); + + tracing_subscriber::fmt() + .with_max_level(tracing::Level::DEBUG) + .with_test_writer() + .init(); + + let mut ns = NetworkServer::new("0.0.0.0", 4242).unwrap(); + ns.run().expect("Failed to serve!"); +} diff --git a/Kalitka/src/server/auth_manager.rs b/Kalitka/src/server/auth_manager.rs new file mode 100644 index 0000000..6bdc0e3 --- /dev/null +++ b/Kalitka/src/server/auth_manager.rs @@ -0,0 +1,137 @@ +use openssl::hash::MessageDigest; +use openssl::pkey::PKey; +use openssl::rsa::Padding; +use openssl::sign::Signer; +use std::sync::mpsc; +use std::collections::HashMap; +use std::convert::TryInto; + +use prost::Message; + +use rs_ipc::{IpcMessage, PushSocket}; + +use packet_processor_macro::*; +#[macro_use] +use packet_processor::*; +use rs_nodeconf::NodeConfig; + +#[packet_processor(GetPlayerTokenReq)] +pub struct AuthManager { + conv_to_user: HashMap, + user_to_conv: HashMap, + //packets_to_send_tx: mpsc::Sender, + packets_to_send_tx: PushSocket, +} + +impl AuthManager { + pub const SPOOFED_PLAYER_UID: u32 = 1337; + + pub fn new(node_config: &NodeConfig) -> AuthManager { + let mut am = AuthManager { + conv_to_user: HashMap::new(), + user_to_conv: HashMap::new(), + packet_callbacks: HashMap::new(), + packets_to_send_tx: node_config.connect_out_queue().unwrap(), + }; + + am.register(); + + return am; + } + + pub fn process_get_player_token(&mut self, conv: u32, metadata: &proto::PacketHead, req: &proto::GetPlayerTokenReq, rsp: &mut proto::GetPlayerTokenRsp) { + let seed: u64 = 0xBABECAFEF00D; // TODO: use real value! + let client_hardcoded_seed: u64 = 0x12345678; + let uid = self.get_uid_by_account_id(req.account_uid.parse().unwrap()); + + rsp.account_type = req.account_type; + rsp.account_uid = req.account_uid.clone(); + rsp.token = req.account_token.clone(); + rsp.secret_key_seed = seed; // TODO: temporary workaround! + rsp.uid = uid; + + if req.key_id > 0 { // TODO: detect client version properly! + // Versions 2.7.5x+ use different algorithm for key initialization + + // TODO: as of now (2022-05-16) this algorithm here is more of a PoC, because we can't really sign the data + // or decrypt the client seed we're getting from the client. + // + // Connecting to our server still requires patching the client to disable signature verification and hardcoding + // some known client seed value. This will allow the patched client to connect to official servers (beware of + // the ban for modding the client!) + // + // An alternative approach to hardcoding the client seed would be to employ RCE in WindSeedClientNotify to extract + // the seed from the client itself. That still would require patching the client though (to allow invalid signatures), + // so it's of a very little difference to us. + // + // Another alternative is to replace keys inside global-metadata.dat file, but that requires writing an encryption + // tool. While still possible, it's tiresome, and won't allow patched client to connect to official server without + // switching back and forth between two versions of global-metadata.dat file. + + let key_id = req.key_id as u8; + + let rsa_key_collection = mhycrypt::load_rsa_keys("RSAConfig", "keys"); + let keys = match rsa_key_collection.get(&key_id) { + Some(keys) => keys, + None => panic!("Unknown key ID {}!", key_id), + }; + + // Decrypt received client seed + + let client_seed_encrypted = base64::decode(&req.client_rand_key).unwrap(); + + let mut dec_buf: Vec = vec![0; 256]; + + let client_seed = match keys.signing_key.private_decrypt(&client_seed_encrypted, &mut dec_buf, Padding::PKCS1) { + Ok(seed_size) => { + // Note: from_be_bytes here, because client seems to swap order of bytes for the seed + u64::from_be_bytes(dec_buf[0..seed_size].try_into().unwrap()) + }, + Err(e) => { // TODO: must panic here! + println!("Error decrypting client seed: {}", e); + client_hardcoded_seed // TODO: temporary workaround! + }, + }; + + // Encrypt server seed which we'll use in negotiating with the client + + let mut enc_buf: Vec = vec![0; 256]; + + // Note: to_be_bytes here, because client seems to swap order of bytes for the seed + let seed_bytes = (seed ^ client_seed).to_be_bytes(); + + let len = keys.encrypt_key.public_encrypt(&seed_bytes, &mut enc_buf, Padding::PKCS1).unwrap(); + + // Sign it + let keypair = PKey::from_rsa(keys.signing_key.clone()).unwrap(); + let mut signer = Signer::new(MessageDigest::sha256(), &keypair).unwrap(); + let signature = signer.sign_oneshot_to_vec(&seed_bytes).unwrap(); + + rsp.key_id = key_id as u32; + rsp.server_rand_key = base64::encode(&enc_buf); + rsp.sign = base64::encode(&signature); + } + + self.conv_to_user.insert(conv, uid); + self.user_to_conv.insert(uid, conv); + } + + fn get_uid_by_account_id(&self, account_uid: u32) -> u32 { + // TODO! + return AuthManager::SPOOFED_PLAYER_UID; + } + + pub fn resolve_conv(&self, conv: u32) -> Option { + match self.conv_to_user.get(&conv) { + Some(uid) => return Some(*uid), + None => return None, + }; + } + + pub fn resolve_uid(&self, uid: u32) -> Option { + match self.user_to_conv.get(&uid) { + Some(conv) => return Some(*conv), + None => return None, + }; + } +} diff --git a/Kalitka/src/server/client_connection.rs b/Kalitka/src/server/client_connection.rs new file mode 100644 index 0000000..e5f3c26 --- /dev/null +++ b/Kalitka/src/server/client_connection.rs @@ -0,0 +1,121 @@ +use std::io; +use std::io::Read; +use std::fs; +use std::net::SocketAddr; +use std::net::UdpSocket; +use std::io::Write; +use std::time::SystemTime; +use std::convert::TryInto; + +use rs_utils::TimeManager; + +extern crate kcp; +extern crate mhycrypt; + +use kcp::Kcp; + +pub struct ClientConnection { + conv: u32, + token: u32, + ikcp: Kcp, + established_time: SystemTime, + key: [u8; 0x1000], + pending_seed: Option, +} + +pub struct Source +{ + address: Option, + socket: UdpSocket, +} + +impl Write for Source { + fn write(&mut self, data: &[u8]) -> io::Result { + return self.socket.send_to(data, self.address.expect("Unknown destination address!")); + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl ClientConnection { + pub fn new(socket: UdpSocket, conv: u32, token: u32) -> ClientConnection { + let s = Source { + address: None, + socket: socket, + }; + + return ClientConnection { + conv: conv, + token: token, + ikcp: Kcp::new(conv, token, s), + established_time: SystemTime::now(), + key: ClientConnection::read_key("master").try_into().expect("Incorrect master key"), + pending_seed: None, + }; + } + + pub fn update_source(&mut self, new_source: SocketAddr) { + self.ikcp.output.0.address = Some(new_source); + } + + pub fn process_udp_packet(&mut self, data: &[u8]) -> Vec> { + match self.pending_seed { + None => {}, + Some(seed) => { + mhycrypt::mhy_generate_key(&mut self.key, seed, false); + self.pending_seed = None; + }, + } + + let mut packets: Vec> = Vec::new(); + self.ikcp.input(data).unwrap(); + self.ikcp.update(self.elapsed_time_millis()).unwrap(); + self.ikcp.flush().unwrap(); + loop { + let mut buf = [0u8; 0x20000]; + match self.ikcp.recv(&mut buf) { + Err(_) => break, + Ok(size) => { + #[cfg(feature = "raw_packet_dump")] + { + use pretty_hex::*; + let cfg = HexConfig {title: true, width: 16, group: 0, ascii: true, ..HexConfig::default() }; + println!("{:?}", buf[..size].to_vec().hex_conf(cfg)); + } + mhycrypt::mhy_xor(&mut buf[..size], &self.key); + let data = buf[..size].to_owned(); + packets.push(data); + }, + } + } + self.ikcp.update(self.elapsed_time_millis()).unwrap(); + return packets; + } + + pub fn update_key(&mut self, seed: u64) { + self.pending_seed = Some(seed); + } + + fn read_key(key_name: &str) -> Vec { + let filename = format!("./{}/{}.key", "keys", key_name); + let mut f = fs::File::open(&filename).expect(&format!("File '{}' not found", filename)); + let metadata = fs::metadata(&filename).expect("unable to read metadata"); + let mut buffer = vec![0; metadata.len() as usize]; + f.read(&mut buffer).expect("buffer overflow"); + return buffer; + } + + fn elapsed_time_millis(&self) -> u32 { + return TimeManager::duration_since(self.established_time).try_into().unwrap(); + } + + pub fn send_udp_packet(&mut self, data: &[u8]) { + let mut buf = data.to_owned(); + mhycrypt::mhy_xor(&mut buf, &self.key); + self.ikcp.send(&buf).expect("Failed to send data!"); + self.ikcp.flush().unwrap(); + self.ikcp.update(self.elapsed_time_millis()).unwrap(); + } +} diff --git a/Kalitka/src/server/mod.rs b/Kalitka/src/server/mod.rs new file mode 100644 index 0000000..68a4201 --- /dev/null +++ b/Kalitka/src/server/mod.rs @@ -0,0 +1,9 @@ +mod network_server; +mod auth_manager; +//mod login_manager; +mod client_connection; + +pub use self::network_server::NetworkServer; +pub use self::auth_manager::AuthManager; +//pub use self::login_manager::LoginManager; +pub use self::client_connection::ClientConnection; diff --git a/Kalitka/src/server/network_server.rs b/Kalitka/src/server/network_server.rs new file mode 100644 index 0000000..df045e1 --- /dev/null +++ b/Kalitka/src/server/network_server.rs @@ -0,0 +1,236 @@ +use std::fmt; +use std::net::UdpSocket; +use std::net::SocketAddr; +use std::collections::HashMap; +use std::io::Cursor; +use std::thread; +use std::sync::mpsc; +use std::sync::{Arc, RwLock, Mutex}; + +use num_derive::FromPrimitive; +use num_traits::FromPrimitive; +use num_derive::ToPrimitive; +use num_traits::ToPrimitive; + +use crate::utils::HandshakePacket; +use crate::utils::DataPacket; +use crate::server::ClientConnection; +use crate::server::AuthManager; + +use rs_ipc::{IpcMessage, PullSocket, PushSocket}; + +use proto::PacketHead; +use proto::GetPlayerTokenRsp; + +use prost::Message; + +use rs_ipc::{SubSocket, PubSocket}; + +use packet_processor::{PacketProcessor, EasilyUnpackable}; +use rs_nodeconf::NodeConfig; + +extern crate kcp; + +// ------------- + +pub struct NetworkServer { + socket: UdpSocket, + clients: Arc>>, + node_config: NodeConfig, + packets_to_process_tx: PubSocket, +} + +#[derive(Debug, Clone)] +pub struct NetworkServerError { + reason: String, +} + +impl NetworkServerError { + pub fn new(reason: &str) -> NetworkServerError { + return NetworkServerError {reason: reason.to_string()}; + } +} + +impl fmt::Display for NetworkServerError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "NetworkServerError: {}", self.reason) + } +} + +impl NetworkServer { + pub fn new(host: &str, port: i16) -> Result { + let node_config = NodeConfig::new(); + + let mut packets_to_process_tx = node_config.bind_in_queue().unwrap(); + + let gs = NetworkServer { + socket: match UdpSocket::bind(format!("{}:{}", host, port).to_string()) { + Ok(socket) => socket, + Err(e) => return Err(NetworkServerError::new(format!("Failed to bind socket: {}", e).as_str())), + }, + clients: Arc::new(Mutex::new(HashMap::new())), + node_config: node_config, + packets_to_process_tx: packets_to_process_tx, + }; + + print!("Connection established\n"); + + return Ok(gs); + } + + pub fn run(&mut self) -> Result { + print!("Starting server\n"); + + let mut packets_to_send_rx = self.node_config.bind_out_queue().unwrap(); + + let clients = self.clients.clone(); + let mut auth_manager = Arc::new(Mutex::new(AuthManager::new(&self.node_config))); + let am = auth_manager.clone(); + + let packet_relaying_thread = thread::spawn(move || { + loop { + let IpcMessage(packet_id, user_id, metadata, data) = packets_to_send_rx.recv().unwrap(); + + let conv = match packet_id { + proto::PacketId::GetPlayerTokenRsp => user_id, // Mapping is not performed on those + _ => am.lock().unwrap().resolve_uid(user_id).unwrap_or_else(|| panic!("Unknown user ID {}!", user_id)), + }; + + let data_packet = DataPacket::new(packet_id.clone() as u16, metadata, data.clone()); + + match clients.lock().unwrap().get_mut(&conv) { + Some(client) => { + let bytes = data_packet.to_bytes(); + client.send_udp_packet(&bytes); + + if packet_id == proto::PacketId::GetPlayerTokenRsp { + // TODO: a bit hacky! + let token_rsp: GetPlayerTokenRsp = EasilyUnpackable::from(&data); + client.update_key(token_rsp.secret_key_seed); + } + }, + None => panic!("Unknown client conv: {}", conv), + }; + } + }); + + let mut buffer = [0u8; 65536]; + + loop { + match self.socket.recv_from(&mut buffer) { + Ok( (bytes_number, source_address) ) => self.process_udp_packet(source_address, &buffer[..bytes_number], &mut auth_manager), + Err(e) => panic!("Failed to receive data: {}", e), + } + } + + //packet_relaying_thread.join().unwrap(); + + return Ok(0); + } + + fn process_udp_packet(&mut self, source_address: SocketAddr, packet_bytes: &[u8], auth_manager: &mut Arc>) { + //print!("Received packet! Len = {}\n", packet_bytes.len()); + + let hs_packet = HandshakePacket::new(packet_bytes); + + match hs_packet { + Ok(hs_packet) => { + //print!("Received handshake packet: {:#?}\n", hs_packet); + if hs_packet.is_connect() { + //print!("Sending reply to CONNECT\n"); + // TODO: assign conv and token! + let conv = 0x96969696u32; + let token = 0x42424242u32; + + let reply = HandshakePacket::new_conv(conv, token); + + let mut client = ClientConnection::new(self.socket.try_clone().unwrap(), conv, token); + client.update_source(source_address); + + self.clients.lock().unwrap().insert(conv, client); + + self.socket.send_to(&reply.to_bytes(), source_address).expect("Failed to send data!"); + } + }, + Err(e) => { + //print!("Error constructing handshake: {:#?}", e); + let conv = kcp::get_conv(packet_bytes); + + let packets = match self.clients.lock().unwrap().get_mut(&conv) { + Some(client) => { + client.update_source(source_address); + + client.process_udp_packet(packet_bytes) + } + None => panic!("Unknown client conv: {}", conv), + }; + + for packet in packets.iter() { + self.process_game_packet(conv, packet, auth_manager); + } + }, + }; + } + + fn process_game_packet(&mut self, conv: u32, packet: &[u8], auth_manager: &mut Arc>) { + let data = match DataPacket::new_from_bytes(packet) { + Ok(data) => data, + Err(e) => panic!("Malformed data packet: {:#?}!", e), + }; + + let head = match PacketHead::decode(&mut Cursor::new(&data.metadata)) { + Ok(head) => head, + Err(e) => panic!("Malformed packet header: {:#?}!", e), + }; + + let packet_id: proto::PacketId = match FromPrimitive::from_u16(data.packet_id) { + Some(packet_id) => packet_id, + None => { + println!("Skipping unknown packet ID {}", data.packet_id); + return; + } + }; + + let user_id = match packet_id { + proto::PacketId::GetPlayerTokenReq => { + auth_manager.lock().unwrap().process(conv, packet_id, data.metadata, data.data); + return; + }, + _ => match auth_manager.lock().unwrap().resolve_conv(conv) { + None => { + println!("Unknown user with conv {}! Skipping", conv); + return; + }, + Some(user_id) => user_id, + }, + }; + + if packet_id == proto::PacketId::UnionCmdNotify { + let union: proto::UnionCmdNotify = EasilyUnpackable::from(&data.data); + for u_cmd in union.cmd_list.into_iter() { + self.send_packet_to_process(user_id, u_cmd.message_id as u16, &data.metadata, &u_cmd.body); + } + } else { + self.send_packet_to_process(user_id, data.packet_id, &data.metadata, &data.data); + } + } + + fn send_packet_to_process(&mut self, user_id: u32, packet_id: u16, metadata: &[u8], data: &[u8]) + { + /*let sender: &mut PubSocket = match &self.packets_to_process_tx { + Some(mut sender) => &mut sender, + None => panic!("Processing queue wasn't set up!"), + };*/ + + let packet_id: proto::PacketId = match FromPrimitive::from_u16(packet_id) { + Some(packet_id) => packet_id, + None => { + println!("Skipping unknown packet ID {}", packet_id); + return; + }, + }; + + println!("Got packet {:?}", packet_id); + self.packets_to_process_tx.send( IpcMessage(packet_id, user_id, metadata.to_vec(), data.to_vec()) ); + } +} diff --git a/src/utils/data_packet.rs b/Kalitka/src/utils/data_packet.rs similarity index 100% rename from src/utils/data_packet.rs rename to Kalitka/src/utils/data_packet.rs diff --git a/src/utils/handshake_packet.rs b/Kalitka/src/utils/handshake_packet.rs similarity index 100% rename from src/utils/handshake_packet.rs rename to Kalitka/src/utils/handshake_packet.rs diff --git a/Kalitka/src/utils/mod.rs b/Kalitka/src/utils/mod.rs new file mode 100644 index 0000000..5d442f9 --- /dev/null +++ b/Kalitka/src/utils/mod.rs @@ -0,0 +1,15 @@ +mod handshake_packet; +mod data_packet; +/*mod id_manager; +mod time_manager; +mod avatar_builder;*/ +/* +#[macro_use] +mod remapper; +*/ +pub use self::handshake_packet::HandshakePacket; +pub use self::data_packet::DataPacket; +/*pub use self::id_manager::IdManager; +pub use self::time_manager::TimeManager; +pub use self::remapper::Remapper; +pub use self::avatar_builder::AvatarBuilder;*/ \ No newline at end of file diff --git a/RustySamovar/Cargo.toml b/RustySamovar/Cargo.toml new file mode 100644 index 0000000..b362c60 --- /dev/null +++ b/RustySamovar/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "RustySamovar" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[features] +raw_packet_dump = [] + +[dependencies] +kcp = { path = "../kcp" } +mhycrypt = { path = "../mhycrypt" } +proto = { path = "../proto" } +lua_serde = { path = "../lua_serde" } +packet-processor-macro = { path = "../packet-processor-macro" } +packet-processor = { path = "../packet-processor" } +rs-ipc = { path = "../rs-ipc" } +excel-hash-wrapper-macro = { path = "../excel-hash-wrapper-macro" } + +prost = "0.8" +bytes = "1.1.0" +base64 = "0.13.0" +tokio = { version = "1", features = ["full"] } +futures = "0.3" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +pretty_env_logger = "0.4" +num-traits = "0.2" +num-derive = "0.3" +pretty-hex = "0.2" +sea-orm = { version = "0.7", features = [ "sqlx-all", "runtime-async-std-native-tls", "debug-print" ] } +#hostname = "0.3" +#local-ip-address = "0.4" +chrono = "0.4" +rand = "0.8" +tracing = "0.1" +tracing-subscriber = { version = "0.3", features = ["env-filter"] } + +[target.'cfg(windows)'.dependencies] +openssl = { version = "0.10", features = ["vendored"] } + +[target.'cfg(unix)'.dependencies] +openssl = "0.10" diff --git a/src/dbmanager/avatar_fight_prop.rs b/RustySamovar/src/dbmanager/avatar_fight_prop.rs similarity index 100% rename from src/dbmanager/avatar_fight_prop.rs rename to RustySamovar/src/dbmanager/avatar_fight_prop.rs diff --git a/src/dbmanager/avatar_info.rs b/RustySamovar/src/dbmanager/avatar_info.rs similarity index 100% rename from src/dbmanager/avatar_info.rs rename to RustySamovar/src/dbmanager/avatar_info.rs diff --git a/src/dbmanager/avatar_prop.rs b/RustySamovar/src/dbmanager/avatar_prop.rs similarity index 100% rename from src/dbmanager/avatar_prop.rs rename to RustySamovar/src/dbmanager/avatar_prop.rs diff --git a/src/dbmanager/avatar_reliquary.rs b/RustySamovar/src/dbmanager/avatar_reliquary.rs similarity index 100% rename from src/dbmanager/avatar_reliquary.rs rename to RustySamovar/src/dbmanager/avatar_reliquary.rs diff --git a/src/dbmanager/avatar_team_info.rs b/RustySamovar/src/dbmanager/avatar_team_info.rs similarity index 100% rename from src/dbmanager/avatar_team_info.rs rename to RustySamovar/src/dbmanager/avatar_team_info.rs diff --git a/src/dbmanager/avatar_weapon.rs b/RustySamovar/src/dbmanager/avatar_weapon.rs similarity index 100% rename from src/dbmanager/avatar_weapon.rs rename to RustySamovar/src/dbmanager/avatar_weapon.rs diff --git a/src/dbmanager/database_manager.rs b/RustySamovar/src/dbmanager/database_manager.rs similarity index 100% rename from src/dbmanager/database_manager.rs rename to RustySamovar/src/dbmanager/database_manager.rs diff --git a/src/dbmanager/equip_info.rs b/RustySamovar/src/dbmanager/equip_info.rs similarity index 100% rename from src/dbmanager/equip_info.rs rename to RustySamovar/src/dbmanager/equip_info.rs diff --git a/src/dbmanager/furniture_info.rs b/RustySamovar/src/dbmanager/furniture_info.rs similarity index 100% rename from src/dbmanager/furniture_info.rs rename to RustySamovar/src/dbmanager/furniture_info.rs diff --git a/src/dbmanager/item_info.rs b/RustySamovar/src/dbmanager/item_info.rs similarity index 100% rename from src/dbmanager/item_info.rs rename to RustySamovar/src/dbmanager/item_info.rs diff --git a/src/dbmanager/material_info.rs b/RustySamovar/src/dbmanager/material_info.rs similarity index 100% rename from src/dbmanager/material_info.rs rename to RustySamovar/src/dbmanager/material_info.rs diff --git a/src/dbmanager/mod.rs b/RustySamovar/src/dbmanager/mod.rs similarity index 100% rename from src/dbmanager/mod.rs rename to RustySamovar/src/dbmanager/mod.rs diff --git a/src/dbmanager/open_state.rs b/RustySamovar/src/dbmanager/open_state.rs similarity index 100% rename from src/dbmanager/open_state.rs rename to RustySamovar/src/dbmanager/open_state.rs diff --git a/src/dbmanager/player_info.rs b/RustySamovar/src/dbmanager/player_info.rs similarity index 100% rename from src/dbmanager/player_info.rs rename to RustySamovar/src/dbmanager/player_info.rs diff --git a/src/dbmanager/player_prop.rs b/RustySamovar/src/dbmanager/player_prop.rs similarity index 100% rename from src/dbmanager/player_prop.rs rename to RustySamovar/src/dbmanager/player_prop.rs diff --git a/src/dbmanager/reliquary_info.rs b/RustySamovar/src/dbmanager/reliquary_info.rs similarity index 100% rename from src/dbmanager/reliquary_info.rs rename to RustySamovar/src/dbmanager/reliquary_info.rs diff --git a/src/dbmanager/reliquary_prop.rs b/RustySamovar/src/dbmanager/reliquary_prop.rs similarity index 100% rename from src/dbmanager/reliquary_prop.rs rename to RustySamovar/src/dbmanager/reliquary_prop.rs diff --git a/src/dbmanager/scene_info.rs b/RustySamovar/src/dbmanager/scene_info.rs similarity index 100% rename from src/dbmanager/scene_info.rs rename to RustySamovar/src/dbmanager/scene_info.rs diff --git a/src/dbmanager/team_info.rs b/RustySamovar/src/dbmanager/team_info.rs similarity index 100% rename from src/dbmanager/team_info.rs rename to RustySamovar/src/dbmanager/team_info.rs diff --git a/src/dbmanager/team_selection_info.rs b/RustySamovar/src/dbmanager/team_selection_info.rs similarity index 100% rename from src/dbmanager/team_selection_info.rs rename to RustySamovar/src/dbmanager/team_selection_info.rs diff --git a/src/dbmanager/trans_point.rs b/RustySamovar/src/dbmanager/trans_point.rs similarity index 100% rename from src/dbmanager/trans_point.rs rename to RustySamovar/src/dbmanager/trans_point.rs diff --git a/src/dbmanager/weapon_affix_info.rs b/RustySamovar/src/dbmanager/weapon_affix_info.rs similarity index 100% rename from src/dbmanager/weapon_affix_info.rs rename to RustySamovar/src/dbmanager/weapon_affix_info.rs diff --git a/src/entitymanager/entities.rs b/RustySamovar/src/entitymanager/entities.rs similarity index 100% rename from src/entitymanager/entities.rs rename to RustySamovar/src/entitymanager/entities.rs diff --git a/src/entitymanager/entity_manager.rs b/RustySamovar/src/entitymanager/entity_manager.rs similarity index 100% rename from src/entitymanager/entity_manager.rs rename to RustySamovar/src/entitymanager/entity_manager.rs diff --git a/src/entitymanager/mod.rs b/RustySamovar/src/entitymanager/mod.rs similarity index 100% rename from src/entitymanager/mod.rs rename to RustySamovar/src/entitymanager/mod.rs diff --git a/src/jsonmanager/avatar.rs b/RustySamovar/src/jsonmanager/avatar.rs similarity index 100% rename from src/jsonmanager/avatar.rs rename to RustySamovar/src/jsonmanager/avatar.rs diff --git a/src/jsonmanager/avatar_skill.rs b/RustySamovar/src/jsonmanager/avatar_skill.rs similarity index 100% rename from src/jsonmanager/avatar_skill.rs rename to RustySamovar/src/jsonmanager/avatar_skill.rs diff --git a/src/jsonmanager/avatar_skill_depot.rs b/RustySamovar/src/jsonmanager/avatar_skill_depot.rs similarity index 100% rename from src/jsonmanager/avatar_skill_depot.rs rename to RustySamovar/src/jsonmanager/avatar_skill_depot.rs diff --git a/src/jsonmanager/entity_curve.rs b/RustySamovar/src/jsonmanager/entity_curve.rs similarity index 100% rename from src/jsonmanager/entity_curve.rs rename to RustySamovar/src/jsonmanager/entity_curve.rs diff --git a/src/jsonmanager/gadget_prop.rs b/RustySamovar/src/jsonmanager/gadget_prop.rs similarity index 100% rename from src/jsonmanager/gadget_prop.rs rename to RustySamovar/src/jsonmanager/gadget_prop.rs diff --git a/src/jsonmanager/gather.rs b/RustySamovar/src/jsonmanager/gather.rs similarity index 100% rename from src/jsonmanager/gather.rs rename to RustySamovar/src/jsonmanager/gather.rs diff --git a/src/jsonmanager/json_manager.rs b/RustySamovar/src/jsonmanager/json_manager.rs similarity index 100% rename from src/jsonmanager/json_manager.rs rename to RustySamovar/src/jsonmanager/json_manager.rs diff --git a/src/jsonmanager/material.rs b/RustySamovar/src/jsonmanager/material.rs similarity index 100% rename from src/jsonmanager/material.rs rename to RustySamovar/src/jsonmanager/material.rs diff --git a/src/jsonmanager/mod.rs b/RustySamovar/src/jsonmanager/mod.rs similarity index 100% rename from src/jsonmanager/mod.rs rename to RustySamovar/src/jsonmanager/mod.rs diff --git a/src/jsonmanager/monster.rs b/RustySamovar/src/jsonmanager/monster.rs similarity index 100% rename from src/jsonmanager/monster.rs rename to RustySamovar/src/jsonmanager/monster.rs diff --git a/src/jsonmanager/proud_skill.rs b/RustySamovar/src/jsonmanager/proud_skill.rs similarity index 100% rename from src/jsonmanager/proud_skill.rs rename to RustySamovar/src/jsonmanager/proud_skill.rs diff --git a/src/jsonmanager/reliquary.rs b/RustySamovar/src/jsonmanager/reliquary.rs similarity index 100% rename from src/jsonmanager/reliquary.rs rename to RustySamovar/src/jsonmanager/reliquary.rs diff --git a/src/jsonmanager/scene.rs b/RustySamovar/src/jsonmanager/scene.rs similarity index 100% rename from src/jsonmanager/scene.rs rename to RustySamovar/src/jsonmanager/scene.rs diff --git a/src/jsonmanager/shop_goods.rs b/RustySamovar/src/jsonmanager/shop_goods.rs similarity index 100% rename from src/jsonmanager/shop_goods.rs rename to RustySamovar/src/jsonmanager/shop_goods.rs diff --git a/src/jsonmanager/shop_rotate.rs b/RustySamovar/src/jsonmanager/shop_rotate.rs similarity index 100% rename from src/jsonmanager/shop_rotate.rs rename to RustySamovar/src/jsonmanager/shop_rotate.rs diff --git a/src/jsonmanager/teleport_point.rs b/RustySamovar/src/jsonmanager/teleport_point.rs similarity index 100% rename from src/jsonmanager/teleport_point.rs rename to RustySamovar/src/jsonmanager/teleport_point.rs diff --git a/src/jsonmanager/weapon.rs b/RustySamovar/src/jsonmanager/weapon.rs similarity index 100% rename from src/jsonmanager/weapon.rs rename to RustySamovar/src/jsonmanager/weapon.rs diff --git a/src/jsonmanager/world_level.rs b/RustySamovar/src/jsonmanager/world_level.rs similarity index 100% rename from src/jsonmanager/world_level.rs rename to RustySamovar/src/jsonmanager/world_level.rs diff --git a/src/luamanager/lua_manager.rs b/RustySamovar/src/luamanager/lua_manager.rs similarity index 100% rename from src/luamanager/lua_manager.rs rename to RustySamovar/src/luamanager/lua_manager.rs diff --git a/src/luamanager/mod.rs b/RustySamovar/src/luamanager/mod.rs similarity index 100% rename from src/luamanager/mod.rs rename to RustySamovar/src/luamanager/mod.rs diff --git a/src/luamanager/scene_config.rs b/RustySamovar/src/luamanager/scene_config.rs similarity index 100% rename from src/luamanager/scene_config.rs rename to RustySamovar/src/luamanager/scene_config.rs diff --git a/src/main.rs b/RustySamovar/src/main.rs similarity index 100% rename from src/main.rs rename to RustySamovar/src/main.rs diff --git a/src/node/config.rs b/RustySamovar/src/node/config.rs similarity index 100% rename from src/node/config.rs rename to RustySamovar/src/node/config.rs diff --git a/src/node/mod.rs b/RustySamovar/src/node/mod.rs similarity index 100% rename from src/node/mod.rs rename to RustySamovar/src/node/mod.rs diff --git a/src/server/auth_manager.rs b/RustySamovar/src/server/auth_manager.rs similarity index 100% rename from src/server/auth_manager.rs rename to RustySamovar/src/server/auth_manager.rs diff --git a/src/server/client_connection.rs b/RustySamovar/src/server/client_connection.rs similarity index 100% rename from src/server/client_connection.rs rename to RustySamovar/src/server/client_connection.rs diff --git a/src/server/game_server.rs b/RustySamovar/src/server/game_server.rs similarity index 100% rename from src/server/game_server.rs rename to RustySamovar/src/server/game_server.rs diff --git a/src/server/game_world.rs b/RustySamovar/src/server/game_world.rs similarity index 100% rename from src/server/game_world.rs rename to RustySamovar/src/server/game_world.rs diff --git a/src/server/login_manager.rs b/RustySamovar/src/server/login_manager.rs similarity index 100% rename from src/server/login_manager.rs rename to RustySamovar/src/server/login_manager.rs diff --git a/src/server/mod.rs b/RustySamovar/src/server/mod.rs similarity index 100% rename from src/server/mod.rs rename to RustySamovar/src/server/mod.rs diff --git a/src/server/network_server.rs b/RustySamovar/src/server/network_server.rs similarity index 99% rename from src/server/network_server.rs rename to RustySamovar/src/server/network_server.rs index 5961fcc..49ecf99 100644 --- a/src/server/network_server.rs +++ b/RustySamovar/src/server/network_server.rs @@ -22,7 +22,7 @@ use rs_ipc::{IpcMessage, PullSocket, PushSocket}; use proto::PacketHead; use proto::GetPlayerTokenRsp; -use proto::get_player_token_rsp; +//use proto::get_player_token_rsp; use prost::Message; diff --git a/src/subsystems/entity_subsystem/entity_subsystem.rs b/RustySamovar/src/subsystems/entity_subsystem/entity_subsystem.rs similarity index 100% rename from src/subsystems/entity_subsystem/entity_subsystem.rs rename to RustySamovar/src/subsystems/entity_subsystem/entity_subsystem.rs diff --git a/src/subsystems/entity_subsystem/mod.rs b/RustySamovar/src/subsystems/entity_subsystem/mod.rs similarity index 100% rename from src/subsystems/entity_subsystem/mod.rs rename to RustySamovar/src/subsystems/entity_subsystem/mod.rs diff --git a/src/subsystems/inventory_subsystem/inventory_subsystem.rs b/RustySamovar/src/subsystems/inventory_subsystem/inventory_subsystem.rs similarity index 100% rename from src/subsystems/inventory_subsystem/inventory_subsystem.rs rename to RustySamovar/src/subsystems/inventory_subsystem/inventory_subsystem.rs diff --git a/src/subsystems/inventory_subsystem/mod.rs b/RustySamovar/src/subsystems/inventory_subsystem/mod.rs similarity index 100% rename from src/subsystems/inventory_subsystem/mod.rs rename to RustySamovar/src/subsystems/inventory_subsystem/mod.rs diff --git a/src/subsystems/misc/mod.rs b/RustySamovar/src/subsystems/misc/mod.rs similarity index 100% rename from src/subsystems/misc/mod.rs rename to RustySamovar/src/subsystems/misc/mod.rs diff --git a/src/subsystems/misc/npc.rs b/RustySamovar/src/subsystems/misc/npc.rs similarity index 100% rename from src/subsystems/misc/npc.rs rename to RustySamovar/src/subsystems/misc/npc.rs diff --git a/src/subsystems/misc/pause.rs b/RustySamovar/src/subsystems/misc/pause.rs similarity index 100% rename from src/subsystems/misc/pause.rs rename to RustySamovar/src/subsystems/misc/pause.rs diff --git a/src/subsystems/misc/scene.rs b/RustySamovar/src/subsystems/misc/scene.rs similarity index 100% rename from src/subsystems/misc/scene.rs rename to RustySamovar/src/subsystems/misc/scene.rs diff --git a/src/subsystems/misc/shop.rs b/RustySamovar/src/subsystems/misc/shop.rs similarity index 100% rename from src/subsystems/misc/shop.rs rename to RustySamovar/src/subsystems/misc/shop.rs diff --git a/src/subsystems/misc/social.rs b/RustySamovar/src/subsystems/misc/social.rs similarity index 100% rename from src/subsystems/misc/social.rs rename to RustySamovar/src/subsystems/misc/social.rs diff --git a/src/subsystems/misc/teleport.rs b/RustySamovar/src/subsystems/misc/teleport.rs similarity index 100% rename from src/subsystems/misc/teleport.rs rename to RustySamovar/src/subsystems/misc/teleport.rs diff --git a/src/subsystems/mod.rs b/RustySamovar/src/subsystems/mod.rs similarity index 100% rename from src/subsystems/mod.rs rename to RustySamovar/src/subsystems/mod.rs diff --git a/src/utils/avatar_builder.rs b/RustySamovar/src/utils/avatar_builder.rs similarity index 100% rename from src/utils/avatar_builder.rs rename to RustySamovar/src/utils/avatar_builder.rs diff --git a/RustySamovar/src/utils/data_packet.rs b/RustySamovar/src/utils/data_packet.rs new file mode 100644 index 0000000..e798fef --- /dev/null +++ b/RustySamovar/src/utils/data_packet.rs @@ -0,0 +1,90 @@ +use std::fmt; +use std::convert::TryInto; + +#[derive(Debug)] +pub struct DataDecError { + reason: String, +} + +#[repr(packed)] +pub struct DataPacketSmallest // Not actually used, just represents the general structure +{ + start_magic: u16, + packet_id: u16, + metadata_size: u16, + data_size: u32, + //metadata: [0u8; metadata_size], + //data: [0u8; data_size], + end_magic: u16, +} + +#[derive(Debug)] +pub struct DataPacket +{ + pub packet_id: u16, + pub metadata: Vec, + pub data: Vec, +} + +impl DataPacket { + const DATA_MAGIC_START: u16 = 0x4567; + const DATA_MAGIC_END: u16 = 0x89AB; + + pub fn new(packet_id: u16, metadata: Vec, data: Vec) -> DataPacket { + return DataPacket { + packet_id: packet_id, + data: data, + metadata: metadata, + }; + } + + pub fn new_from_bytes(raw_data: &[u8]) -> Result { + if raw_data.len() < std::mem::size_of::() { + return Err(DataDecError {reason: "Size is too small!".to_string()}); + } + + // unwrap() here are valid as we're cutting exactly 4 bytes of data + let start_magic = u16::from_be_bytes(raw_data[0..2].try_into().unwrap()); + let end_magic = u16::from_be_bytes(raw_data[raw_data.len()-2..].try_into().unwrap()); + + if (start_magic == DataPacket::DATA_MAGIC_START) && (end_magic == DataPacket::DATA_MAGIC_END) { + let packet_id = u16::from_be_bytes(raw_data[2..4].try_into().unwrap()); + let metadata_size = u16::from_be_bytes(raw_data[4..6].try_into().unwrap()) as usize; + let data_size = u32::from_be_bytes(raw_data[6..10].try_into().unwrap()) as usize; + + let expected_size = std::mem::size_of::() + metadata_size + data_size; + + if raw_data.len() != expected_size { + return Err(DataDecError {reason: format!("Wrong packet size: expected {}, got {} (header {}, payload {})!", expected_size, raw_data.len(), std::mem::size_of::(), metadata_size + data_size)}); + } + + return Ok(DataPacket { + packet_id: packet_id, + metadata: raw_data[10..metadata_size+10].to_owned(), + data: raw_data[metadata_size+10..metadata_size+data_size+10].to_owned(), + }); + } else { + return Err(DataDecError {reason: format!("Unknown magic: 0x{:x} 0x{:x}", start_magic, end_magic),}); + } + } + + pub fn to_bytes(&self) -> Vec { + let mut ret = Vec::with_capacity(std::mem::size_of::() + self.data.len() + self.metadata.len()); + + ret.extend_from_slice(&DataPacket::DATA_MAGIC_START.to_be_bytes()); + ret.extend_from_slice(&self.packet_id.to_be_bytes()); + ret.extend_from_slice(&(self.metadata.len() as u16).to_be_bytes()); + ret.extend_from_slice(&(self.data.len() as u32).to_be_bytes()); + ret.extend_from_slice(&self.metadata); + ret.extend_from_slice(&self.data); + ret.extend_from_slice(&DataPacket::DATA_MAGIC_END.to_be_bytes()); + + return ret; + } +} + +impl fmt::Display for DataPacket { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "packet") + } +} diff --git a/RustySamovar/src/utils/handshake_packet.rs b/RustySamovar/src/utils/handshake_packet.rs new file mode 100644 index 0000000..d82c88b --- /dev/null +++ b/RustySamovar/src/utils/handshake_packet.rs @@ -0,0 +1,91 @@ +use std::fmt; +use std::convert::TryInto; + +#[derive(Debug)] +pub struct HandshakeDecError { + reason: String, +} + +#[derive(Debug)] +#[repr(C)] +pub struct HandshakePacket +{ + start_magic: u32, + param1: u32, + param2: u32, + data: u32, + end_magic: u32, +} + +impl HandshakePacket { + const HS_MAGIC_CONNECT_START: u32 = 0x000000FF; + const HS_MAGIC_CONNECT_END: u32 = 0xFFFFFFFF; + const HS_MAGIC_SEND_CONV_START: u32 = 0x00000145; + const HS_MAGIC_SEND_CONV_END: u32 = 0x14514545; + const HS_MAGIC_DISCONNECT_START: u32 = 0x00000194; + const HS_MAGIC_DISCONNECT_END: u32 = 0x19419494; + + const HS_CONNECTION_DATA: u32 = 1234567890; + + pub fn new(raw_data: &[u8]) -> Result { + if raw_data.len() != std::mem::size_of::() { + return Err(HandshakeDecError {reason: "Size mismatch!".to_string()}); + } + + // unwrap() here are valid as we're cutting exactly 4 bytes of data + let start_magic = u32::from_be_bytes(raw_data[0..4].try_into().unwrap()); + let param1 = u32::from_be_bytes(raw_data[4..8].try_into().unwrap()); + let param2 = u32::from_be_bytes(raw_data[8..12].try_into().unwrap()); + let data = u32::from_be_bytes(raw_data[12..16].try_into().unwrap()); + let end_magic = u32::from_be_bytes(raw_data[16..20].try_into().unwrap()); + + if (start_magic == HandshakePacket::HS_MAGIC_CONNECT_START) && (end_magic == HandshakePacket::HS_MAGIC_CONNECT_END) || + (start_magic == HandshakePacket::HS_MAGIC_SEND_CONV_START) && (end_magic == HandshakePacket::HS_MAGIC_SEND_CONV_END) || + (start_magic == HandshakePacket::HS_MAGIC_DISCONNECT_START) && (end_magic == HandshakePacket::HS_MAGIC_DISCONNECT_END) { + + return Ok(HandshakePacket { + start_magic: start_magic, + param1: param1, + param2: param2, + data: data, + end_magic: end_magic, + }); + } else { + return Err(HandshakeDecError {reason: format!("Unknown magic: 0x{:x} 0x{:x}", start_magic, end_magic),}); + } + } + + pub fn is_connect(&self) -> bool { + return (self.start_magic == HandshakePacket::HS_MAGIC_CONNECT_START) && + (self.end_magic == HandshakePacket::HS_MAGIC_CONNECT_END) && + (self.data == HandshakePacket::HS_CONNECTION_DATA); + } + + pub fn new_conv(conv: u32, token: u32) -> HandshakePacket { + HandshakePacket { + start_magic: HandshakePacket::HS_MAGIC_SEND_CONV_START, + param1: conv, + param2: token, + data: HandshakePacket::HS_CONNECTION_DATA, + end_magic: HandshakePacket::HS_MAGIC_SEND_CONV_END, + } + } + + pub fn to_bytes(&self) -> Vec { + let mut ret = Vec::with_capacity(std::mem::size_of::()); + + ret.extend_from_slice(&self.start_magic.to_be_bytes()); + ret.extend_from_slice(&self.param1.to_be_bytes()); + ret.extend_from_slice(&self.param2.to_be_bytes()); + ret.extend_from_slice(&self.data.to_be_bytes()); + ret.extend_from_slice(&self.end_magic.to_be_bytes()); + + return ret; + } +} + +impl fmt::Display for HandshakePacket { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "packet") + } +} diff --git a/src/utils/id_manager.rs b/RustySamovar/src/utils/id_manager.rs similarity index 100% rename from src/utils/id_manager.rs rename to RustySamovar/src/utils/id_manager.rs diff --git a/src/utils/mod.rs b/RustySamovar/src/utils/mod.rs similarity index 100% rename from src/utils/mod.rs rename to RustySamovar/src/utils/mod.rs diff --git a/src/utils/remapper.rs b/RustySamovar/src/utils/remapper.rs similarity index 100% rename from src/utils/remapper.rs rename to RustySamovar/src/utils/remapper.rs diff --git a/src/utils/time_manager.rs b/RustySamovar/src/utils/time_manager.rs similarity index 100% rename from src/utils/time_manager.rs rename to RustySamovar/src/utils/time_manager.rs diff --git a/rs-nodeconf/Cargo.toml b/rs-nodeconf/Cargo.toml new file mode 100644 index 0000000..25d0855 --- /dev/null +++ b/rs-nodeconf/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "rs-nodeconf" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rs-ipc = { path = "../rs-ipc" } diff --git a/rs-nodeconf/src/config.rs b/rs-nodeconf/src/config.rs new file mode 100644 index 0000000..dd889fa --- /dev/null +++ b/rs-nodeconf/src/config.rs @@ -0,0 +1,35 @@ +use rs_ipc::{PubSocket, PullSocket, PushSocket, Result, SubSocket}; + +pub struct NodeConfig { + pub in_queue_addr: String, + pub in_queue_port: u16, + pub out_queue_addr: String, + pub out_queue_port: u16, +} + +impl NodeConfig { + pub fn new() -> Self { + NodeConfig { + in_queue_addr: "127.0.0.1".to_string(), + in_queue_port: 9012, + out_queue_addr: "127.0.0.1".to_string(), + out_queue_port: 9014, + } + } + + pub fn bind_in_queue(&self) -> Result { + PubSocket::bind_tcp(&self.in_queue_addr, self.in_queue_port) + } + + pub fn bind_out_queue(&self) -> Result { + PullSocket::bind_tcp(&self.out_queue_addr, self.out_queue_port) + } + + pub fn connect_in_queue(&self) -> Result { + SubSocket::connect_tcp(&self.in_queue_addr, self.in_queue_port) + } + + pub fn connect_out_queue(&self) -> Result { + PushSocket::connect_tcp(&self.out_queue_addr, self.out_queue_port) + } +} \ No newline at end of file diff --git a/rs-nodeconf/src/lib.rs b/rs-nodeconf/src/lib.rs new file mode 100644 index 0000000..b1c5de7 --- /dev/null +++ b/rs-nodeconf/src/lib.rs @@ -0,0 +1,3 @@ +mod config; + +pub use crate::config::NodeConfig; \ No newline at end of file diff --git a/rs-utils/Cargo.toml b/rs-utils/Cargo.toml new file mode 100644 index 0000000..f37debe --- /dev/null +++ b/rs-utils/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "rs-utils" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +serde = { version = "1.0", features = ["derive"] } +chrono = "0.4" diff --git a/rs-utils/src/lib.rs b/rs-utils/src/lib.rs new file mode 100644 index 0000000..ec4477f --- /dev/null +++ b/rs-utils/src/lib.rs @@ -0,0 +1,3 @@ +mod time_manager; + +pub use time_manager::TimeManager; \ No newline at end of file diff --git a/rs-utils/src/time_manager.rs b/rs-utils/src/time_manager.rs new file mode 100644 index 0000000..2943627 --- /dev/null +++ b/rs-utils/src/time_manager.rs @@ -0,0 +1,28 @@ +use std::time::SystemTime; +use std::convert::TryInto; + +use chrono::{DateTime, NaiveDateTime, Utc}; +use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer}; + +pub struct TimeManager { +} + +impl TimeManager { + pub fn duration_since(time_point: SystemTime) -> u64 { + SystemTime::now().duration_since(time_point).unwrap().as_millis().try_into().unwrap() + } + + pub fn timestamp() -> u64 { + return Self::duration_since(SystemTime::UNIX_EPOCH); + } + + pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> std::result::Result, D::Error> { + let time: String = Deserialize::deserialize(deserializer)?; + + if time.is_empty() { + Ok(None) + } else { + Ok(Some(NaiveDateTime::parse_from_str(&time, "%Y-%m-%d %H:%M:%S").map_err(D::Error::custom)?)) + } + } +}