From cb035e9de40b5b1e5a8a5e862ae9dd6a9da68d06 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Mon, 8 Sep 2014 11:35:02 -0400 Subject: move the client implementation to a trait this will allow us to more easily allow adding hooks --- examples/client.rs | 25 ++++++++++++++++++++++++- src/client.rs | 55 ++++++++++++++++++++++-------------------------------- 2 files changed, 46 insertions(+), 34 deletions(-) diff --git a/examples/client.rs b/examples/client.rs index cf9f328..eb3d31a 100644 --- a/examples/client.rs +++ b/examples/client.rs @@ -1,10 +1,33 @@ extern crate irc; use irc::constants::{Ping, Pong}; +use irc::Client; + +use std::io; + +struct ExampleClient { + conn: io::BufferedStream, + socket_name: Option, +} + +impl irc::Client for ExampleClient { + fn new (conn: io::BufferedStream, socket_name: Option) -> ExampleClient { + ExampleClient { conn: conn, socket_name: socket_name } + } + fn conn (&mut self) -> &mut io::BufferedStream { + &mut self.conn + } + fn socket_name (&self) -> Option<&str> { + match self.socket_name { + Some(ref name) => Some(name.as_slice()), + None => None, + } + } +} fn main () { let builder = irc::ClientBuilder::new("doytest", "chat.freenode.net"); - let client = builder.connect(); + let client: ExampleClient = builder.connect(); client.run_loop_with(|client, m| { println!("{}", m); match *m.message_type() { diff --git a/src/client.rs b/src/client.rs index 1623b02..55f2277 100644 --- a/src/client.rs +++ b/src/client.rs @@ -3,7 +3,7 @@ use std::{io, str}; use constants::{Nick, Pass, User}; use message::Message; -pub struct ClientBuilder { +pub struct ClientBuilder { nick: String, pass: Option, realname: String, @@ -15,13 +15,8 @@ pub struct ClientBuilder { port: u16, } -pub struct Client { - conn: io::BufferedStream, - socket_name: Option, -} - -impl ClientBuilder { - pub fn new (nick: &str, servername: &str) -> ClientBuilder { +impl ClientBuilder { + pub fn new (nick: &str, servername: &str) -> ClientBuilder { ClientBuilder { nick: nick.to_string(), pass: None, @@ -35,32 +30,32 @@ impl ClientBuilder { } } - pub fn set_pass (&mut self, pass: &str) -> &mut ClientBuilder { + pub fn set_pass (&mut self, pass: &str) -> &mut ClientBuilder { self.pass = Some(pass.to_string()); self } - pub fn set_username (&mut self, username: &str) -> &mut ClientBuilder { + pub fn set_username (&mut self, username: &str) -> &mut ClientBuilder { self.username = username.to_string(); self } - pub fn set_realname (&mut self, realname: &str) -> &mut ClientBuilder { + pub fn set_realname (&mut self, realname: &str) -> &mut ClientBuilder { self.realname = realname.to_string(); self } - pub fn set_hostname (&mut self, hostname: &str) -> &mut ClientBuilder { + pub fn set_hostname (&mut self, hostname: &str) -> &mut ClientBuilder { self.hostname = Some(hostname.to_string()); self } - pub fn set_port (&mut self, port: u16) -> &mut ClientBuilder { + pub fn set_port (&mut self, port: u16) -> &mut ClientBuilder { self.port = port; self } - pub fn connect (self) -> Client { + pub fn connect (self) -> T { let nick = self.nick.clone(); let pass = self.pass.clone(); let hostname = self.hostname.clone(); @@ -74,7 +69,7 @@ impl ClientBuilder { Some(host) => host, None => { match client.socket_name() { - Some(host) => host.to_string(), + Some(ref host) => host.to_string(), // XXX something better here? None => "localhost".to_string(), } @@ -98,40 +93,34 @@ impl ClientBuilder { client } - pub fn connect_raw (self) -> Client { + pub fn connect_raw (self) -> T { let mut stream = io::TcpStream::connect(self.servername.as_slice(), self.port); let mut stream = stream.unwrap(); let socket_name = match stream.socket_name() { Ok(addr) => Some(addr.ip.to_string()), Err(_) => None, }; - Client { - conn: io::BufferedStream::new(stream), - socket_name: socket_name, - } + Client::new(io::BufferedStream::new(stream), socket_name) } } -impl Client { - pub fn read (&mut self) -> Message { +pub trait Client { + fn new (conn: io::BufferedStream, socket_name: Option) -> Self; + fn conn (&mut self) -> &mut io::BufferedStream; + fn socket_name (&self) -> Option<&str>; + + fn read (&mut self) -> Message { // \n isn't valid inside a message, so this should be fine. if the \n // we find isn't preceded by a \r, this will be caught by the message // parser. - let buf = self.conn.read_until(b'\n'); + let buf = self.conn().read_until(b'\n'); // XXX handle different encodings // XXX proper error handling Message::parse(str::from_utf8(buf.unwrap().as_slice()).unwrap()).unwrap() } - pub fn write (&mut self, msg: Message) { - msg.write_protocol_string(&mut self.conn); - } - - pub fn socket_name (&self) -> Option<&str> { - match self.socket_name { - Some(ref name) => Some(name.as_slice()), - None => None, - } + fn write (&mut self, msg: Message) { + msg.write_protocol_string(self.conn()); } // XXX eventually, we'll want to set up callbacks for specific events @@ -140,7 +129,7 @@ impl Client { // storing closures very well yet if they need to receive a borrowed // pointer, and we would need to pass the client object into the callback // in order to make this work - pub fn run_loop_with (mut self, handler: |&mut Client, Message|) { + fn run_loop_with (mut self, handler: |&mut Self, Message|) { loop { let m = self.read(); handler(&mut self, m); -- cgit v1.2.3-54-g00ecf