diff --git a/src/config.rs b/src/config.rs index e121e31..257092f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -8,3 +8,6 @@ pub const PASSWORD: &'static str = "ijklmnop"; pub const SERVER_HOST : &'static str = "server.slsknet.org"; pub const SERVER_PORT : u16 = 2242; + +pub const CONTROL_HOST: &'static str = "localhost"; +pub const CONTROL_PORT: u16 = 2244; diff --git a/src/control.rs b/src/control.rs index aed7308..93034fc 100644 --- a/src/control.rs +++ b/src/control.rs @@ -1,66 +1,123 @@ use std::io; use std::io::{Read, Write}; +use std::sync::mpsc; +use std::thread; use rustc_serialize::json; - use mio::tcp::TcpStream; +use websocket; +use websocket::{Receiver, Sender}; -#[derive(RustcDecodable, RustcEncodable)] -pub enum ControlRequest { - LoginRequest(LoginRequest), +use client; +use config; + +type WebSocketReceiver = + websocket::receiver::Receiver; + +type WebSocketSender = + websocket::sender::Sender; + +type WebSocketClient = + websocket::Client; + +pub struct Controller { + client_tx: mpsc::Sender, + client_rx: mpsc::Receiver, } -impl ControlRequest { - fn read_from(&self, mut reader: R) -> io::Result { - let mut string = String::new(); - try!(reader.read_to_string(&mut string)); - match json::decode(&string) { - Ok(request) => Ok(request), - Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)), +impl Controller { + pub fn new(tx: mpsc::Sender, + rx: mpsc::Receiver) + -> Self + { + Controller { + client_tx: tx, + client_rx: rx, } } -} -#[derive(RustcDecodable, RustcEncodable)] -pub enum ControlResponse { - LoginResponse(LoginResponse), -} + pub fn run(&mut self) { + let host = config::CONTROL_HOST; + let port = config::CONTROL_PORT; + loop { + let client = Self::get_client(host, port); + let (mut sender, mut receiver) = client.split(); + let tx = self.client_tx.clone(); + thread::spawn(move || { + Self::receiver_loop(receiver, tx); + }); + Self::sender_loop(sender, &mut self.client_rx); + } + } -impl ControlResponse { - fn write_to(&self, mut writer: W) -> io::Result<()> { - match json::encode(self) { - Ok(json_string) => { - try!(writer.write(&json_string.into_bytes())); - Ok(()) - }, + fn get_client(host: &str, port: u16) -> WebSocketClient + { + let mut server = websocket::Server::bind((host, port)).unwrap(); + loop { + match Self::try_get_client(&mut server) { + Ok(client) => return client, + Err(e) => error!("Error accepting control connection: {}", e), + } + } + } + fn try_get_client(server: &mut websocket::Server) + -> io::Result + { + let connection = try!(server.accept()); + let request = try!(connection.read_request()); + match request.accept().send() { + Ok(client) => Ok(client), Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)), } } -} -pub struct ControlStream { - stream: TcpStream, -} + fn receiver_loop( + mut receiver: WebSocketReceiver, tx: mpsc::Sender) + { + for message_result in receiver.incoming_messages() { + let message: websocket::Message = match message_result { + Ok(message) => message, + Err(e) => { + warn!("Error receiving control message {}", e); + continue; + }, + }; + let payload = match message.opcode { + websocket::message::Type::Text => + String::from_utf8(message.payload.into_owned()).unwrap(), -impl ControlStream { - pub fn new(stream: TcpStream) -> Self { - ControlStream { - stream: stream, + code => { + warn!("Unhandled websocket message type: {:?}", code); + continue; + }, + }; + let control_request = json::decode(&payload).unwrap(); + tx.send(control_request); } } - pub fn read_request(&mut self) -> io::Result> { - Ok(None) - } - - pub fn write_response(&mut self, response: &ControlResponse) - -> io::Result<()> + fn sender_loop( + mut sender: WebSocketSender, rx: &mut mpsc::Receiver) { - response.write_to(&mut self.stream) + for control_response in rx.iter() { + let encoded = json::encode(&control_response).unwrap(); + let message = websocket::Message::text(encoded); + sender.send_message(&message).unwrap(); + } } } +#[derive(RustcDecodable, RustcEncodable)] +pub enum ControlRequest { + LoginRequest(LoginRequest), +} + +#[derive(RustcDecodable, RustcEncodable)] +pub enum ControlResponse { + LoginResponse(LoginResponse), +} + #[derive(RustcDecodable, RustcEncodable)] pub struct LoginRequest { username: String,