cubik 0.1.0

OpenGL/glium-based multiplayer game engine
Documentation
use std::io;
use std::str::FromStr;

use std::time::Duration;
use crate::message::CommMessage;
use std::collections::{HashMap, HashSet};
use std::net::{SocketAddr, TcpStream, AddrParseError};
use serde::{Serialize, de::DeserializeOwned};
use crate::message;
use derive_more::{From, Error, Display};

#[derive(From, Error, Debug, Display)]
pub enum ClientError {
	IOError(io::Error),
	MessageError(message::MessageError),
	AddrParseError(AddrParseError)
}

#[derive(Debug, Default)]
pub struct PeerMeta {
	pub name: Option<String>
}

pub struct ClientContainer<M: Serialize + DeserializeOwned> {
	pub stream: TcpStream,
	pub peers: HashMap<u8, PeerMeta>,
	pub incoming_msgs: Vec<M>,
	pub player_id: Option<u8>,
	buffer: Vec<u8>
}

impl<M: Serialize + DeserializeOwned> ClientContainer<M> {
	pub fn new(addr: &str) -> Result<Self, ClientError> {
		let addr = SocketAddr::from_str(addr)?;
		let stream = TcpStream::connect_timeout(&addr, Duration::new(5, 0))?;

		stream.set_nonblocking(true)?;

		Ok(Self {
			stream: stream,
			peers: HashMap::new(),
			incoming_msgs: Vec::new(),
			buffer: Vec::new(),
			player_id: None
		})
	}

	pub fn state_name(&mut self, name: String) -> Result<(), ClientError> {
		message::send::<M>(&mut self.stream, &CommMessage::PlayerNameStatement {
			player_id: 0,
			name: name
		})?;
		Ok(())
	}

	pub fn pids(&self) -> HashSet<u8> {
		self.peers.keys().cloned().collect()
	}

	pub fn send(&mut self, message: M) -> Result<(), ClientError> {
		Ok(message::send(&mut self.stream, &CommMessage::App(message))?)
	}

	pub fn update(&mut self) -> Result<(), ClientError> {
		while let Some(msg) = message::receive(&mut self.stream, &mut self.buffer)? {
			self.process_msg(msg);
		}

		Ok(())
	}

	fn process_msg(&mut self, msg: CommMessage<M>) {
		match msg {
			CommMessage::Welcome { client_id, players } => {
				self.player_id = Some(client_id);
				self.peers = players.iter().map(|(pid, name)| (*pid, PeerMeta { name: name.clone() })).collect();
			},
			CommMessage::PlayerChange { player_id, joined } => {
				if joined {
					self.peers.insert(player_id, Default::default());
				} else {
					self.peers.remove(&player_id);
				}
			},
			CommMessage::PlayerNameStatement { player_id, name } => {
				if let Some(peer) = self.peers.get_mut(&player_id) {
					peer.name = Some(name);
				}
			},
			CommMessage::App(msg) => self.incoming_msgs.push(msg)
		};
	}

	pub fn get_msgs(&mut self) -> Vec<M> {
		let mut result: Vec<M> = Vec::new();
		result.append(&mut self.incoming_msgs);
		result
	}
}