diff options
author | Zachary Dremann <dremann@gmail.com> | 2014-06-11 23:43:41 -0400 |
---|---|---|
committer | Zachary Dremann <dremann@gmail.com> | 2014-06-12 13:26:42 -0400 |
commit | ad4f61e29f3072fd7d9e78386439e52f8512287e (patch) | |
tree | 813b459827bda2de52d561d451d65590a4947a86 | |
parent | ab946b42f3c9e195b709902320cc3566d67e6fa5 (diff) | |
download | rusty-irc-ad4f61e29f3072fd7d9e78386439e52f8512287e.tar.gz rusty-irc-ad4f61e29f3072fd7d9e78386439e52f8512287e.zip |
Make construction of an IRC client 2 parts, create, then connect.
-rw-r--r-- | examples/client.rs | 17 | ||||
-rw-r--r-- | src/lib.rs | 151 |
2 files changed, 107 insertions, 61 deletions
diff --git a/examples/client.rs b/examples/client.rs index 4363060..0419816 100644 --- a/examples/client.rs +++ b/examples/client.rs @@ -3,8 +3,6 @@ extern crate irc; use std::io::stdio; use irc::IrcClient; -use irc::msg::Message; -//use irc::msg::cmd; fn main() { let mut stderr = stdio::stderr(); @@ -17,13 +15,12 @@ fn main() { drop(args); - let mut connection = IrcClient::connect(host.as_slice(), port, "rusty-irc".to_string(), "dremann".to_string(), "Zachary Dremann".to_string()).unwrap(); - let sender = connection.sender(); + let (tx, rx) = channel(); + + let client = IrcClient::new("rusti-irc".to_string(), "dremann".to_string(), "Zachary Dremann".to_string()); + let connection = client.connect(host.as_slice(), port, tx).ok().unwrap(); + let sender = connection.sender().clone(); - let on_msg = |message: &Message| { - println!("{} {}", message.prefix, message.command); - }; - spawn(proc() { let mut stdin = stdio::stdin(); for line in stdin.lines() { @@ -39,5 +36,7 @@ fn main() { } }); - connection.run_loop(on_msg); + for msg in rx.iter() { + println!("{} {}", msg.prefix, msg.command); + } } @@ -1,8 +1,7 @@ #![crate_id = "irc#0.1"] #![crate_type = "lib"] -use std::io::net::tcp::TcpStream; -use std::io::IoResult; +use std::io::TcpStream; use std::io::BufferedReader; use std::io::IoError; @@ -11,24 +10,58 @@ use msg::cmd; pub mod msg; -pub struct IrcClient { - stream: TcpStream, - output_sender: Sender<Message>, +pub mod state { + use msg::Message; + use std::io::TcpStream; + + pub struct Disconnected; + pub struct Connected { + pub output: Sender<Message>, + pub stream: TcpStream, + } + + impl Drop for Connected { + fn drop(&mut self) { + let _ = self.stream.close_read(); + let _ = self.stream.close_write(); + } + } +} + +pub struct IrcClient<State> { + nick: Option<String>, + username: Option<String>, + real_name: Option<String>, + state: State, } -impl IrcClient { - pub fn connect( - host: &str, port: u16, nick: String, username: String, real_name: String) -> IoResult<IrcClient> { - +impl IrcClient <state::Disconnected> { + pub fn new(nick: String, username: String, real_name: String) -> IrcClient<state::Disconnected> { + IrcClient { nick: Some(nick), username: Some(username), real_name: Some(real_name), state: state::Disconnected } + } + + #[allow(experimental)] + pub fn connect(mut self, host: &str, port: u16, message_sender: Sender<Message>) -> Result<IrcClient<state::Connected>, (IoError, IrcClient<state::Disconnected>)> { + let stream = match TcpStream::connect(host, port) { + Ok(stream) => stream, + Err(e) => return Err((e, self)) + }; + let (send_writer, rec_writer) = channel(); - let mut connection = IrcClient{ - stream: try!(TcpStream::connect(host, port)), - output_sender: send_writer.clone(), + let connection = IrcClient{ + nick: self.nick.take(), + username: self.username.take(), + real_name: self.real_name.take(), + state: state::Connected { + stream: stream.clone(), + output: send_writer.clone(), + } }; - let writer = connection.stream.clone(); - + let reader = stream.clone(); + let writer = stream; + // spawn writer thread spawn(proc() { let mut writer = writer; @@ -37,52 +70,66 @@ impl IrcClient { } }); - connection.send(Message::new(cmd::Nick(nick))); - connection.send(Message::new(cmd::User(username, 8, real_name))); + spawn(proc() { + let mut reader = reader; + loop { + fn reader_by_ref<'a, R: Reader>(reader: &'a mut R) -> std::io::RefReader<'a, R> { reader.by_ref() } + + reader.set_read_timeout(Some(500)); + let mut buf_reader = BufferedReader::new(reader_by_ref(&mut reader)); + + let line = buf_reader.read_line(); + match line { + Ok(line) => match from_str::<Message>(line.as_slice().trim_right()) { + Some(msg) => { + if message_sender.send_opt(msg.clone()).is_err() { + break; + } + if on_msg_rec(&msg, &send_writer).is_err() { + break; + } + }, + None => println!("Invalid Message recieved"), + }, + Err(IoError{kind: std::io::TimedOut, ..}) => continue, + Err(e) => { + println!("Unable to read line: {}", e); + break; + } + } + } + }); + Ok(connection) } - pub fn send(&mut self, message: Message) { - self.output_sender.send(message); +} + +impl IrcClient<state::Connected> { + pub fn disconnect(self) -> IrcClient<state::Disconnected> { + let IrcClient { nick: nick, username:username, real_name:real_name, .. } = self; + IrcClient { + state: state::Disconnected, + nick: nick, + username: username, + real_name: real_name, + } } - pub fn sender(&self) -> Sender<Message> { - self.output_sender.clone() + pub fn send(&mut self, msg: Message) { + self.state.output.send(msg); } - fn on_msg_rec(msg: &Message, sender: &Sender<Message>) { - let _prefix = &msg.prefix; - let cmd = &msg.command; - match *cmd { - cmd::Ping(ref s) => sender.send(Message::new(cmd::Pong(s.clone()))), - _ => { } - }; + pub fn sender<'a>(&'a self) -> &'a Sender<Message> { + &self.state.output } +} - #[allow(experimental)] - pub fn run_loop(&mut self, on_msg: |&Message| -> ()) { - let reader = &mut self.stream; - loop { - fn reader_by_ref<'a, R: Reader>(reader: &'a mut R) -> std::io::RefReader<'a, R> { reader.by_ref() } - - reader.set_read_timeout(Some(500)); - let mut buf_reader = BufferedReader::new(reader_by_ref(reader)); - - let line = buf_reader.read_line(); - match line { - Ok(line) => match from_str::<Message>(line.as_slice().trim_right()) { - Some(msg) => { - IrcClient::on_msg_rec(&msg, &self.output_sender); - on_msg(&msg); - }, - None => println!("Invalid Message recieved"), - }, - Err(IoError{kind: std::io::TimedOut, ..}) => continue, - Err(e) => { - println!("Unable to read line: {}", e); - break; - } - } - } +fn on_msg_rec(msg: &Message, sender: &Sender<Message>) -> Result<(), Message> { + let _prefix = &msg.prefix; + let cmd = &msg.command; + match *cmd { + cmd::Ping(ref s) => sender.send_opt(Message::new(cmd::Pong(s.clone()))), + _ => Ok(()) } } |