use std::io; use std::net::ToSocketAddrs; use std::sync::mpsc; use mio; use config; use super::{Intent, Stream, SendPacket, Request, Response}; use super::server::*; /*===============* * TOKEN COUNTER * *===============*/ /// This struct provides a simple way to generate different tokens. struct TokenCounter { counter: usize, } impl TokenCounter { fn new() -> Self { TokenCounter { counter: 0, } } fn next(&mut self) -> mio::Token { self.counter += 1; mio::Token(self.counter - 1) } } /*========================* * SERVER RESPONSE SENDER * *========================*/ pub struct ServerResponseSender(mpsc::Sender); impl SendPacket for ServerResponseSender { type Value = ServerResponse; type Error = mpsc::SendError; fn send_packet(&mut self, value: Self::Value) -> Result<(), Self::Error> { self.0.send(Response::ServerResponse(value)) } } /*=========* * HANDLER * *=========*/ /// This struct handles all the soulseek connections, to the server and to /// peers. struct Handler { token_counter: TokenCounter, server_token: mio::Token, server_stream: Stream, client_tx: mpsc::Sender, } impl Handler { fn new(client_tx: mpsc::Sender) -> io::Result { let host = config::SERVER_HOST; let port = config::SERVER_PORT; let server_stream = Stream::new( try!(Self::connect(host, port)), ServerResponseSender(client_tx.clone()) ); info!("Connected to server at {}:{}", host, port); let mut token_counter = TokenCounter::new(); let server_token = token_counter.next(); Ok(Handler { token_counter: token_counter, server_token: server_token, server_stream: server_stream, client_tx: client_tx, }) } fn register(&self, event_loop: &mut mio::EventLoop) -> io::Result<()> { event_loop.register( self.server_stream.evented(), self.server_token, mio::EventSet::readable(), mio::PollOpt::edge() | mio::PollOpt::oneshot() ) } fn connect(hostname: &str, port: u16) -> io::Result { for sock_addr in try!((hostname, port).to_socket_addrs()) { if let Ok(stream) = mio::tcp::TcpStream::connect(&sock_addr) { return Ok(stream) } } Err(io::Error::new( io::ErrorKind::Other, format!("Cannot connect to {}:{}", hostname, port) )) } fn process_server_intent( &mut self, intent: Intent, event_loop: &mut mio::EventLoop) { match intent { Intent::Done => { error!("Server connection closed"); // TODO notify client and shut down }, Intent::Continue(event_set) => { event_loop.reregister( self.server_stream.evented(), self.server_token, event_set, mio::PollOpt::edge() | mio::PollOpt::oneshot() ).unwrap(); } } } } impl mio::Handler for Handler { type Timeout = (); type Message = Request; fn ready(&mut self, event_loop: &mut mio::EventLoop, token: mio::Token, event_set: mio::EventSet) { if token == self.server_token { let intent = self.server_stream.on_ready(event_set); self.process_server_intent(intent, event_loop); } else { unreachable!("Unknown token!"); } } fn notify(&mut self, event_loop: &mut mio::EventLoop, request: Request) { match request { Request::ServerRequest(server_request) => { let intent = self.server_stream.on_notify(&server_request); self.process_server_intent(intent, event_loop); } } } } pub type Sender = mio::Sender; pub struct Agent { event_loop: mio::EventLoop, handler: Handler, } impl Agent { pub fn new(client_tx: mpsc::Sender) -> io::Result { // Create the event loop. let mut event_loop = try!(mio::EventLoop::new()); // Create the handler for the event loop. let handler = try!(Handler::new(client_tx)); // Register the handler's sockets with the event loop. try!(handler.register(&mut event_loop)); Ok(Agent { event_loop: event_loop, handler: handler, }) } pub fn channel(&self) -> Sender { self.event_loop.channel() } pub fn run(&mut self) -> io::Result<()> { self.event_loop.run(&mut self.handler) } }