aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZachary Dremann <dremann@gmail.com>2014-06-11 23:43:41 -0400
committerZachary Dremann <dremann@gmail.com>2014-06-12 13:26:42 -0400
commitad4f61e29f3072fd7d9e78386439e52f8512287e (patch)
tree813b459827bda2de52d561d451d65590a4947a86
parentab946b42f3c9e195b709902320cc3566d67e6fa5 (diff)
downloadrusty-irc-ad4f61e29f3072fd7d9e78386439e52f8512287e.tar.gz
rusty-irc-ad4f61e29f3072fd7d9e78386439e52f8512287e.zip
Make construction of an IRC client 2 parts, create, then connect.
-rw-r--r--examples/client.rs17
-rw-r--r--src/lib.rs151
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);
+ }
}
diff --git a/src/lib.rs b/src/lib.rs
index 3898480..a707059 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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(())
}
}