use libpso::crypto::{PSOCipher, NullCipher}; use libpso::{PSOPacket, PacketParseError}; use crate::common::serverstate::{ServerState, ServerPacket, OnConnect}; use crate::common::network::{recv_packet, PacketNetworkError}; use std::net; use std::io::Write; use mio::tcp::TcpStream; use mio::{Poll, Events, Token, Ready, PollOpt}; pub struct Client { running: bool, socket: mio::tcp::TcpStream, cipher_in: Box, cipher_out: Box, state: Box>, send_buffer: Vec, } impl Client { pub fn new(socket: mio::tcp::TcpStream, state: Box>) -> Client { let mut client = Client { running: true, socket: socket, cipher_in: Box::new(NullCipher {}), cipher_out: Box::new(NullCipher {}), state: state, send_buffer: Vec::new(), }; for task in client.state.on_connect() { match task { OnConnect::Packet(pkt) => client.send(&*pkt), OnConnect::Cipher((cipher_in, cipher_out)) => { client.cipher_in = cipher_in; client.cipher_out = cipher_out; }, } } client } fn send_data(&mut self) { if self.send_buffer.len() == 0 { return; } match self.socket.write(&self.send_buffer) { Ok(len) => { if len == 0 { self.running = false; } self.send_buffer.drain(..len); }, Err(err) => { println!("[client] error sending data to {:?}: {:?}", self.socket, err); } } } // TODO: this may need to pad to 8 bytes for bb cipher fn send(&mut self, pkt: &dyn PSOPacket) { let buf = pkt.as_bytes(); let mut cbuf = self.cipher_out.encrypt(&buf).unwrap(); self.send_buffer.append(&mut cbuf); self.send_data(); } pub fn io_loop(mut self) { let poll = Poll::new().unwrap(); poll.register(&self.socket, Token(0), Ready::readable() | Ready::writable(), PollOpt::edge()).unwrap(); let mut events = Events::with_capacity(1024); while self.running { poll.poll(&mut events, None).unwrap(); for event in &events{ if event.token() == Token(0) { if event.readiness().is_writable() { self.send_data(); } if event.readiness().is_readable() { loop { let pkt = recv_packet(&mut self.socket, &mut *self.cipher_in) .and_then(|pkt| { P::from_bytes(&pkt) .map_err(|err| err.into()) }); match pkt { Ok(pkt) => { let response = self.state.handle(&pkt); for r in response { self.send(&*r); } }, Err(err) => { match err { PacketNetworkError::ClientDisconnected => self.running = false, _ => println!("error recv-ing packet with {:?}: {:?}", self.socket, err), } break; } } } } } } } } }