aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorZachary Dremann <dremann@gmail.com>2014-06-25 09:14:42 -0400
committerZachary Dremann <dremann@gmail.com>2014-06-25 09:14:42 -0400
commit4beb868e0ca2aa5ad9c29e4ba934c0fd8fc2501e (patch)
treef6dcc3385f737303e2876e1b5c1de63ad1dce59b /src
parentc140343437f4339ad88761bade9fd50038ae20ac (diff)
downloadrusty-irc-4beb868e0ca2aa5ad9c29e4ba934c0fd8fc2501e.tar.gz
rusty-irc-4beb868e0ca2aa5ad9c29e4ba934c0fd8fc2501e.zip
Allow IrcClient to be cloned, and sent between tasks.
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs147
1 files changed, 78 insertions, 69 deletions
diff --git a/src/lib.rs b/src/lib.rs
index eb31afc..64e267a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -3,64 +3,66 @@
use std::io::TcpStream;
use std::io::BufferedReader;
-use std::io::IoError;
+use std::io::{IoError, IoResult};
+use std::sync::{Arc, RWLock, Mutex};
use msg::Message;
use msg::cmd;
pub mod msg;
-pub mod state {
- use msg::Message;
- use std::io::TcpStream;
-
- pub struct Disconnected;
- pub struct Connected {
- pub output: Sender<Message>,
- pub stream: TcpStream,
- }
+#[deriving(Clone, PartialEq, Eq)]
+pub struct ClientConfig<T> {
+ pub nicks: T,
+ pub username: String,
+ pub real_name: String,
+}
- impl Drop for Connected {
- fn drop(&mut self) {
- let _ = self.stream.close_read();
- let _ = self.stream.close_write();
- }
- }
+struct SharedState<It> {
+ username: String,
+ real_name: String,
+ future_nicks: Mutex<It>,
+ chosen_nick: RWLock<String>,
}
-pub struct IrcClient<State> {
- nick: String,
- username: String,
- real_name: String,
- state: State,
+pub struct IrcClient<T> {
+ state: Arc<SharedState<T>>,
+ stream: TcpStream,
+ output_chan: Sender<Message>,
}
-impl IrcClient <state::Disconnected> {
- pub fn new(nick: String, username: String, real_name: String) -> IrcClient<state::Disconnected> {
- IrcClient { nick: nick, username: username, real_name: real_name, state: state::Disconnected }
+impl<T: Iterator<String>+Send+Share> Clone for IrcClient<T> {
+ fn clone(&self) -> IrcClient<T> {
+ IrcClient {
+ state: self.state.clone(),
+ stream: self.stream.clone(),
+ output_chan: self.output_chan.clone(),
+ }
}
+}
- #[allow(experimental)]
- pub fn connect(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))
- };
+impl<T: Iterator<String>+Send+Share> IrcClient<T> {
+ pub fn new(config: ClientConfig<T>, host: &str, port: u16, msg_chan: Sender<Message>) -> IoResult<IrcClient<T>> {
+ let ClientConfig { mut nicks, username, real_name } = config;
+ let stream = try!(TcpStream::connect(host, port));
let (send_writer, rec_writer) = channel();
- let IrcClient { nick:nick, username: username, real_name: real_name, .. } = self;
+ let chosen_nick = nicks.next().unwrap();
- let connection = IrcClient{
- nick: nick,
- username: username,
- real_name: real_name,
- state: state::Connected {
- stream: stream.clone(),
- output: send_writer.clone(),
- }
+ let state = SharedState {
+ username: username.clone(),
+ real_name: real_name.clone(),
+ future_nicks: Mutex::new(nicks),
+ chosen_nick: RWLock::new(chosen_nick.clone())
};
+ let connection = IrcClient {
+ state: Arc::new(state),
+ stream: stream.clone(),
+ output_chan: send_writer.clone()
+ };
+
let reader = stream.clone();
let writer = stream;
@@ -72,8 +74,10 @@ impl IrcClient <state::Disconnected> {
}
});
+ let reader_client = connection.clone();
std::task::TaskBuilder::new().named("rusty-irc:reader").spawn(proc() {
let mut reader = BufferedReader::new(reader);
+ let mut reader_client = reader_client;
loop {
unsafe {
let raw: *mut TcpStream = reader.get_ref() as *_ as *mut _;
@@ -84,53 +88,58 @@ impl IrcClient <state::Disconnected> {
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() {
+ if msg_chan.send_opt(msg.clone()).is_err() {
break;
}
+ reader_client.on_msg_rec(&msg);
},
None => println!("Invalid Message recieved"),
},
Err(IoError{kind: std::io::TimedOut, ..}) => continue,
- Err(e) => {
- fail!("Unable to read line: {}", e);
- }
+ Err(IoError{kind: std::io::EndOfFile, ..}) => fail!("Connection closed by server"),
+ Err(e) => fail!("Unable to read line: {}", e)
}
}
});
- Ok(connection)
- }
-
-}
+ connection.send(Message::new(cmd::Nick(chosen_nick)));
+ connection.send(Message::new(cmd::User(username, 8, real_name)));
-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,
- }
+ Ok(connection)
}
- pub fn send(&mut self, msg: Message) {
- self.state.output.send(msg);
+ #[inline]
+ pub fn send(&self, msg: Message) {
+ let _ = self.output_chan.send_opt(msg);
}
pub fn sender<'a>(&'a self) -> &'a Sender<Message> {
- &self.state.output
+ &self.output_chan
}
-}
-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(())
+ pub fn nick(&self) -> String {
+ self.state.chosen_nick.read().clone()
}
+
+ pub fn username<'a>(&'a self) -> &'a str {
+ self.state.username.as_slice()
+ }
+
+ pub fn real_name<'a>(&'a self) -> &'a str {
+ self.state.real_name.as_slice()
+ }
+
+ fn on_msg_rec(&mut self, msg: &Message) {
+ let _prefix = &msg.prefix;
+ let cmd = &msg.command;
+ match *cmd {
+ cmd::Ping(ref s) =>
+ self.send(Message::new(cmd::Pong(s.clone()))),
+ cmd::Numeric(443, _, _) => {
+ *self.state.chosen_nick.write() = self.state.future_nicks.lock().next().unwrap();
+ },
+ _ => ()
+ }
+ }
}
+