| @@ -433,6 +433,7 @@ dependencies = [ | |||||
| "serde", | "serde", | ||||
| "serde_json", | "serde_json", | ||||
| "structopt", | "structopt", | ||||
| "toml", | |||||
| "uuid", | "uuid", | ||||
| ] | ] | ||||
| @@ -737,6 +738,15 @@ dependencies = [ | |||||
| "winapi 0.3.8", | "winapi 0.3.8", | ||||
| ] | ] | ||||
| [[package]] | |||||
| name = "toml" | |||||
| version = "0.5.6" | |||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
| checksum = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" | |||||
| dependencies = [ | |||||
| "serde", | |||||
| ] | |||||
| [[package]] | [[package]] | ||||
| name = "unicode-segmentation" | name = "unicode-segmentation" | ||||
| version = "1.6.0" | version = "1.6.0" | ||||
| @@ -14,3 +14,4 @@ uuid = { version = "0.8.1", features = ["v4"] } | |||||
| lazy_static = "1.4.0" | lazy_static = "1.4.0" | ||||
| futures = "0.3.5" | futures = "0.3.5" | ||||
| futures-util = "0.3.5" | futures-util = "0.3.5" | ||||
| toml = "0.5.6" | |||||
| @@ -0,0 +1 @@ | |||||
| username="Isabelle" | |||||
| @@ -14,5 +14,5 @@ pub async fn client(port: u16) -> Result<()> { | |||||
| Message::new("Isabelle".to_owned(), "Hello Server".to_owned()).try_into()?; | Message::new("Isabelle".to_owned(), "Hello Server".to_owned()).try_into()?; | ||||
| message.write(&mut stream).await?; | message.write(&mut stream).await?; | ||||
| Ok(()) | |||||
| loop {} | |||||
| } | } | ||||
| @@ -0,0 +1,15 @@ | |||||
| use crate::Result; | |||||
| use serde::Deserialize; | |||||
| #[derive(Deserialize)] | |||||
| pub struct ClientConfig { | |||||
| user: String, | |||||
| } | |||||
| impl ClientConfig { | |||||
| pub fn load() -> Result<Self> { | |||||
| let config = std::fs::read_to_string("./client_config.toml")?; | |||||
| let config: ClientConfig = toml::from_str(&config)?; | |||||
| Ok(config) | |||||
| } | |||||
| } | |||||
| @@ -1,5 +1,6 @@ | |||||
| // modules | // modules | ||||
| mod client; | mod client; | ||||
| mod config; | |||||
| #[allow(dead_code)] | #[allow(dead_code)] | ||||
| mod packet; | mod packet; | ||||
| mod server; | mod server; | ||||
| @@ -9,5 +10,5 @@ pub use client::client; | |||||
| pub use server::server; | pub use server::server; | ||||
| // lazy idiot error/result type | // lazy idiot error/result type | ||||
| pub type Error = Box<dyn std::error::Error>; | |||||
| pub type Error = std::io::Error; | |||||
| pub type Result<T> = std::result::Result<T, Error>; | pub type Result<T> = std::result::Result<T, Error>; | ||||
| @@ -1,11 +1,15 @@ | |||||
| // namespacing | // namespacing | ||||
| use crate::{Error, Result}; | |||||
| use crate::Result; | |||||
| use async_std::net::TcpStream; | use async_std::net::TcpStream; | ||||
| use async_std::prelude::*; | use async_std::prelude::*; | ||||
| use chrono::prelude::*; | |||||
| use serde::{Deserialize, Serialize}; | |||||
| use futures_util::io::ReadHalf; | |||||
| use std::convert::TryInto; | use std::convert::TryInto; | ||||
| mod join; | |||||
| pub use join::Join; | |||||
| mod message; | |||||
| pub use message::Message; | |||||
| /// structured [packet type byte][four bytes of packet length][contents of packet] | /// structured [packet type byte][four bytes of packet length][contents of packet] | ||||
| pub struct NetworkPacket(Vec<u8>); | pub struct NetworkPacket(Vec<u8>); | ||||
| @@ -25,6 +29,11 @@ impl std::convert::Into<NetworkPacket> for Packet { | |||||
| } | } | ||||
| } | } | ||||
| pub trait Sendable { | |||||
| fn to_packet(self) -> Packet; | |||||
| fn from_packet(packet: Packet) -> Self; | |||||
| } | |||||
| /// contains data to be turned into a network packet or into a more specific packet | /// contains data to be turned into a network packet or into a more specific packet | ||||
| pub struct Packet { | pub struct Packet { | ||||
| pub packet_type: PacketType, | pub packet_type: PacketType, | ||||
| @@ -38,9 +47,13 @@ impl Packet { | |||||
| } | } | ||||
| /// read a packet from a tcpstream | /// read a packet from a tcpstream | ||||
| pub async fn read(stream: &mut TcpStream) -> Result<Packet> { | |||||
| pub async fn read(stream: &mut ReadHalf<TcpStream>) -> Result<Option<Packet>> { | |||||
| let mut info_buf = [0u8; 5]; | let mut info_buf = [0u8; 5]; | ||||
| stream.read(&mut info_buf).await?; | |||||
| let check = stream.read(&mut info_buf).await?; | |||||
| if check == 0 { | |||||
| return Ok(None); | |||||
| } | |||||
| let packet_type = PacketType::from_u8(info_buf[0]).unwrap(); | let packet_type = PacketType::from_u8(info_buf[0]).unwrap(); | ||||
| let length = u32::from_le_bytes(info_buf[1..5].try_into().unwrap()) as usize; | let length = u32::from_le_bytes(info_buf[1..5].try_into().unwrap()) as usize; | ||||
| @@ -48,13 +61,13 @@ impl Packet { | |||||
| let mut contents: Vec<u8> = vec![0; length]; | let mut contents: Vec<u8> = vec![0; length]; | ||||
| stream.read(&mut contents).await?; | stream.read(&mut contents).await?; | ||||
| Ok(Packet::new(packet_type, contents)) | |||||
| Ok(Some(Packet::new(packet_type, contents))) | |||||
| } | } | ||||
| /// write a packet to the tcpstream | /// write a packet to the tcpstream | ||||
| pub async fn write(self, stream: &mut TcpStream) -> Result<()> { | pub async fn write(self, stream: &mut TcpStream) -> Result<()> { | ||||
| let network_packet: NetworkPacket = self.into(); | let network_packet: NetworkPacket = self.into(); | ||||
| let _ = stream.write(&network_packet.0).await?; | |||||
| stream.write(&network_packet.0).await?; | |||||
| Ok(()) | Ok(()) | ||||
| } | } | ||||
| } | } | ||||
| @@ -63,6 +76,7 @@ impl Packet { | |||||
| #[repr(u8)] | #[repr(u8)] | ||||
| pub enum PacketType { | pub enum PacketType { | ||||
| Message = 0, | Message = 0, | ||||
| Join = 1, | |||||
| } | } | ||||
| impl PacketType { | impl PacketType { | ||||
| @@ -74,39 +88,3 @@ impl PacketType { | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /// a Message | |||||
| #[derive(Deserialize, Serialize, Debug)] | |||||
| pub struct Message { | |||||
| user: String, | |||||
| contents: String, | |||||
| timestamp: i64, | |||||
| } | |||||
| impl Message { | |||||
| /// create a new message | |||||
| pub fn new(user: String, contents: String) -> Self { | |||||
| let timestamp = Utc::now().timestamp(); | |||||
| Self { user, contents, timestamp } | |||||
| } | |||||
| } | |||||
| impl std::convert::TryFrom<Packet> for Message { | |||||
| type Error = Error; | |||||
| fn try_from(packet: Packet) -> Result<Self> { | |||||
| let packet_contents = &String::from_utf8(packet.packet_contents)?; | |||||
| let message: Message = serde_json::from_str(packet_contents)?; | |||||
| Ok(message) | |||||
| } | |||||
| } | |||||
| impl std::convert::TryInto<Packet> for Message { | |||||
| type Error = Error; | |||||
| fn try_into(self) -> Result<Packet> { | |||||
| let packet_contents: Vec<u8> = serde_json::to_string(&self)?.into_bytes(); | |||||
| let packet_type = PacketType::Message; | |||||
| Ok(Packet { packet_type, packet_contents }) | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,38 @@ | |||||
| use crate::packet::{Packet, PacketType}; | |||||
| use crate::{Error, Result}; | |||||
| use chrono::prelude::*; | |||||
| use serde::{Deserialize, Serialize}; | |||||
| #[derive(Deserialize, Serialize, Debug)] | |||||
| pub struct Join { | |||||
| user: String, | |||||
| timestamp: i64, | |||||
| } | |||||
| impl Join { | |||||
| fn new(user: String) -> Self { | |||||
| let timestamp = Utc::now().timestamp(); | |||||
| Self { user, timestamp } | |||||
| } | |||||
| } | |||||
| impl std::convert::TryFrom<Packet> for Join { | |||||
| type Error = Error; | |||||
| fn try_from(packet: Packet) -> Result<Self> { | |||||
| let packet_contents = | |||||
| &String::from_utf8(packet.packet_contents).expect("could not decode as utf8"); | |||||
| let message: Join = serde_json::from_str(packet_contents)?; | |||||
| Ok(message) | |||||
| } | |||||
| } | |||||
| impl std::convert::TryInto<Packet> for Join { | |||||
| type Error = Error; | |||||
| fn try_into(self) -> Result<Packet> { | |||||
| let packet_contents: Vec<u8> = serde_json::to_string(&self)?.into_bytes(); | |||||
| let packet_type = PacketType::Join; | |||||
| Ok(Packet { packet_type, packet_contents }) | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,42 @@ | |||||
| // namespacing | |||||
| use crate::packet::{Packet, PacketType}; | |||||
| use crate::{Error, Result}; | |||||
| use chrono::prelude::*; | |||||
| use serde::{Deserialize, Serialize}; | |||||
| /// a Message | |||||
| #[derive(Deserialize, Serialize, Debug)] | |||||
| pub struct Message { | |||||
| user: String, | |||||
| contents: String, | |||||
| timestamp: i64, | |||||
| } | |||||
| impl Message { | |||||
| /// create a new message | |||||
| pub fn new(user: String, contents: String) -> Self { | |||||
| let timestamp = Utc::now().timestamp(); | |||||
| Self { user, contents, timestamp } | |||||
| } | |||||
| } | |||||
| impl std::convert::TryFrom<Packet> for Message { | |||||
| type Error = Error; | |||||
| fn try_from(packet: Packet) -> Result<Self> { | |||||
| let packet_contents = | |||||
| &String::from_utf8(packet.packet_contents).expect("could not decode as utf8"); | |||||
| let message: Message = serde_json::from_str(packet_contents)?; | |||||
| Ok(message) | |||||
| } | |||||
| } | |||||
| impl std::convert::TryInto<Packet> for Message { | |||||
| type Error = Error; | |||||
| fn try_into(self) -> Result<Packet> { | |||||
| let packet_contents: Vec<u8> = serde_json::to_string(&self)?.into_bytes(); | |||||
| let packet_type = PacketType::Message; | |||||
| Ok(Packet { packet_type, packet_contents }) | |||||
| } | |||||
| } | |||||
| @@ -1,15 +1,17 @@ | |||||
| // namespacing | // namespacing | ||||
| /*use crate::packet::{Message, Packet, PacketType};*/ | |||||
| use crate::Result; | |||||
| use async_std::net::{TcpListener, TcpStream}; | |||||
| use async_std::prelude::*; | |||||
| /*use async_std::task;*/ | |||||
| use futures::io::WriteHalf; | |||||
| use lazy_static::lazy_static; | |||||
| use std::collections::HashMap; | |||||
| /*use std::convert::TryFrom;*/ | |||||
| use crate::{ | |||||
| packet::{Join, Message, Packet, PacketType}, | |||||
| Result, | |||||
| }; | |||||
| use async_std::{ | |||||
| net::{TcpListener, TcpStream}, | |||||
| prelude::*, | |||||
| task, | |||||
| }; | |||||
| use futures::io::{ReadHalf, WriteHalf}; | |||||
| use futures_util::io::AsyncReadExt; | use futures_util::io::AsyncReadExt; | ||||
| use std::sync::Mutex; | |||||
| use lazy_static::lazy_static; | |||||
| use std::{collections::HashMap, convert::TryFrom, sync::Mutex}; | |||||
| use uuid::Uuid; | use uuid::Uuid; | ||||
| lazy_static! { | lazy_static! { | ||||
| @@ -24,23 +26,60 @@ pub async fn server(port: u16) -> Result<()> { | |||||
| let mut incoming = listener.incoming(); | let mut incoming = listener.incoming(); | ||||
| while let Some(stream) = incoming.next().await { | while let Some(stream) = incoming.next().await { | ||||
| let mut stream = stream?; | |||||
| println!("new stream from: {}", &stream.peer_addr()?.ip()); | |||||
| let stream = stream?; | |||||
| let stream_addr = &stream.peer_addr()?.ip(); | |||||
| println!("new stream from: {}", &stream_addr); | |||||
| let (read, write) = stream.split(); | let (read, write) = stream.split(); | ||||
| let stream_id = Uuid::new_v4(); | let stream_id = Uuid::new_v4(); | ||||
| WRITE_STREAMS.lock()?.insert(stream_id, write); | |||||
| // handle stream | |||||
| /* task::spawn(async { | |||||
| loop { | |||||
| let packet = Packet::read(&mut stream).await?; | |||||
| let message = match packet.packet_type { | |||||
| PacketType::Message => Message::try_from(packet), | |||||
| }; | |||||
| println!("{:?}", message); | |||||
| WRITE_STREAMS.lock().expect("could not aqcuire lock").insert(stream_id.clone(), write); | |||||
| task::spawn(handle_stream(read, stream_id)); | |||||
| } | |||||
| Ok(()) | |||||
| } | |||||
| async fn handle_stream(mut stream: ReadHalf<TcpStream>, stream_id: Uuid) -> Result<()> { | |||||
| loop { | |||||
| let packet = match Packet::read(&mut stream).await { | |||||
| Ok(packet) => packet, | |||||
| Err(err) => { | |||||
| println!("error reading packet: {:?}", err); | |||||
| return Ok(()); | |||||
| } | |||||
| }; | |||||
| let packet = if let Some(packet) = packet { | |||||
| println!("got packet"); | |||||
| packet | |||||
| } else { | |||||
| break; | |||||
| }; | |||||
| match packet.packet_type { | |||||
| PacketType::Message => { | |||||
| let msg = Message::try_from(packet)?; | |||||
| println!("{:?}", msg); | |||||
| } | |||||
| PacketType::Join => { | |||||
| let join = Join::try_from(packet)?; | |||||
| println!("{:?}", join); | |||||
| } | } | ||||
| });*/ | |||||
| } | |||||
| println!("packet processed"); | |||||
| } | } | ||||
| println!("disconnecting"); | |||||
| WRITE_STREAMS.lock().expect("failed to aqcuire lock").remove(&stream_id); | |||||
| Ok(()) | Ok(()) | ||||
| } | } | ||||
| /* | |||||
| async fn relay_packet() -> Result<()> { | |||||
| let locked_stream = WRITE_STREAMS.lock(). | |||||
| }*/ | |||||