Fixed unit tests for async changes.
This commit is contained in:
parent
77d44a5055
commit
86e224b8aa
6 changed files with 404 additions and 175 deletions
|
@ -29,5 +29,5 @@ serde_derive = "1.0"
|
|||
serde_json = "1.0"
|
||||
tokio-core = "0.1"
|
||||
tokio-io = "0.1"
|
||||
tokio-mockstream = "1.0"
|
||||
tokio-mockstream = "1.1"
|
||||
tokio-tls = "0.1"
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
//! A module providing IRC connections for use by `IrcServer`s.
|
||||
use std::fmt;
|
||||
use std::{fmt, io};
|
||||
use error;
|
||||
use client::data::Config;
|
||||
use client::transport::IrcTransport;
|
||||
use client::transport::{IrcTransport, LogView, Logged};
|
||||
use proto::{IrcCodec, Message};
|
||||
use encoding::{EncoderTrap};
|
||||
use encoding::label::encoding_from_whatwg_label;
|
||||
use futures::{Async, Poll, Future, Sink, StartSend, Stream};
|
||||
use native_tls::TlsConnector;
|
||||
use tokio_core::reactor::Handle;
|
||||
use tokio_core::net::{TcpStream, TcpStreamNew};
|
||||
use tokio_io::AsyncRead;
|
||||
use tokio_mockstream::MockStream;
|
||||
use tokio_tls::{TlsConnectorExt, TlsStream};
|
||||
|
||||
/// An IRC connection used internally by `IrcServer`.
|
||||
|
@ -17,6 +20,8 @@ pub enum Connection {
|
|||
Unsecured(IrcTransport<TcpStream>),
|
||||
#[doc(hidden)]
|
||||
Secured(IrcTransport<TlsStream<TcpStream>>),
|
||||
#[doc(hidden)]
|
||||
Mock(Logged<MockStream>),
|
||||
}
|
||||
|
||||
impl fmt::Debug for Connection {
|
||||
|
@ -27,6 +32,7 @@ impl fmt::Debug for Connection {
|
|||
match *self {
|
||||
Connection::Unsecured(_) => "Connection::Unsecured(...)",
|
||||
Connection::Secured(_) => "Connection::Secured(...)",
|
||||
Connection::Mock(_) => "Connection::Mock(...)",
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -41,6 +47,8 @@ pub enum ConnectionFuture<'a> {
|
|||
Unsecured(&'a Config, TcpStreamNew),
|
||||
#[doc(hidden)]
|
||||
Secured(&'a Config, TlsFuture),
|
||||
#[doc(hidden)]
|
||||
Mock(&'a Config),
|
||||
}
|
||||
|
||||
impl<'a> Future for ConnectionFuture<'a> {
|
||||
|
@ -61,6 +69,29 @@ impl<'a> Future for ConnectionFuture<'a> {
|
|||
|
||||
Ok(Async::Ready(Connection::Secured(transport)))
|
||||
}
|
||||
&mut ConnectionFuture::Mock(ref config) => {
|
||||
let enc: error::Result<_> = encoding_from_whatwg_label(config.encoding()).ok_or(
|
||||
io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
&format!("Attempted to use unknown codec {}.", config.encoding())[..],
|
||||
).into(),
|
||||
);
|
||||
let encoding = enc?;
|
||||
let init_str = config.mock_initial_value();
|
||||
let initial: error::Result<_> = {
|
||||
encoding.encode(&init_str, EncoderTrap::Replace).map_err(|data| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
&format!("Failed to encode {} as {}.", data, encoding.name())[..],
|
||||
).into()
|
||||
})
|
||||
};
|
||||
|
||||
let framed = MockStream::new(&initial?).framed(IrcCodec::new(config.encoding())?);
|
||||
let transport = IrcTransport::new(config, framed);
|
||||
|
||||
Ok(Async::Ready(Connection::Mock(Logged::wrap(transport))))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +99,9 @@ impl<'a> Future for ConnectionFuture<'a> {
|
|||
impl Connection {
|
||||
/// Creates a new `Connection` using the specified `Config` and `Handle`.
|
||||
pub fn new<'a>(config: &'a Config, handle: &Handle) -> error::Result<ConnectionFuture<'a>> {
|
||||
if config.use_ssl() {
|
||||
if config.use_mock_connection() {
|
||||
Ok(ConnectionFuture::Mock(config))
|
||||
} else if config.use_ssl() {
|
||||
let domain = format!("{}:{}", config.server(), config.port());
|
||||
let connector = TlsConnector::builder()?.build()?;
|
||||
let stream = TcpStream::connect(&config.socket_addr(), handle)
|
||||
|
@ -90,6 +123,15 @@ impl Connection {
|
|||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a view of the internal logging if and only if this connection is using a mock stream.
|
||||
/// Otherwise, this will always return `None`. This is used for unit testing.
|
||||
pub fn log_view(&self) -> Option<LogView> {
|
||||
match self {
|
||||
&Connection::Mock(ref inner) => Some(inner.view()),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Stream for Connection {
|
||||
|
@ -100,6 +142,7 @@ impl Stream for Connection {
|
|||
match self {
|
||||
&mut Connection::Unsecured(ref mut inner) => inner.poll(),
|
||||
&mut Connection::Secured(ref mut inner) => inner.poll(),
|
||||
&mut Connection::Mock(ref mut inner) => inner.poll(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -112,6 +155,7 @@ impl Sink for Connection {
|
|||
match self {
|
||||
&mut Connection::Unsecured(ref mut inner) => inner.start_send(item),
|
||||
&mut Connection::Secured(ref mut inner) => inner.start_send(item),
|
||||
&mut Connection::Mock(ref mut inner) => inner.start_send(item),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,6 +163,7 @@ impl Sink for Connection {
|
|||
match self {
|
||||
&mut Connection::Unsecured(ref mut inner) => inner.poll_complete(),
|
||||
&mut Connection::Secured(ref mut inner) => inner.poll_complete(),
|
||||
&mut Connection::Mock(ref mut inner) => inner.poll_complete(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,8 +8,8 @@ use client::conn::Connection;
|
|||
use client::data::{Command, Config, Message, Response, User};
|
||||
use client::data::Command::{JOIN, NICK, NICKSERV, PART, PRIVMSG, MODE, QUIT};
|
||||
use client::server::utils::ServerExt;
|
||||
use client::transport::LogView;
|
||||
use futures::{Async, Poll, Future, Sink, Stream};
|
||||
use futures::future;
|
||||
use futures::stream::SplitStream;
|
||||
use futures::sync::mpsc;
|
||||
use futures::sync::oneshot;
|
||||
|
@ -427,6 +427,8 @@ impl ServerState {
|
|||
pub struct IrcServer {
|
||||
/// The internal, thread-safe server state.
|
||||
state: Arc<ServerState>,
|
||||
/// A view of the logs for a mock connection.
|
||||
view: Option<LogView>,
|
||||
}
|
||||
|
||||
impl Server for IrcServer {
|
||||
|
@ -492,9 +494,10 @@ impl IrcServer {
|
|||
/// Creates a new IRC server connection from the specified configuration, connecting
|
||||
/// immediately.
|
||||
pub fn from_config(config: Config) -> error::Result<IrcServer> {
|
||||
// Setting up a remote reactor running forever.
|
||||
// Setting up a remote reactor running for the length of the connection.
|
||||
let (tx_outgoing, rx_outgoing) = mpsc::unbounded();
|
||||
let (tx_incoming, rx_incoming) = oneshot::channel();
|
||||
let (tx_view, rx_view) = oneshot::channel();
|
||||
|
||||
let cfg = config.clone();
|
||||
let _ = thread::spawn(move || {
|
||||
|
@ -502,39 +505,49 @@ impl IrcServer {
|
|||
|
||||
// Setting up internal processing stuffs.
|
||||
let handle = reactor.handle();
|
||||
let (sink, stream) = reactor
|
||||
let conn = reactor
|
||||
.run(Connection::new(&cfg, &handle).unwrap())
|
||||
.unwrap()
|
||||
.split();
|
||||
.unwrap();
|
||||
|
||||
tx_view.send(conn.log_view()).unwrap();
|
||||
let (sink, stream) = conn.split();
|
||||
|
||||
let outgoing_future = sink.send_all(rx_outgoing.map_err(|_| {
|
||||
let res: error::Error = error::ErrorKind::ChannelError.into();
|
||||
res
|
||||
}));
|
||||
handle.spawn(outgoing_future.map(|_| ()).map_err(|_| ()));
|
||||
})).map(|_| ()).map_err(|_| ());
|
||||
|
||||
// Send the stream half back to the original thread.
|
||||
tx_incoming.send(stream).unwrap();
|
||||
|
||||
reactor.run(future::empty::<(), ()>()).unwrap();
|
||||
reactor.run(outgoing_future).unwrap();
|
||||
});
|
||||
|
||||
Ok(IrcServer {
|
||||
state: Arc::new(ServerState::new(rx_incoming.wait()?, tx_outgoing, config)),
|
||||
view: rx_view.wait()?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Gets the log view from the internal transport. Only used for unit testing.
|
||||
#[cfg(test)]
|
||||
fn log_view(&self) -> &LogView {
|
||||
self.view.as_ref().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::{IrcServer, Server};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use std::collections::HashMap;
|
||||
use std::default::Default;
|
||||
use client::conn::MockConnection;
|
||||
use client::data::Config;
|
||||
#[cfg(not(feature = "nochanlists"))]
|
||||
use client::data::User;
|
||||
use proto::command::Command::{PART, PRIVMSG};
|
||||
use futures::{Future, Stream};
|
||||
|
||||
pub fn test_config() -> Config {
|
||||
Config {
|
||||
|
@ -544,53 +557,67 @@ mod test {
|
|||
server: Some(format!("irc.test.net")),
|
||||
channels: Some(vec![format!("#test"), format!("#test2")]),
|
||||
user_info: Some(format!("Testing.")),
|
||||
use_mock_connection: Some(true),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_server_value(server: IrcServer) -> String {
|
||||
server.conn().written(server.config().encoding()).unwrap()
|
||||
// We sleep here because of synchronization issues.
|
||||
// We can't guarantee that everything will have been sent by the time of this call.
|
||||
thread::sleep(Duration::from_millis(100));
|
||||
server.log_view().sent().unwrap().iter().fold(String::new(), |mut acc, msg| {
|
||||
acc.push_str(&msg.to_string());
|
||||
acc
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn iterator() {
|
||||
fn stream() {
|
||||
let exp = "PRIVMSG test :Hi!\r\nPRIVMSG test :This is a test!\r\n\
|
||||
:test!test@test JOIN #test\r\n";
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::new(exp));
|
||||
let server = IrcServer::from_config(Config {
|
||||
mock_initial_value: Some(exp.to_owned()),
|
||||
..test_config()
|
||||
}).unwrap();
|
||||
let mut messages = String::new();
|
||||
for message in server.iter() {
|
||||
messages.push_str(&message.unwrap().to_string());
|
||||
}
|
||||
server.stream().for_each(|message| {
|
||||
messages.push_str(&message.to_string());
|
||||
Ok(())
|
||||
}).wait().unwrap();
|
||||
assert_eq!(&messages[..], exp);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn handle_message() {
|
||||
let value = "PING :irc.test.net\r\n:irc.test.net 376 test :End of /MOTD command.\r\n";
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::new(value));
|
||||
for message in server.iter() {
|
||||
let value = ":irc.test.net 376 test :End of /MOTD command.\r\n";
|
||||
let server = IrcServer::from_config(Config {
|
||||
mock_initial_value: Some(value.to_owned()),
|
||||
..test_config()
|
||||
}).unwrap();
|
||||
server.stream().for_each(|message| {
|
||||
println!("{:?}", message);
|
||||
}
|
||||
Ok(())
|
||||
}).wait().unwrap();
|
||||
assert_eq!(
|
||||
&get_server_value(server)[..],
|
||||
"PONG :irc.test.net\r\nJOIN #test\r\nJOIN #test2\r\n"
|
||||
"JOIN #test\r\nJOIN #test2\r\n"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn handle_end_motd_with_nick_password() {
|
||||
let value = ":irc.test.net 376 test :End of /MOTD command.\r\n";
|
||||
let server = IrcServer::from_connection(
|
||||
Config {
|
||||
nick_password: Some(format!("password")),
|
||||
channels: Some(vec![format!("#test"), format!("#test2")]),
|
||||
..Default::default()
|
||||
},
|
||||
MockConnection::new(value),
|
||||
);
|
||||
for message in server.iter() {
|
||||
let server = IrcServer::from_config(Config {
|
||||
mock_initial_value: Some(value.to_owned()),
|
||||
nick_password: Some(format!("password")),
|
||||
channels: Some(vec![format!("#test"), format!("#test2")]),
|
||||
..test_config()
|
||||
}).unwrap();
|
||||
server.stream().for_each(|message| {
|
||||
println!("{:?}", message);
|
||||
}
|
||||
Ok(())
|
||||
}).wait().unwrap();
|
||||
assert_eq!(
|
||||
&get_server_value(server)[..],
|
||||
"NICKSERV IDENTIFY password\r\nJOIN #test\r\n\
|
||||
|
@ -601,22 +628,21 @@ mod test {
|
|||
#[test]
|
||||
fn handle_end_motd_with_chan_keys() {
|
||||
let value = ":irc.test.net 376 test :End of /MOTD command\r\n";
|
||||
let server = IrcServer::from_connection(
|
||||
Config {
|
||||
nickname: Some(format!("test")),
|
||||
channels: Some(vec![format!("#test"), format!("#test2")]),
|
||||
channel_keys: {
|
||||
let mut map = HashMap::new();
|
||||
map.insert(format!("#test2"), format!("password"));
|
||||
Some(map)
|
||||
},
|
||||
..Default::default()
|
||||
let server = IrcServer::from_config(Config {
|
||||
mock_initial_value: Some(value.to_owned()),
|
||||
nickname: Some(format!("test")),
|
||||
channels: Some(vec![format!("#test"), format!("#test2")]),
|
||||
channel_keys: {
|
||||
let mut map = HashMap::new();
|
||||
map.insert(format!("#test2"), format!("password"));
|
||||
Some(map)
|
||||
},
|
||||
MockConnection::new(value),
|
||||
);
|
||||
for message in server.iter() {
|
||||
..test_config()
|
||||
}).unwrap();
|
||||
server.stream().for_each(|message| {
|
||||
println!("{:?}", message);
|
||||
}
|
||||
Ok(())
|
||||
}).wait().unwrap();
|
||||
assert_eq!(
|
||||
&get_server_value(server)[..],
|
||||
"JOIN #test\r\nJOIN #test2 password\r\n"
|
||||
|
@ -627,20 +653,19 @@ mod test {
|
|||
fn handle_end_motd_with_ghost() {
|
||||
let value = ":irc.pdgn.co 433 * test :Nickname is already in use.\r\n\
|
||||
:irc.test.net 376 test2 :End of /MOTD command.\r\n";
|
||||
let server = IrcServer::from_connection(
|
||||
Config {
|
||||
nickname: Some(format!("test")),
|
||||
alt_nicks: Some(vec![format!("test2")]),
|
||||
nick_password: Some(format!("password")),
|
||||
channels: Some(vec![format!("#test"), format!("#test2")]),
|
||||
should_ghost: Some(true),
|
||||
..Default::default()
|
||||
},
|
||||
MockConnection::new(value),
|
||||
);
|
||||
for message in server.iter() {
|
||||
let server = IrcServer::from_config(Config {
|
||||
mock_initial_value: Some(value.to_owned()),
|
||||
nickname: Some(format!("test")),
|
||||
alt_nicks: Some(vec![format!("test2")]),
|
||||
nick_password: Some(format!("password")),
|
||||
channels: Some(vec![format!("#test"), format!("#test2")]),
|
||||
should_ghost: Some(true),
|
||||
..test_config()
|
||||
}).unwrap();
|
||||
server.stream().for_each(|message| {
|
||||
println!("{:?}", message);
|
||||
}
|
||||
Ok(())
|
||||
}).wait().unwrap();
|
||||
assert_eq!(
|
||||
&get_server_value(server)[..],
|
||||
"NICK :test2\r\nNICKSERV GHOST test password\r\n\
|
||||
|
@ -652,21 +677,20 @@ mod test {
|
|||
fn handle_end_motd_with_ghost_seq() {
|
||||
let value = ":irc.pdgn.co 433 * test :Nickname is already in use.\r\n\
|
||||
:irc.test.net 376 test2 :End of /MOTD command.\r\n";
|
||||
let server = IrcServer::from_connection(
|
||||
Config {
|
||||
nickname: Some(format!("test")),
|
||||
alt_nicks: Some(vec![format!("test2")]),
|
||||
nick_password: Some(format!("password")),
|
||||
channels: Some(vec![format!("#test"), format!("#test2")]),
|
||||
should_ghost: Some(true),
|
||||
ghost_sequence: Some(vec![format!("RECOVER"), format!("RELEASE")]),
|
||||
..Default::default()
|
||||
},
|
||||
MockConnection::new(value),
|
||||
);
|
||||
for message in server.iter() {
|
||||
let server = IrcServer::from_config(Config {
|
||||
mock_initial_value: Some(value.to_owned()),
|
||||
nickname: Some(format!("test")),
|
||||
alt_nicks: Some(vec![format!("test2")]),
|
||||
nick_password: Some(format!("password")),
|
||||
channels: Some(vec![format!("#test"), format!("#test2")]),
|
||||
should_ghost: Some(true),
|
||||
ghost_sequence: Some(vec![format!("RECOVER"), format!("RELEASE")]),
|
||||
..test_config()
|
||||
}).unwrap();
|
||||
server.stream().for_each(|message| {
|
||||
println!("{:?}", message);
|
||||
}
|
||||
Ok(())
|
||||
}).wait().unwrap();
|
||||
assert_eq!(
|
||||
&get_server_value(server)[..],
|
||||
"NICK :test2\r\nNICKSERV RECOVER test password\
|
||||
|
@ -678,18 +702,17 @@ mod test {
|
|||
#[test]
|
||||
fn handle_end_motd_with_umodes() {
|
||||
let value = ":irc.test.net 376 test :End of /MOTD command.\r\n";
|
||||
let server = IrcServer::from_connection(
|
||||
Config {
|
||||
nickname: Some(format!("test")),
|
||||
umodes: Some(format!("+B")),
|
||||
channels: Some(vec![format!("#test"), format!("#test2")]),
|
||||
..Default::default()
|
||||
},
|
||||
MockConnection::new(value),
|
||||
);
|
||||
for message in server.iter() {
|
||||
let server = IrcServer::from_config(Config {
|
||||
mock_initial_value: Some(value.to_owned()),
|
||||
nickname: Some(format!("test")),
|
||||
umodes: Some(format!("+B")),
|
||||
channels: Some(vec![format!("#test"), format!("#test2")]),
|
||||
..test_config()
|
||||
}).unwrap();
|
||||
server.stream().for_each(|message| {
|
||||
println!("{:?}", message);
|
||||
}
|
||||
Ok(())
|
||||
}).wait().unwrap();
|
||||
assert_eq!(
|
||||
&get_server_value(server)[..],
|
||||
"MODE test +B\r\nJOIN #test\r\nJOIN #test2\r\n"
|
||||
|
@ -698,11 +721,15 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn nickname_in_use() {
|
||||
let value = ":irc.pdgn.co 433 * test :Nickname is already in use.";
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::new(value));
|
||||
for message in server.iter() {
|
||||
let value = ":irc.pdgn.co 433 * test :Nickname is already in use.\r\n";
|
||||
let server = IrcServer::from_config(Config {
|
||||
mock_initial_value: Some(value.to_owned()),
|
||||
..test_config()
|
||||
}).unwrap();
|
||||
server.stream().for_each(|message| {
|
||||
println!("{:?}", message);
|
||||
}
|
||||
Ok(())
|
||||
}).wait().unwrap();
|
||||
assert_eq!(&get_server_value(server)[..], "NICK :test2\r\n");
|
||||
}
|
||||
|
||||
|
@ -711,15 +738,19 @@ mod test {
|
|||
fn ran_out_of_nicknames() {
|
||||
let value = ":irc.pdgn.co 433 * test :Nickname is already in use.\r\n\
|
||||
:irc.pdgn.co 433 * test2 :Nickname is already in use.\r\n";
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::new(value));
|
||||
for message in server.iter() {
|
||||
let server = IrcServer::from_config(Config {
|
||||
mock_initial_value: Some(value.to_owned()),
|
||||
..test_config()
|
||||
}).unwrap();
|
||||
server.stream().for_each(|message| {
|
||||
println!("{:?}", message);
|
||||
}
|
||||
Ok(())
|
||||
}).wait().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send() {
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::empty());
|
||||
let server = IrcServer::from_config(test_config()).unwrap();
|
||||
assert!(
|
||||
server
|
||||
.send(PRIVMSG(format!("#test"), format!("Hi there!")))
|
||||
|
@ -733,23 +764,27 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn send_no_newline_injection() {
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::empty());
|
||||
let server = IrcServer::from_config(test_config()).unwrap();
|
||||
assert!(
|
||||
server
|
||||
.send(PRIVMSG(format!("#test"), format!("Hi there!\nJOIN #bad")))
|
||||
.send(PRIVMSG(format!("#test"), format!("Hi there!\r\nJOIN #bad")))
|
||||
.is_ok()
|
||||
);
|
||||
assert_eq!(&get_server_value(server)[..], "PRIVMSG #test :Hi there!\n");
|
||||
assert_eq!(&get_server_value(server)[..], "PRIVMSG #test :Hi there!\r\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(feature = "nochanlists"))]
|
||||
fn channel_tracking_names() {
|
||||
let value = ":irc.test.net 353 test = #test :test ~owner &admin\r\n";
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::new(value));
|
||||
for message in server.iter() {
|
||||
let server = IrcServer::from_config(Config {
|
||||
mock_initial_value: Some(value.to_owned()),
|
||||
..test_config()
|
||||
}).unwrap();
|
||||
server.stream().for_each(|message| {
|
||||
println!("{:?}", message);
|
||||
}
|
||||
Ok(())
|
||||
}).wait().unwrap();
|
||||
assert_eq!(server.list_channels().unwrap(), vec!["#test".to_owned()])
|
||||
}
|
||||
|
||||
|
@ -757,10 +792,14 @@ mod test {
|
|||
#[cfg(not(feature = "nochanlists"))]
|
||||
fn channel_tracking_names_part() {
|
||||
let value = ":irc.test.net 353 test = #test :test ~owner &admin\r\n";
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::new(value));
|
||||
for message in server.iter() {
|
||||
let server = IrcServer::from_config(Config {
|
||||
mock_initial_value: Some(value.to_owned()),
|
||||
..test_config()
|
||||
}).unwrap();
|
||||
server.stream().for_each(|message| {
|
||||
println!("{:?}", message);
|
||||
}
|
||||
Ok(())
|
||||
}).wait().unwrap();
|
||||
assert!(server.send(PART(format!("#test"), None)).is_ok());
|
||||
assert!(server.list_channels().unwrap().is_empty())
|
||||
}
|
||||
|
@ -769,10 +808,14 @@ mod test {
|
|||
#[cfg(not(feature = "nochanlists"))]
|
||||
fn user_tracking_names() {
|
||||
let value = ":irc.test.net 353 test = #test :test ~owner &admin\r\n";
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::new(value));
|
||||
for message in server.iter() {
|
||||
let server = IrcServer::from_config(Config {
|
||||
mock_initial_value: Some(value.to_owned()),
|
||||
..test_config()
|
||||
}).unwrap();
|
||||
server.stream().for_each(|message| {
|
||||
println!("{:?}", message);
|
||||
}
|
||||
Ok(())
|
||||
}).wait().unwrap();
|
||||
assert_eq!(
|
||||
server.list_users("#test").unwrap(),
|
||||
vec![User::new("test"), User::new("~owner"), User::new("&admin")]
|
||||
|
@ -784,10 +827,14 @@ mod test {
|
|||
fn user_tracking_names_join() {
|
||||
let value = ":irc.test.net 353 test = #test :test ~owner &admin\r\n\
|
||||
:test2!test@test JOIN #test\r\n";
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::new(value));
|
||||
for message in server.iter() {
|
||||
let server = IrcServer::from_config(Config {
|
||||
mock_initial_value: Some(value.to_owned()),
|
||||
..test_config()
|
||||
}).unwrap();
|
||||
server.stream().for_each(|message| {
|
||||
println!("{:?}", message);
|
||||
}
|
||||
Ok(())
|
||||
}).wait().unwrap();
|
||||
assert_eq!(
|
||||
server.list_users("#test").unwrap(),
|
||||
vec![
|
||||
|
@ -804,10 +851,14 @@ mod test {
|
|||
fn user_tracking_names_part() {
|
||||
let value = ":irc.test.net 353 test = #test :test ~owner &admin\r\n\
|
||||
:owner!test@test PART #test\r\n";
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::new(value));
|
||||
for message in server.iter() {
|
||||
let server = IrcServer::from_config(Config {
|
||||
mock_initial_value: Some(value.to_owned()),
|
||||
..test_config()
|
||||
}).unwrap();
|
||||
server.stream().for_each(|message| {
|
||||
println!("{:?}", message);
|
||||
}
|
||||
Ok(())
|
||||
}).wait().unwrap();
|
||||
assert_eq!(
|
||||
server.list_users("#test").unwrap(),
|
||||
vec![User::new("test"), User::new("&admin")]
|
||||
|
@ -819,10 +870,14 @@ mod test {
|
|||
fn user_tracking_names_mode() {
|
||||
let value = ":irc.test.net 353 test = #test :+test ~owner &admin\r\n\
|
||||
:test!test@test MODE #test +o test\r\n";
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::new(value));
|
||||
for message in server.iter() {
|
||||
let server = IrcServer::from_config(Config {
|
||||
mock_initial_value: Some(value.to_owned()),
|
||||
..test_config()
|
||||
}).unwrap();
|
||||
server.stream().for_each(|message| {
|
||||
println!("{:?}", message);
|
||||
}
|
||||
Ok(())
|
||||
}).wait().unwrap();
|
||||
assert_eq!(
|
||||
server.list_users("#test").unwrap(),
|
||||
vec![User::new("@test"), User::new("~owner"), User::new("&admin")]
|
||||
|
@ -844,10 +899,14 @@ mod test {
|
|||
#[cfg(feature = "nochanlists")]
|
||||
fn no_user_tracking() {
|
||||
let value = ":irc.test.net 353 test = #test :test ~owner &admin";
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::new(value));
|
||||
for message in server.iter() {
|
||||
let server = IrcServer::from_config(Config {
|
||||
mock_initial_value: Some(value.to_owned()),
|
||||
..test_config()
|
||||
}).unwrap();
|
||||
server.stream().for_each(|message| {
|
||||
println!("{:?}", message);
|
||||
}
|
||||
Ok(())
|
||||
}).wait().unwrap();
|
||||
assert!(server.list_users("#test").is_none())
|
||||
}
|
||||
|
||||
|
@ -855,10 +914,14 @@ mod test {
|
|||
#[cfg(feature = "ctcp")]
|
||||
fn finger_response() {
|
||||
let value = ":test!test@test PRIVMSG test :\u{001}FINGER\u{001}\r\n";
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::new(value));
|
||||
for message in server.iter() {
|
||||
let server = IrcServer::from_config(Config {
|
||||
mock_initial_value: Some(value.to_owned()),
|
||||
..test_config()
|
||||
}).unwrap();
|
||||
server.stream().for_each(|message| {
|
||||
println!("{:?}", message);
|
||||
}
|
||||
Ok(())
|
||||
}).wait().unwrap();
|
||||
assert_eq!(
|
||||
&get_server_value(server)[..],
|
||||
"NOTICE test :\u{001}FINGER :test (test)\u{001}\
|
||||
|
@ -870,10 +933,14 @@ mod test {
|
|||
#[cfg(feature = "ctcp")]
|
||||
fn version_response() {
|
||||
let value = ":test!test@test PRIVMSG test :\u{001}VERSION\u{001}\r\n";
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::new(value));
|
||||
for message in server.iter() {
|
||||
let server = IrcServer::from_config(Config {
|
||||
mock_initial_value: Some(value.to_owned()),
|
||||
..test_config()
|
||||
}).unwrap();
|
||||
server.stream().for_each(|message| {
|
||||
println!("{:?}", message);
|
||||
}
|
||||
Ok(())
|
||||
}).wait().unwrap();
|
||||
assert_eq!(
|
||||
&get_server_value(server)[..],
|
||||
"NOTICE test :\u{001}VERSION irc:git:Rust\u{001}\
|
||||
|
@ -885,10 +952,14 @@ mod test {
|
|||
#[cfg(feature = "ctcp")]
|
||||
fn source_response() {
|
||||
let value = ":test!test@test PRIVMSG test :\u{001}SOURCE\u{001}\r\n";
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::new(value));
|
||||
for message in server.iter() {
|
||||
let server = IrcServer::from_config(Config {
|
||||
mock_initial_value: Some(value.to_owned()),
|
||||
..test_config()
|
||||
}).unwrap();
|
||||
server.stream().for_each(|message| {
|
||||
println!("{:?}", message);
|
||||
}
|
||||
Ok(())
|
||||
}).wait().unwrap();
|
||||
assert_eq!(
|
||||
&get_server_value(server)[..],
|
||||
"NOTICE test :\u{001}SOURCE https://github.com/aatxe/irc\u{001}\r\n\
|
||||
|
@ -900,10 +971,14 @@ mod test {
|
|||
#[cfg(feature = "ctcp")]
|
||||
fn ctcp_ping_response() {
|
||||
let value = ":test!test@test PRIVMSG test :\u{001}PING test\u{001}\r\n";
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::new(value));
|
||||
for message in server.iter() {
|
||||
let server = IrcServer::from_config(Config {
|
||||
mock_initial_value: Some(value.to_owned()),
|
||||
..test_config()
|
||||
}).unwrap();
|
||||
server.stream().for_each(|message| {
|
||||
println!("{:?}", message);
|
||||
}
|
||||
Ok(())
|
||||
}).wait().unwrap();
|
||||
assert_eq!(
|
||||
&get_server_value(server)[..],
|
||||
"NOTICE test :\u{001}PING test\u{001}\r\n"
|
||||
|
@ -914,10 +989,14 @@ mod test {
|
|||
#[cfg(feature = "ctcp")]
|
||||
fn time_response() {
|
||||
let value = ":test!test@test PRIVMSG test :\u{001}TIME\u{001}\r\n";
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::new(value));
|
||||
for message in server.iter() {
|
||||
let server = IrcServer::from_config(Config {
|
||||
mock_initial_value: Some(value.to_owned()),
|
||||
..test_config()
|
||||
}).unwrap();
|
||||
server.stream().for_each(|message| {
|
||||
println!("{:?}", message);
|
||||
}
|
||||
Ok(())
|
||||
}).wait().unwrap();
|
||||
let val = get_server_value(server);
|
||||
assert!(val.starts_with("NOTICE test :\u{001}TIME :"));
|
||||
assert!(val.ends_with("\u{001}\r\n"));
|
||||
|
@ -927,10 +1006,14 @@ mod test {
|
|||
#[cfg(feature = "ctcp")]
|
||||
fn user_info_response() {
|
||||
let value = ":test!test@test PRIVMSG test :\u{001}USERINFO\u{001}\r\n";
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::new(value));
|
||||
for message in server.iter() {
|
||||
let server = IrcServer::from_config(Config {
|
||||
mock_initial_value: Some(value.to_owned()),
|
||||
..test_config()
|
||||
}).unwrap();
|
||||
server.stream().for_each(|message| {
|
||||
println!("{:?}", message);
|
||||
}
|
||||
Ok(())
|
||||
}).wait().unwrap();
|
||||
assert_eq!(
|
||||
&get_server_value(server)[..],
|
||||
"NOTICE test :\u{001}USERINFO :Testing.\u{001}\
|
||||
|
@ -942,10 +1025,14 @@ mod test {
|
|||
#[cfg(feature = "ctcp")]
|
||||
fn ctcp_ping_no_timestamp() {
|
||||
let value = ":test!test@test PRIVMSG test :\u{001}PING\u{001}\r\n";
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::new(value));
|
||||
for message in server.iter() {
|
||||
let server = IrcServer::from_config(Config {
|
||||
mock_initial_value: Some(value.to_owned()),
|
||||
..test_config()
|
||||
}).unwrap();
|
||||
server.stream().for_each(|message| {
|
||||
println!("{:?}", message);
|
||||
}
|
||||
Ok(())
|
||||
}).wait().unwrap();
|
||||
assert_eq!(&get_server_value(server)[..], "");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -354,15 +354,13 @@ where
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::ServerExt;
|
||||
use std::default::Default;
|
||||
use client::conn::MockConnection;
|
||||
use client::data::Config;
|
||||
use client::server::IrcServer;
|
||||
use client::server::test::{get_server_value, test_config};
|
||||
|
||||
#[test]
|
||||
fn identify() {
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::empty());
|
||||
let server = IrcServer::from_config(test_config()).unwrap();
|
||||
server.identify().unwrap();
|
||||
assert_eq!(
|
||||
&get_server_value(server)[..],
|
||||
|
@ -373,14 +371,11 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn identify_with_password() {
|
||||
let server = IrcServer::from_connection(
|
||||
Config {
|
||||
nickname: Some(format!("test")),
|
||||
password: Some(format!("password")),
|
||||
..Default::default()
|
||||
},
|
||||
MockConnection::empty(),
|
||||
);
|
||||
let server = IrcServer::from_config(Config {
|
||||
nickname: Some(format!("test")),
|
||||
password: Some(format!("password")),
|
||||
..test_config()
|
||||
}).unwrap();
|
||||
server.identify().unwrap();
|
||||
assert_eq!(
|
||||
&get_server_value(server)[..],
|
||||
|
@ -391,14 +386,14 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn send_pong() {
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::empty());
|
||||
let server = IrcServer::from_config(test_config()).unwrap();
|
||||
server.send_pong("irc.test.net").unwrap();
|
||||
assert_eq!(&get_server_value(server)[..], "PONG :irc.test.net\r\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_join() {
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::empty());
|
||||
let server = IrcServer::from_config(test_config()).unwrap();
|
||||
server.send_join("#test,#test2,#test3").unwrap();
|
||||
assert_eq!(
|
||||
&get_server_value(server)[..],
|
||||
|
@ -408,21 +403,21 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn send_part() {
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::empty());
|
||||
let server = IrcServer::from_config(test_config()).unwrap();
|
||||
server.send_part("#test").unwrap();
|
||||
assert_eq!(&get_server_value(server)[..], "PART #test\r\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_oper() {
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::empty());
|
||||
let server = IrcServer::from_config(test_config()).unwrap();
|
||||
server.send_oper("test", "test").unwrap();
|
||||
assert_eq!(&get_server_value(server)[..], "OPER test :test\r\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_privmsg() {
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::empty());
|
||||
let server = IrcServer::from_config(test_config()).unwrap();
|
||||
server.send_privmsg("#test", "Hi, everybody!").unwrap();
|
||||
assert_eq!(
|
||||
&get_server_value(server)[..],
|
||||
|
@ -432,7 +427,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn send_notice() {
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::empty());
|
||||
let server = IrcServer::from_config(test_config()).unwrap();
|
||||
server.send_notice("#test", "Hi, everybody!").unwrap();
|
||||
assert_eq!(
|
||||
&get_server_value(server)[..],
|
||||
|
@ -442,14 +437,14 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn send_topic_no_topic() {
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::empty());
|
||||
let server = IrcServer::from_config(test_config()).unwrap();
|
||||
server.send_topic("#test", "").unwrap();
|
||||
assert_eq!(&get_server_value(server)[..], "TOPIC #test\r\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_topic() {
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::empty());
|
||||
let server = IrcServer::from_config(test_config()).unwrap();
|
||||
server.send_topic("#test", "Testing stuff.").unwrap();
|
||||
assert_eq!(
|
||||
&get_server_value(server)[..],
|
||||
|
@ -459,7 +454,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn send_kill() {
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::empty());
|
||||
let server = IrcServer::from_config(test_config()).unwrap();
|
||||
server.send_kill("test", "Testing kills.").unwrap();
|
||||
assert_eq!(
|
||||
&get_server_value(server)[..],
|
||||
|
@ -469,14 +464,14 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn send_kick_no_message() {
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::empty());
|
||||
let server = IrcServer::from_config(test_config()).unwrap();
|
||||
server.send_kick("#test", "test", "").unwrap();
|
||||
assert_eq!(&get_server_value(server)[..], "KICK #test test\r\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_kick() {
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::empty());
|
||||
let server = IrcServer::from_config(test_config()).unwrap();
|
||||
server.send_kick("#test", "test", "Testing kicks.").unwrap();
|
||||
assert_eq!(
|
||||
&get_server_value(server)[..],
|
||||
|
@ -486,42 +481,42 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn send_mode_no_modeparams() {
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::empty());
|
||||
let server = IrcServer::from_config(test_config()).unwrap();
|
||||
server.send_mode("#test", "+i", "").unwrap();
|
||||
assert_eq!(&get_server_value(server)[..], "MODE #test +i\r\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_mode() {
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::empty());
|
||||
let server = IrcServer::from_config(test_config()).unwrap();
|
||||
server.send_mode("#test", "+o", "test").unwrap();
|
||||
assert_eq!(&get_server_value(server)[..], "MODE #test +o test\r\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_samode_no_modeparams() {
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::empty());
|
||||
let server = IrcServer::from_config(test_config()).unwrap();
|
||||
server.send_samode("#test", "+i", "").unwrap();
|
||||
assert_eq!(&get_server_value(server)[..], "SAMODE #test +i\r\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_samode() {
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::empty());
|
||||
let server = IrcServer::from_config(test_config()).unwrap();
|
||||
server.send_samode("#test", "+o", "test").unwrap();
|
||||
assert_eq!(&get_server_value(server)[..], "SAMODE #test +o test\r\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_sanick() {
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::empty());
|
||||
let server = IrcServer::from_config(test_config()).unwrap();
|
||||
server.send_sanick("test", "test2").unwrap();
|
||||
assert_eq!(&get_server_value(server)[..], "SANICK test test2\r\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_invite() {
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::empty());
|
||||
let server = IrcServer::from_config(test_config()).unwrap();
|
||||
server.send_invite("test", "#test").unwrap();
|
||||
assert_eq!(&get_server_value(server)[..], "INVITE test #test\r\n");
|
||||
}
|
||||
|
@ -529,7 +524,7 @@ mod test {
|
|||
#[test]
|
||||
#[cfg(feature = "ctcp")]
|
||||
fn send_ctcp() {
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::empty());
|
||||
let server = IrcServer::from_config(test_config()).unwrap();
|
||||
server.send_ctcp("test", "MESSAGE").unwrap();
|
||||
assert_eq!(
|
||||
&get_server_value(server)[..],
|
||||
|
@ -540,7 +535,7 @@ mod test {
|
|||
#[test]
|
||||
#[cfg(feature = "ctcp")]
|
||||
fn send_action() {
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::empty());
|
||||
let server = IrcServer::from_config(test_config()).unwrap();
|
||||
server.send_action("test", "tests.").unwrap();
|
||||
assert_eq!(
|
||||
&get_server_value(server)[..],
|
||||
|
@ -551,7 +546,7 @@ mod test {
|
|||
#[test]
|
||||
#[cfg(feature = "ctcp")]
|
||||
fn send_finger() {
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::empty());
|
||||
let server = IrcServer::from_config(test_config()).unwrap();
|
||||
server.send_finger("test").unwrap();
|
||||
assert_eq!(
|
||||
&get_server_value(server)[..],
|
||||
|
@ -562,7 +557,7 @@ mod test {
|
|||
#[test]
|
||||
#[cfg(feature = "ctcp")]
|
||||
fn send_version() {
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::empty());
|
||||
let server = IrcServer::from_config(test_config()).unwrap();
|
||||
server.send_version("test").unwrap();
|
||||
assert_eq!(
|
||||
&get_server_value(server)[..],
|
||||
|
@ -573,7 +568,7 @@ mod test {
|
|||
#[test]
|
||||
#[cfg(feature = "ctcp")]
|
||||
fn send_source() {
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::empty());
|
||||
let server = IrcServer::from_config(test_config()).unwrap();
|
||||
server.send_source("test").unwrap();
|
||||
assert_eq!(
|
||||
&get_server_value(server)[..],
|
||||
|
@ -584,7 +579,7 @@ mod test {
|
|||
#[test]
|
||||
#[cfg(feature = "ctcp")]
|
||||
fn send_user_info() {
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::empty());
|
||||
let server = IrcServer::from_config(test_config()).unwrap();
|
||||
server.send_user_info("test").unwrap();
|
||||
assert_eq!(
|
||||
&get_server_value(server)[..],
|
||||
|
@ -595,7 +590,7 @@ mod test {
|
|||
#[test]
|
||||
#[cfg(feature = "ctcp")]
|
||||
fn send_ctcp_ping() {
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::empty());
|
||||
let server = IrcServer::from_config(test_config()).unwrap();
|
||||
server.send_ctcp_ping("test").unwrap();
|
||||
let val = get_server_value(server);
|
||||
println!("{}", val);
|
||||
|
@ -606,7 +601,7 @@ mod test {
|
|||
#[test]
|
||||
#[cfg(feature = "ctcp")]
|
||||
fn send_time() {
|
||||
let server = IrcServer::from_connection(test_config(), MockConnection::empty());
|
||||
let server = IrcServer::from_config(test_config()).unwrap();
|
||||
server.send_time("test").unwrap();
|
||||
assert_eq!(
|
||||
&get_server_value(server)[..],
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
//! An IRC transport that wraps an IRC-framed stream to provide automatic PING replies.
|
||||
use std::io;
|
||||
use std::sync::{Arc, RwLock, RwLockReadGuard};
|
||||
use std::time::Instant;
|
||||
use error;
|
||||
use client::data::Config;
|
||||
|
@ -30,6 +31,11 @@ where
|
|||
last_ping: Instant::now(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the inner stream underlying the `IrcTransport`.
|
||||
pub fn into_inner(self) -> Framed<T, IrcCodec> {
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Stream for IrcTransport<T>
|
||||
|
@ -76,3 +82,93 @@ where
|
|||
Ok(self.inner.poll_complete()?)
|
||||
}
|
||||
}
|
||||
|
||||
/// A view of the logs from a particular `Logged` transport.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct LogView {
|
||||
sent: Arc<RwLock<Vec<Message>>>,
|
||||
received: Arc<RwLock<Vec<Message>>>,
|
||||
}
|
||||
|
||||
impl LogView {
|
||||
/// Gets a read guard for all the messages sent on the transport.
|
||||
pub fn sent(&self) -> error::Result<RwLockReadGuard<Vec<Message>>> {
|
||||
self.sent.read().map_err(|_|
|
||||
error::ErrorKind::PoisonedLog.into()
|
||||
)
|
||||
}
|
||||
|
||||
/// Gets a read guard for all the messages received on the transport.
|
||||
pub fn received(&self) -> error::Result<RwLockReadGuard<Vec<Message>>> {
|
||||
self.received.read().map_err(|_|
|
||||
error::ErrorKind::PoisonedLog.into()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// A logged version of the `IrcTransport` that records all sent and received messages.
|
||||
/// Note: this will introduce some performance overhead by cloning all messages.
|
||||
pub struct Logged<T> where T: AsyncRead + AsyncWrite {
|
||||
inner: IrcTransport<T>,
|
||||
view: LogView,
|
||||
}
|
||||
|
||||
impl<T> Logged<T> where T: AsyncRead + AsyncWrite {
|
||||
/// Wraps the given `IrcTransport` in logging.
|
||||
pub fn wrap(inner: IrcTransport<T>) -> Logged<T> {
|
||||
Logged {
|
||||
inner: inner,
|
||||
view: LogView {
|
||||
sent: Arc::new(RwLock::new(vec![])),
|
||||
received: Arc::new(RwLock::new(vec![])),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a view of the logging for this transport.
|
||||
pub fn view(&self) -> LogView {
|
||||
self.view.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Stream for Logged<T>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite,
|
||||
{
|
||||
type Item = Message;
|
||||
type Error = error::Error;
|
||||
|
||||
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
|
||||
match try_ready!(self.inner.poll()) {
|
||||
Some(msg) => {
|
||||
let recv: error::Result<_> = self.view.received.write().map_err(|_|
|
||||
error::ErrorKind::PoisonedLog.into()
|
||||
);
|
||||
recv?.push(msg.clone());
|
||||
Ok(Async::Ready(Some(msg)))
|
||||
},
|
||||
None => Ok(Async::Ready(None))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Sink for Logged<T>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite,
|
||||
{
|
||||
type SinkItem = Message;
|
||||
type SinkError = error::Error;
|
||||
|
||||
fn start_send(&mut self, item: Self::SinkItem) -> StartSend<Self::SinkItem, Self::SinkError> {
|
||||
let res = self.inner.start_send(item.clone())?;
|
||||
let sent: error::Result<_> = self.view.sent.write().map_err(|_|
|
||||
error::ErrorKind::PoisonedLog.into()
|
||||
);
|
||||
sent?.push(item);
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
|
||||
Ok(self.inner.poll_complete()?)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,5 +35,11 @@ error_chain! {
|
|||
description("An error occured on one of the IrcServer's internal channels.")
|
||||
display("An error occured on one of the IrcServer's internal channels.")
|
||||
}
|
||||
|
||||
/// An error occured causing a mutex for a logged transport to be poisoned.
|
||||
PoisonedLog {
|
||||
description("An error occured causing a mutex for a logged transport to be poisoned.")
|
||||
display("An error occured causing a mutex for a logged transport to be poisoned.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue