diff --git a/src/conn.rs b/src/conn.rs index 5d34548..67b744c 100644 --- a/src/conn.rs +++ b/src/conn.rs @@ -19,41 +19,65 @@ pub struct Connection { /// A Connection over a buffered NetStream. pub type NetConnection = Connection, BufferedWriter>; +/// An internal type +type NetReaderWriterPair = (BufferedReader, BufferedWriter); + impl Connection, BufferedWriter> { /// Creates a thread-safe TCP connection to the specified server. #[experimental] - pub fn connect(host: &str, port: u16) - -> IoResult { + pub fn connect(host: &str, port: u16) -> IoResult { + let (reader, writer) = try!(Connection::connect_internal(host, port)); + Ok(Connection::new(reader, writer)) + } + + /// connects to the specified server and returns a reader-writer pair. + fn connect_internal(host: &str, port: u16) -> IoResult { let socket = try!(TcpStream::connect(format!("{}:{}", host, port)[])); - Ok(Connection::new( - BufferedReader::new(NetStream::UnsecuredTcpStream(socket.clone())), - BufferedWriter::new(NetStream::UnsecuredTcpStream(socket)) - )) + Ok((BufferedReader::new(NetStream::UnsecuredTcpStream(socket.clone())), + BufferedWriter::new(NetStream::UnsecuredTcpStream(socket)))) } /// Creates a thread-safe TCP connection to the specified server over SSL. /// If the library is compiled without SSL support, this method panics. #[experimental] - #[cfg(feature = "ssl")] pub fn connect_ssl(host: &str, port: u16) -> IoResult { + let (reader, writer) = try!(Connection::connect_ssl_internal(host, port)); + Ok(Connection::new(reader, writer)) + } + + /// Connects over SSL to the specified server and returns a reader-writer pair. + #[cfg(feature = "ssl")] + fn connect_ssl_internal(host: &str, port: u16) -> IoResult { let socket = try!(TcpStream::connect(format!("{}:{}", host, port)[])); let ssl = try!(ssl_to_io(SslContext::new(SslMethod::Tlsv1))); let ssl_socket = try!(ssl_to_io(SslStream::new(&ssl, socket))); - Ok(Connection::new( - BufferedReader::new(NetStream::SslTcpStream(ssl_socket.clone())), - BufferedWriter::new(NetStream::SslTcpStream(ssl_socket)), - )) + Ok((BufferedReader::new(NetStream::SslTcpStream(ssl_socket.clone())), + BufferedWriter::new(NetStream::SslTcpStream(ssl_socket)))) } - /// Creates a thread-safe TCP connection to the specified server over SSL. - /// If the library is compiled without SSL support, this method panics. - #[experimental] + /// Panics because SSL support is not compiled in. #[cfg(not(feature = "ssl"))] - pub fn connect_ssl(host: &str, port: u16) - -> IoResult { + fn connect_ssl_internal(host: &str, port: u16) -> IoResult { panic!("Cannot connect to {}:{} over SSL without compiling with SSL support.", host, port) } + + /// Reconnects to the specified server, dropping the current connection. + pub fn reconnect(&self, host: &str, port: u16) -> IoResult<()> { + let use_ssl = match self.reader.lock().get_ref() { + &NetStream::UnsecuredTcpStream(_) => false, + #[cfg(feature = "ssl")] + &NetStream::SslTcpStream(_) => true, + }; + let (reader, writer) = if use_ssl { + try!(Connection::connect_ssl_internal(host, port)) + } else { + try!(Connection::connect_internal(host, port)) + }; + *self.reader.lock() = reader; + *self.writer.lock() = writer; + Ok(()) + } /// Sets the keepalive for the network stream. #[experimental] diff --git a/src/server/mod.rs b/src/server/mod.rs index 5002a3c..c5a7331 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -62,13 +62,8 @@ impl IrcServer, BufferedWriter> { /// Reconnects to the IRC server. #[experimental] - pub fn reconnect(&mut self) -> IoResult<()> { - self.conn = try!(if self.config.use_ssl() { - Connection::connect_ssl(self.config.server(), self.config.port()) - } else { - Connection::connect(self.config.server(), self.config.port()) - }); - Ok(()) + pub fn reconnect(&self) -> IoResult<()> { + self.conn.reconnect(self.config().server(), self.config.port()) } } diff --git a/src/server/utils.rs b/src/server/utils.rs index 31da151..b0323a2 100644 --- a/src/server/utils.rs +++ b/src/server/utils.rs @@ -4,7 +4,7 @@ use std::io::IoResult; use data::{Command, Config, User}; use data::Command::{CAP, INVITE, JOIN, KICK, KILL, MODE, NICK, NOTICE}; -use data::Command::{OPER, PASS, PONG, PRIVMSG, SAMODE, SANICK, TOPIC, USER}; +use data::Command::{OPER, PASS, PONG, PRIVMSG, QUIT, SAMODE, SANICK, TOPIC, USER}; use data::command::CapSubCommand::{END, REQ}; use data::kinds::{IrcReader, IrcWriter}; use server::{Server, ServerIterator}; @@ -153,6 +153,17 @@ impl<'a, T: IrcReader, U: IrcWriter> Wrapper<'a, T, U> { pub fn send_invite(&self, nick: &str, chan: &str) -> IoResult<()> { self.server.send(INVITE(nick, chan)) } + + /// Quits the server entirely with a message. + /// This defaults to `Powered by Rust.` if none is specified. + #[experimental] + pub fn send_quit(&self, msg: &str) -> IoResult<()> { + self.server.send(QUIT(Some(if msg.len() == 0 { + "Powered by Rust." + } else { + msg + }))) + } } #[cfg(test)]