Cleaned up tests and documentation after the big renaming.

This commit is contained in:
Aaron Weiss 2018-01-28 03:19:05 +01:00
parent 87b84fdeb9
commit 59f426ac8d
No known key found for this signature in database
GPG key ID: 047D32DF25DC22EF
7 changed files with 273 additions and 288 deletions

View file

@ -24,7 +24,7 @@ fn main() {
let mut reactor = IrcReactor::new().unwrap();
for config in configs {
// Immediate errors like failure to resolve the client's name or to establish any connection will
// Immediate errors like failure to resolve the server's domain or to establish any connection will
// manifest here in the result of prepare_client_and_connect.
let client = reactor.prepare_client_and_connect(&config).unwrap();
client.identify().unwrap();

View file

@ -36,7 +36,7 @@ fn main() {
}).and_then(|()| reactor.run());
match res {
// The connections ended normally (for example, they sent a QUIT message to the client).
// The connections ended normally (for example, they sent a QUIT message to the server).
Ok(_) => break,
// Something went wrong! We'll print the error, and restart the connections.
Err(e) => eprintln!("{}", e),

View file

@ -31,7 +31,7 @@
//! # extern crate irc;
//! # use irc::client::prelude::*;
//! # fn main() {
//! # let server = IrcClient::new("config.toml").unwrap();
//! # let server = IrcClient::new("config.toml").unwrap();
//! server.send_cap_req(&[Capability::MultiPrefix, Capability::UserhostInNames]).unwrap();
//! server.identify().unwrap();
//! # }
@ -48,7 +48,7 @@ use proto::command::Command::*;
use proto::mode::ModeType;
use client::Client;
/// Idiomatic extensions for sending messages to an IRC server.
/// Idiomatic extensions for sending messages to an IRC server as a [`Client`](../trait.Client.html).
pub trait ClientExt: Client {
/// Sends a request for a list of server capabilities for a specific IRCv3 version.
fn send_cap_ls(&self, version: NegotiationVersion) -> Result<()>
@ -377,26 +377,22 @@ pub trait ClientExt: Client {
}
}
impl<S> ClientExt for S
where
S: Client,
{
}
impl<C> ClientExt for C where C: Client {}
#[cfg(test)]
mod test {
use super::ClientExt;
use client::data::Config;
use client::IrcClient;
use client::test::{get_server_value, test_config};
use client::test::{get_client_value, test_config};
use proto::{ChannelMode, Mode};
#[test]
fn identify() {
let server = IrcClient::from_config(test_config()).unwrap();
server.identify().unwrap();
let client = IrcClient::from_config(test_config()).unwrap();
client.identify().unwrap();
assert_eq!(
&get_server_value(server)[..],
&get_client_value(client)[..],
"CAP END\r\nNICK :test\r\n\
USER test 0 * :test\r\n"
);
@ -404,14 +400,14 @@ mod test {
#[test]
fn identify_with_password() {
let server = IrcClient::from_config(Config {
let client = IrcClient::from_config(Config {
nickname: Some(format!("test")),
password: Some(format!("password")),
..test_config()
}).unwrap();
server.identify().unwrap();
client.identify().unwrap();
assert_eq!(
&get_server_value(server)[..],
&get_client_value(client)[..],
"CAP END\r\nPASS :password\r\nNICK :test\r\n\
USER test 0 * :test\r\n"
);
@ -419,149 +415,149 @@ mod test {
#[test]
fn send_pong() {
let server = IrcClient::from_config(test_config()).unwrap();
server.send_pong("irc.test.net").unwrap();
assert_eq!(&get_server_value(server)[..], "PONG :irc.test.net\r\n");
let client = IrcClient::from_config(test_config()).unwrap();
client.send_pong("irc.test.net").unwrap();
assert_eq!(&get_client_value(client)[..], "PONG :irc.test.net\r\n");
}
#[test]
fn send_join() {
let server = IrcClient::from_config(test_config()).unwrap();
server.send_join("#test,#test2,#test3").unwrap();
let client = IrcClient::from_config(test_config()).unwrap();
client.send_join("#test,#test2,#test3").unwrap();
assert_eq!(
&get_server_value(server)[..],
&get_client_value(client)[..],
"JOIN #test,#test2,#test3\r\n"
);
}
#[test]
fn send_part() {
let server = IrcClient::from_config(test_config()).unwrap();
server.send_part("#test").unwrap();
assert_eq!(&get_server_value(server)[..], "PART #test\r\n");
let client = IrcClient::from_config(test_config()).unwrap();
client.send_part("#test").unwrap();
assert_eq!(&get_client_value(client)[..], "PART #test\r\n");
}
#[test]
fn send_oper() {
let server = IrcClient::from_config(test_config()).unwrap();
server.send_oper("test", "test").unwrap();
assert_eq!(&get_server_value(server)[..], "OPER test :test\r\n");
let client = IrcClient::from_config(test_config()).unwrap();
client.send_oper("test", "test").unwrap();
assert_eq!(&get_client_value(client)[..], "OPER test :test\r\n");
}
#[test]
fn send_privmsg() {
let server = IrcClient::from_config(test_config()).unwrap();
server.send_privmsg("#test", "Hi, everybody!").unwrap();
let client = IrcClient::from_config(test_config()).unwrap();
client.send_privmsg("#test", "Hi, everybody!").unwrap();
assert_eq!(
&get_server_value(server)[..],
&get_client_value(client)[..],
"PRIVMSG #test :Hi, everybody!\r\n"
);
}
#[test]
fn send_notice() {
let server = IrcClient::from_config(test_config()).unwrap();
server.send_notice("#test", "Hi, everybody!").unwrap();
let client = IrcClient::from_config(test_config()).unwrap();
client.send_notice("#test", "Hi, everybody!").unwrap();
assert_eq!(
&get_server_value(server)[..],
&get_client_value(client)[..],
"NOTICE #test :Hi, everybody!\r\n"
);
}
#[test]
fn send_topic_no_topic() {
let server = IrcClient::from_config(test_config()).unwrap();
server.send_topic("#test", "").unwrap();
assert_eq!(&get_server_value(server)[..], "TOPIC #test\r\n");
let client = IrcClient::from_config(test_config()).unwrap();
client.send_topic("#test", "").unwrap();
assert_eq!(&get_client_value(client)[..], "TOPIC #test\r\n");
}
#[test]
fn send_topic() {
let server = IrcClient::from_config(test_config()).unwrap();
server.send_topic("#test", "Testing stuff.").unwrap();
let client = IrcClient::from_config(test_config()).unwrap();
client.send_topic("#test", "Testing stuff.").unwrap();
assert_eq!(
&get_server_value(server)[..],
&get_client_value(client)[..],
"TOPIC #test :Testing stuff.\r\n"
);
}
#[test]
fn send_kill() {
let server = IrcClient::from_config(test_config()).unwrap();
server.send_kill("test", "Testing kills.").unwrap();
let client = IrcClient::from_config(test_config()).unwrap();
client.send_kill("test", "Testing kills.").unwrap();
assert_eq!(
&get_server_value(server)[..],
&get_client_value(client)[..],
"KILL test :Testing kills.\r\n"
);
}
#[test]
fn send_kick_no_message() {
let server = IrcClient::from_config(test_config()).unwrap();
server.send_kick("#test", "test", "").unwrap();
assert_eq!(&get_server_value(server)[..], "KICK #test test\r\n");
let client = IrcClient::from_config(test_config()).unwrap();
client.send_kick("#test", "test", "").unwrap();
assert_eq!(&get_client_value(client)[..], "KICK #test test\r\n");
}
#[test]
fn send_kick() {
let server = IrcClient::from_config(test_config()).unwrap();
server.send_kick("#test", "test", "Testing kicks.").unwrap();
let client = IrcClient::from_config(test_config()).unwrap();
client.send_kick("#test", "test", "Testing kicks.").unwrap();
assert_eq!(
&get_server_value(server)[..],
&get_client_value(client)[..],
"KICK #test test :Testing kicks.\r\n"
);
}
#[test]
fn send_mode_no_modeparams() {
let server = IrcClient::from_config(test_config()).unwrap();
server.send_mode("#test", &[Mode::Plus(ChannelMode::InviteOnly, None)]).unwrap();
assert_eq!(&get_server_value(server)[..], "MODE #test +i\r\n");
let client = IrcClient::from_config(test_config()).unwrap();
client.send_mode("#test", &[Mode::Plus(ChannelMode::InviteOnly, None)]).unwrap();
assert_eq!(&get_client_value(client)[..], "MODE #test +i\r\n");
}
#[test]
fn send_mode() {
let server = IrcClient::from_config(test_config()).unwrap();
server.send_mode("#test", &[Mode::Plus(ChannelMode::Oper, Some("test".to_owned()))])
let client = IrcClient::from_config(test_config()).unwrap();
client.send_mode("#test", &[Mode::Plus(ChannelMode::Oper, Some("test".to_owned()))])
.unwrap();
assert_eq!(&get_server_value(server)[..], "MODE #test +o test\r\n");
assert_eq!(&get_client_value(client)[..], "MODE #test +o test\r\n");
}
#[test]
fn send_samode_no_modeparams() {
let server = IrcClient::from_config(test_config()).unwrap();
server.send_samode("#test", "+i", "").unwrap();
assert_eq!(&get_server_value(server)[..], "SAMODE #test +i\r\n");
let client = IrcClient::from_config(test_config()).unwrap();
client.send_samode("#test", "+i", "").unwrap();
assert_eq!(&get_client_value(client)[..], "SAMODE #test +i\r\n");
}
#[test]
fn send_samode() {
let server = IrcClient::from_config(test_config()).unwrap();
server.send_samode("#test", "+o", "test").unwrap();
assert_eq!(&get_server_value(server)[..], "SAMODE #test +o test\r\n");
let client = IrcClient::from_config(test_config()).unwrap();
client.send_samode("#test", "+o", "test").unwrap();
assert_eq!(&get_client_value(client)[..], "SAMODE #test +o test\r\n");
}
#[test]
fn send_sanick() {
let server = IrcClient::from_config(test_config()).unwrap();
server.send_sanick("test", "test2").unwrap();
assert_eq!(&get_server_value(server)[..], "SANICK test test2\r\n");
let client = IrcClient::from_config(test_config()).unwrap();
client.send_sanick("test", "test2").unwrap();
assert_eq!(&get_client_value(client)[..], "SANICK test test2\r\n");
}
#[test]
fn send_invite() {
let server = IrcClient::from_config(test_config()).unwrap();
server.send_invite("test", "#test").unwrap();
assert_eq!(&get_server_value(server)[..], "INVITE test #test\r\n");
let client = IrcClient::from_config(test_config()).unwrap();
client.send_invite("test", "#test").unwrap();
assert_eq!(&get_client_value(client)[..], "INVITE test #test\r\n");
}
#[test]
#[cfg(feature = "ctcp")]
fn send_ctcp() {
let server = IrcClient::from_config(test_config()).unwrap();
server.send_ctcp("test", "MESSAGE").unwrap();
let client = IrcClient::from_config(test_config()).unwrap();
client.send_ctcp("test", "MESSAGE").unwrap();
assert_eq!(
&get_server_value(server)[..],
&get_client_value(client)[..],
"PRIVMSG test :\u{001}MESSAGE\u{001}\r\n"
);
}
@ -569,10 +565,10 @@ mod test {
#[test]
#[cfg(feature = "ctcp")]
fn send_action() {
let server = IrcClient::from_config(test_config()).unwrap();
server.send_action("test", "tests.").unwrap();
let client = IrcClient::from_config(test_config()).unwrap();
client.send_action("test", "tests.").unwrap();
assert_eq!(
&get_server_value(server)[..],
&get_client_value(client)[..],
"PRIVMSG test :\u{001}ACTION tests.\u{001}\r\n"
);
}
@ -580,10 +576,10 @@ mod test {
#[test]
#[cfg(feature = "ctcp")]
fn send_finger() {
let server = IrcClient::from_config(test_config()).unwrap();
server.send_finger("test").unwrap();
let client = IrcClient::from_config(test_config()).unwrap();
client.send_finger("test").unwrap();
assert_eq!(
&get_server_value(server)[..],
&get_client_value(client)[..],
"PRIVMSG test :\u{001}FINGER\u{001}\r\n"
);
}
@ -591,10 +587,10 @@ mod test {
#[test]
#[cfg(feature = "ctcp")]
fn send_version() {
let server = IrcClient::from_config(test_config()).unwrap();
server.send_version("test").unwrap();
let client = IrcClient::from_config(test_config()).unwrap();
client.send_version("test").unwrap();
assert_eq!(
&get_server_value(server)[..],
&get_client_value(client)[..],
"PRIVMSG test :\u{001}VERSION\u{001}\r\n"
);
}
@ -602,10 +598,10 @@ mod test {
#[test]
#[cfg(feature = "ctcp")]
fn send_source() {
let server = IrcClient::from_config(test_config()).unwrap();
server.send_source("test").unwrap();
let client = IrcClient::from_config(test_config()).unwrap();
client.send_source("test").unwrap();
assert_eq!(
&get_server_value(server)[..],
&get_client_value(client)[..],
"PRIVMSG test :\u{001}SOURCE\u{001}\r\n"
);
}
@ -613,10 +609,10 @@ mod test {
#[test]
#[cfg(feature = "ctcp")]
fn send_user_info() {
let server = IrcClient::from_config(test_config()).unwrap();
server.send_user_info("test").unwrap();
let client = IrcClient::from_config(test_config()).unwrap();
client.send_user_info("test").unwrap();
assert_eq!(
&get_server_value(server)[..],
&get_client_value(client)[..],
"PRIVMSG test :\u{001}USERINFO\u{001}\r\n"
);
}
@ -624,9 +620,9 @@ mod test {
#[test]
#[cfg(feature = "ctcp")]
fn send_ctcp_ping() {
let server = IrcClient::from_config(test_config()).unwrap();
server.send_ctcp_ping("test").unwrap();
let val = get_server_value(server);
let client = IrcClient::from_config(test_config()).unwrap();
client.send_ctcp_ping("test").unwrap();
let val = get_client_value(client);
println!("{}", val);
assert!(val.starts_with("PRIVMSG test :\u{001}PING "));
assert!(val.ends_with("\u{001}\r\n"));
@ -635,10 +631,10 @@ mod test {
#[test]
#[cfg(feature = "ctcp")]
fn send_time() {
let server = IrcClient::from_config(test_config()).unwrap();
server.send_time("test").unwrap();
let client = IrcClient::from_config(test_config()).unwrap();
client.send_time("test").unwrap();
assert_eq!(
&get_server_value(server)[..],
&get_client_value(client)[..],
"PRIVMSG test :\u{001}TIME\u{001}\r\n"
);
}

View file

@ -2,10 +2,10 @@
//!
//! This API provides the ability to connect to an IRC server via the
//! [`IrcClient`](struct.IrcClient.html) type. The [`Client`](trait.Client.html) trait that
//! [`IrcClient`](struct.IrcClient.html) implements provides methods for communicating with this
//! server. An extension trait, [`ClientExt`](./utils/trait.ClientExt.html), provides short-hand for
//! [`IrcClient`](struct.IrcClient.html) implements provides methods for communicating with the
//! server. An extension trait, [`ClientExt`](./ext/trait.ClientExt.html), provides short-hand for
//! sending a variety of important messages without referring to their entries in
//! [`proto::command`](../../proto/command/enum.Command.html).
//! [`proto::command`](../proto/command/enum.Command.html).
//!
//! # Examples
//!
@ -17,13 +17,13 @@
//! use irc::client::prelude::{IrcClient, ClientExt};
//!
//! # fn main() {
//! let server = IrcClient::new("config.toml").unwrap();
//! let client = IrcClient::new("config.toml").unwrap();
//! // identify comes from `ClientExt`
//! server.identify().unwrap();
//! client.identify().unwrap();
//! # }
//! ```
//!
//! We can then use functions from [Client](trait.Client.html) to receive messages from the
//! We can then use functions from [`Client`](trait.Client.html) to receive messages from the
//! server in a blocking fashion and perform any desired actions in response. The following code
//! performs a simple call-and-response when the bot's name is mentioned in a channel.
//!
@ -33,15 +33,14 @@
//! use irc::client::prelude::{Client, Command};
//!
//! # fn main() {
//! # let server = IrcClient::new("config.toml").unwrap();
//! # server.identify().unwrap();
//! server.for_each_incoming(|irc_msg| {
//! match irc_msg.command {
//! Command::PRIVMSG(channel, message) => if message.contains(server.current_nickname()) {
//! server.send_privmsg(&channel, "beep boop").unwrap();
//! # let client = IrcClient::new("config.toml").unwrap();
//! # client.identify().unwrap();
//! client.for_each_incoming(|irc_msg| {
//! if let Command::PRIVMSG(channel, message) = irc_msg.command {
//! if message.contains(client.current_nickname()) {
//! client.send_privmsg(&channel, "beep boop").unwrap();
//! }
//! }
//! _ => ()
//! }
//! }).unwrap();
//! # }
//! ```
@ -91,12 +90,12 @@ pub mod transport;
/// use irc::client::prelude::EachIncomingExt;
///
/// # fn main() {
/// # let server = IrcClient::new("config.toml").unwrap();
/// # server.identify().unwrap();
/// server.stream().for_each_incoming(|irc_msg| {
/// # let client = IrcClient::new("config.toml").unwrap();
/// # client.identify().unwrap();
/// client.stream().for_each_incoming(|irc_msg| {
/// match irc_msg.command {
/// Command::PRIVMSG(channel, message) => if message.contains(server.current_nickname()) {
/// server.send_privmsg(&channel, "beep boop").unwrap();
/// Command::PRIVMSG(channel, message) => if message.contains(client.current_nickname()) {
/// client.send_privmsg(&channel, "beep boop").unwrap();
/// }
/// _ => ()
/// }
@ -106,10 +105,7 @@ pub mod transport;
pub trait EachIncomingExt: Stream<Item=Message, Error=error::IrcError> {
/// Blocks on the stream, running the given function on each incoming message as they arrive.
fn for_each_incoming<F>(self, mut f: F) -> error::Result<()>
where
F: FnMut(Message) -> (),
Self: Sized,
{
where F: FnMut(Message) -> (), Self: Sized {
self.for_each(|msg| {
f(msg);
Ok(())
@ -121,35 +117,35 @@ impl<T> EachIncomingExt for T where T: Stream<Item=Message, Error=error::IrcErro
/// An interface for communicating with an IRC server.
pub trait Client {
/// Gets the configuration being used with this Client.
/// Gets the configuration being used with this `Client`.
fn config(&self) -> &Config;
/// Sends a [Command](../../proto/command/enum.Command.html) to this Client. This is the core
/// primitive for sending messages to the server. In practice, it's often more pleasant (and
/// more idiomatic) to use the functions defined on [ClientExt](./utils/trait.ClientExt.html).
/// They capture a lot of the more repetitive aspects of sending messages.
/// Sends a [`Command`](../proto/command/enum.Command.html) as this `Client`. This is the
/// core primitive for sending messages to the server. In practice, it's often more pleasant
/// (and more idiomatic) to use the functions defined on
/// [`ClientExt`](./ext/trait.ClientExt.html). They capture a lot of the more repetitive
/// aspects of sending messages.
///
/// # Example
/// ```no_run
/// # extern crate irc;
/// # use irc::client::prelude::*;
/// # fn main() {
/// # let server = IrcClient::new("config.toml").unwrap();
/// server.send(Command::NICK("example".to_owned())).unwrap();
/// server.send(Command::USER("user".to_owned(), "0".to_owned(), "name".to_owned())).unwrap();
/// # let client = IrcClient::new("config.toml").unwrap();
/// client.send(Command::NICK("example".to_owned())).unwrap();
/// client.send(Command::USER("user".to_owned(), "0".to_owned(), "name".to_owned())).unwrap();
/// # }
/// ```
fn send<M: Into<Message>>(&self, message: M) -> error::Result<()>
where
Self: Sized;
fn send<M: Into<Message>>(&self, message: M) -> error::Result<()> where Self: Sized;
/// Gets a stream of incoming messages from the Client. This is only necessary when trying to
/// set up more complex clients, and requires use of the `futures` crate. Most IRC bots should
/// be able to get by using only `for_each_incoming` to handle received messages. You can find
/// some examples of more complex setups using `stream` in the
/// [GitHub repository](https://github.com/aatxe/irc/tree/master/examples).
/// Gets a stream of incoming messages from the `Client`'s connection. This is only necessary
/// when trying to set up more complex clients, and requires use of the `futures` crate. Most
/// IRC bots should be able to get by using only `for_each_incoming` to handle received
/// messages. You can find some examples of more complex setups using `stream` in the
/// [GitHub repository](https://github.com/aatxe/irc/tree/stable/examples).
///
/// **Note**: The stream can only be returned once. Subsequent attempts will cause a panic.
// FIXME: when impl traits stabilize, we should change this return type.
fn stream(&self) -> ClientStream;
/// Blocks on the stream, running the given function on each incoming message as they arrive.
@ -159,22 +155,18 @@ pub trait Client {
/// # extern crate irc;
/// # use irc::client::prelude::{IrcClient, ClientExt, Client, Command};
/// # fn main() {
/// # let server = IrcClient::new("config.toml").unwrap();
/// # server.identify().unwrap();
/// server.for_each_incoming(|irc_msg| {
/// match irc_msg.command {
/// Command::PRIVMSG(channel, message) => if message.contains(server.current_nickname()) {
/// server.send_privmsg(&channel, "beep boop").unwrap();
/// # let client = IrcClient::new("config.toml").unwrap();
/// # client.identify().unwrap();
/// client.for_each_incoming(|irc_msg| {
/// if let Command::PRIVMSG(channel, message) = irc_msg.command {
/// if message.contains(client.current_nickname()) {
/// client.send_privmsg(&channel, "beep boop").unwrap();
/// }
/// }
/// _ => ()
/// }
/// }).unwrap();
/// # }
/// ```
fn for_each_incoming<F>(&self, f: F) -> error::Result<()>
where
F: FnMut(Message) -> (),
{
fn for_each_incoming<F>(&self, f: F) -> error::Result<()> where F: FnMut(Message) -> () {
self.stream().for_each_incoming(f)
}
@ -182,7 +174,7 @@ pub trait Client {
/// altogether via the `nochanlists` feature.
fn list_channels(&self) -> Option<Vec<String>>;
/// Gets a list of [Users](../data/user/struct.User.html) in the specified channel. If the
/// Gets a list of [`Users`](./data/user/struct.User.html) in the specified channel. If the
/// specified channel hasn't been joined or the `nochanlists` feature is enabled, this function
/// will return `None`.
///
@ -195,20 +187,20 @@ pub trait Client {
/// use irc::proto::caps::Capability;
///
/// # fn main() {
/// # let server = IrcClient::new("config.toml").unwrap();
/// server.send_cap_req(&[Capability::MultiPrefix]).unwrap();
/// server.identify().unwrap();
/// # let client = IrcClient::new("config.toml").unwrap();
/// client.send_cap_req(&[Capability::MultiPrefix]).unwrap();
/// client.identify().unwrap();
/// # }
/// ```
fn list_users(&self, channel: &str) -> Option<Vec<User>>;
}
/// A stream of `Messages` from the `IrcClient`.
/// A stream of `Messages` received from an IRC server via an `IrcClient`.
///
/// Interaction with this stream relies on the `futures` API, but is only expected for less
/// traditional use cases. To learn more, you can view the documentation for the
/// [futures](https://docs.rs/futures/) crate, or the tutorials for
/// [tokio](https://tokio.rs/docs/getting-started/futures/).
/// [`futures`](https://docs.rs/futures/) crate, or the tutorials for
/// [`tokio`](https://tokio.rs/docs/getting-started/futures/).
#[derive(Debug)]
pub struct ClientStream {
state: Arc<ClientState>,
@ -250,10 +242,7 @@ impl<'a> Client for ClientState {
&self.config
}
fn send<M: Into<Message>>(&self, msg: M) -> error::Result<()>
where
Self: Sized,
{
fn send<M: Into<Message>>(&self, msg: M) -> error::Result<()> where Self: Sized {
let msg = &msg.into();
self.handle_sent_message(msg)?;
Ok((&self.outgoing).unbounded_send(
@ -608,13 +597,13 @@ impl ClientState {
/// The canonical implementation of a connection to an IRC server.
///
/// The type itself provides a number of methods to create new connections, but most of the API
/// surface is in the form of the [Client](trait.Client.html) and
/// [`ClientExt`](./utils/trait.ClientExt.html) traits that provide methods of communicating with
/// surface is in the form of the [`Client`](trait.Client.html) and
/// [`ClientExt`](./ext/trait.ClientExt.html) traits that provide methods of communicating with
/// the server after connection. Cloning an `IrcClient` is relatively cheap, as it's equivalent to
/// cloning a single `Arc`. This may be useful for setting up multiple threads with access to one
/// connection.
///
/// For a full example usage, see [`irc::client::server`](./index.html).
/// For a full example usage, see [`irc::client`](./index.html).
#[derive(Clone, Debug)]
pub struct IrcClient {
/// The internal, thread-safe server state.
@ -679,7 +668,7 @@ impl Client for IrcClient {
}
impl IrcClient {
/// Creates a new IRC Client connection from the configuration at the specified path, connecting
/// Creates a new `IrcClient` from the configuration at the specified path, connecting
/// immediately. This function is short-hand for loading the configuration and then calling
/// `IrcClient::from_config` and consequently inherits its behaviors.
///
@ -688,19 +677,19 @@ impl IrcClient {
/// # extern crate irc;
/// # use irc::client::prelude::*;
/// # fn main() {
/// let server = IrcClient::new("config.toml").unwrap();
/// let client = IrcClient::new("config.toml").unwrap();
/// # }
/// ```
pub fn new<P: AsRef<Path>>(config: P) -> error::Result<IrcClient> {
IrcClient::from_config(Config::load(config)?)
}
/// Creates a new IRC server connection from the specified configuration, connecting
/// immediately. Due to current design limitations, error handling here is somewhat limited. In
/// particular, failed connections will cause the program to panic because the connection
/// attempt is made on a freshly created thread. If you need to avoid this behavior and handle
/// errors more gracefully, it is recommended that you use an
/// [IrcReactor](../reactor/struct.IrcReactor.html) instead.
/// Creates a new `IrcClient` from the specified configuration, connecting immediately. Due to
/// current design limitations, error handling here is somewhat limited. In particular, failed
/// connections will cause the program to panic because the connection attempt is made on a
/// freshly created thread. If you need to avoid this behavior and handle errors more
/// gracefully, it is recommended that you use an
/// [`IrcReactor`](./reactor/struct.IrcReactor.html) instead.
///
/// # Example
/// ```no_run
@ -713,7 +702,7 @@ impl IrcClient {
/// server: Some("irc.example.com".to_owned()),
/// .. Default::default()
/// };
/// let server = IrcClient::from_config(config).unwrap();
/// let client = IrcClient::from_config(config).unwrap();
/// # }
/// ```
pub fn from_config(config: Config) -> error::Result<IrcClient> {
@ -751,17 +740,17 @@ impl IrcClient {
})
}
/// Creates a new IRC server connection from the specified configuration and on the event loop
/// corresponding to the given handle. This can be used to set up a number of IrcClients on a
/// Creates a `Future` of an `IrcClient` from the specified configuration and on the event loop
/// corresponding to the given handle. This can be used to set up a number of `IrcClients` on a
/// single, shared event loop. It can also be used to take more control over execution and error
/// handling. Connection will not occur until the event loop is run.
///
/// Proper usage requires familiarity with `tokio` and `futures`. You can find more information
/// in the crate documentation for [tokio-core](http://docs.rs/tokio-core) or
/// [futures](http://docs.rs/futures). Additionally, you can find detailed tutorials on using
/// in the crate documentation for [`tokio-core`](http://docs.rs/tokio-core) or
/// [`futures`](http://docs.rs/futures). Additionally, you can find detailed tutorials on using
/// both libraries on the [tokio website](https://tokio.rs/docs/getting-started/tokio/). An easy
/// to use abstraction that does not require this knowledge is available via
/// [`IrcReactors`](../reactor/struct.IrcReactor.html).
/// [`IrcReactors`](./reactor/struct.IrcReactor.html).
///
/// # Example
/// ```no_run
@ -781,11 +770,11 @@ impl IrcClient {
/// let mut reactor = Core::new().unwrap();
/// let future = IrcClient::new_future(reactor.handle(), &config).unwrap();
/// // immediate connection errors (like no internet) will turn up here...
/// let PackedIrcClient(server, future) = reactor.run(future).unwrap();
/// let PackedIrcClient(client, future) = reactor.run(future).unwrap();
/// // runtime errors (like disconnections and so forth) will turn up here...
/// reactor.run(server.stream().for_each(move |irc_msg| {
/// reactor.run(client.stream().for_each(move |irc_msg| {
/// // processing messages works like usual
/// process_msg(&server, irc_msg)
/// process_msg(&client, irc_msg)
/// }).join(future)).unwrap();
/// # }
/// # fn process_msg(server: &IrcClient, message: Message) -> error::Result<()> { Ok(()) }
@ -820,10 +809,10 @@ impl IrcClient {
///
/// Interaction with this future relies on the `futures` API, but is only expected for more advanced
/// use cases. To learn more, you can view the documentation for the
/// [futures](https://docs.rs/futures/) crate, or the tutorials for
/// [tokio](https://tokio.rs/docs/getting-started/futures/). An easy to use abstraction that does
/// not require this knowledge is available via [`IrcReactors`](../reactor/struct.IrcReactor.html).
#[derive(Debug)]
/// [`futures`](https://docs.rs/futures/) crate, or the tutorials for
/// [`tokio`](https://tokio.rs/docs/getting-started/futures/). An easy to use abstraction that does
/// not require this knowledge is available via [`IrcReactors`](./reactor/struct.IrcReactor.html).
#[derive(Debug)]
pub struct IrcClientFuture<'a> {
conn: ConnectionFuture<'a>,
_handle: Handle,
@ -858,12 +847,12 @@ impl<'a> Future for IrcClientFuture<'a> {
}
}
/// An `IrcClient` packaged with a future that drives its message sending. In order for the server
/// An `IrcClient` packaged with a future that drives its message sending. In order for the client
/// to actually work properly, this future _must_ be running.
///
/// This type should only be used by advanced users who are familiar with the implementation of this
/// crate. An easy to use abstraction that does not require this knowledge is available via
/// [`IrcReactors`](../reactor/struct.IrcReactor.html).
/// [`IrcReactors`](./reactor/struct.IrcReactor.html).
pub struct PackedIrcClient(pub IrcClient, pub Box<Future<Item = (), Error = error::IrcError>>);
#[cfg(test)]
@ -893,11 +882,11 @@ mod test {
}
}
pub fn get_server_value(server: IrcClient) -> String {
pub fn get_client_value(client: IrcClient) -> String {
// 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| {
client.log_view().sent().unwrap().iter().fold(String::new(), |mut acc, msg| {
acc.push_str(&msg.to_string());
acc
})
@ -907,12 +896,12 @@ mod test {
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 = IrcClient::from_config(Config {
let client = IrcClient::from_config(Config {
mock_initial_value: Some(exp.to_owned()),
..test_config()
}).unwrap();
let mut messages = String::new();
server.for_each_incoming(|message| {
client.for_each_incoming(|message| {
messages.push_str(&message.to_string());
}).unwrap();
assert_eq!(&messages[..], exp);
@ -921,15 +910,15 @@ mod test {
#[test]
fn handle_message() {
let value = ":irc.test.net 376 test :End of /MOTD command.\r\n";
let server = IrcClient::from_config(Config {
let client = IrcClient::from_config(Config {
mock_initial_value: Some(value.to_owned()),
..test_config()
}).unwrap();
server.for_each_incoming(|message| {
client.for_each_incoming(|message| {
println!("{:?}", message);
}).unwrap();
assert_eq!(
&get_server_value(server)[..],
&get_client_value(client)[..],
"JOIN #test\r\nJOIN #test2\r\n"
);
}
@ -937,17 +926,17 @@ mod test {
#[test]
fn handle_end_motd_with_nick_password() {
let value = ":irc.test.net 376 test :End of /MOTD command.\r\n";
let server = IrcClient::from_config(Config {
let client = IrcClient::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.for_each_incoming(|message| {
client.for_each_incoming(|message| {
println!("{:?}", message);
}).unwrap();
assert_eq!(
&get_server_value(server)[..],
&get_client_value(client)[..],
"NICKSERV IDENTIFY password\r\nJOIN #test\r\n\
JOIN #test2\r\n"
);
@ -956,7 +945,7 @@ 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 = IrcClient::from_config(Config {
let client = IrcClient::from_config(Config {
mock_initial_value: Some(value.to_owned()),
nickname: Some(format!("test")),
channels: Some(vec![format!("#test"), format!("#test2")]),
@ -967,11 +956,11 @@ mod test {
},
..test_config()
}).unwrap();
server.for_each_incoming(|message| {
client.for_each_incoming(|message| {
println!("{:?}", message);
}).unwrap();
assert_eq!(
&get_server_value(server)[..],
&get_client_value(client)[..],
"JOIN #test\r\nJOIN #test2 password\r\n"
);
}
@ -980,7 +969,7 @@ 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 = IrcClient::from_config(Config {
let client = IrcClient::from_config(Config {
mock_initial_value: Some(value.to_owned()),
nickname: Some(format!("test")),
alt_nicks: Some(vec![format!("test2")]),
@ -989,11 +978,11 @@ mod test {
should_ghost: Some(true),
..test_config()
}).unwrap();
server.for_each_incoming(|message| {
client.for_each_incoming(|message| {
println!("{:?}", message);
}).unwrap();
assert_eq!(
&get_server_value(server)[..],
&get_client_value(client)[..],
"NICK :test2\r\nNICKSERV GHOST test password\r\n\
NICK :test\r\nNICKSERV IDENTIFY password\r\nJOIN #test\r\nJOIN #test2\r\n"
);
@ -1003,7 +992,7 @@ 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 = IrcClient::from_config(Config {
let client = IrcClient::from_config(Config {
mock_initial_value: Some(value.to_owned()),
nickname: Some(format!("test")),
alt_nicks: Some(vec![format!("test2")]),
@ -1013,11 +1002,11 @@ mod test {
ghost_sequence: Some(vec![format!("RECOVER"), format!("RELEASE")]),
..test_config()
}).unwrap();
server.for_each_incoming(|message| {
client.for_each_incoming(|message| {
println!("{:?}", message);
}).unwrap();
assert_eq!(
&get_server_value(server)[..],
&get_client_value(client)[..],
"NICK :test2\r\nNICKSERV RECOVER test password\
\r\nNICKSERV RELEASE test password\r\nNICK :test\r\nNICKSERV IDENTIFY password\
\r\nJOIN #test\r\nJOIN #test2\r\n"
@ -1027,18 +1016,18 @@ mod test {
#[test]
fn handle_end_motd_with_umodes() {
let value = ":irc.test.net 376 test :End of /MOTD command.\r\n";
let server = IrcClient::from_config(Config {
let client = IrcClient::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.for_each_incoming(|message| {
client.for_each_incoming(|message| {
println!("{:?}", message);
}).unwrap();
assert_eq!(
&get_server_value(server)[..],
&get_client_value(client)[..],
"MODE test +B\r\nJOIN #test\r\nJOIN #test2\r\n"
);
}
@ -1046,14 +1035,14 @@ mod test {
#[test]
fn nickname_in_use() {
let value = ":irc.pdgn.co 433 * test :Nickname is already in use.\r\n";
let server = IrcClient::from_config(Config {
let client = IrcClient::from_config(Config {
mock_initial_value: Some(value.to_owned()),
..test_config()
}).unwrap();
server.for_each_incoming(|message| {
client.for_each_incoming(|message| {
println!("{:?}", message);
}).unwrap();
assert_eq!(&get_server_value(server)[..], "NICK :test2\r\n");
assert_eq!(&get_client_value(client)[..], "NICK :test2\r\n");
}
#[test]
@ -1061,82 +1050,82 @@ 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 = IrcClient::from_config(Config {
let client = IrcClient::from_config(Config {
mock_initial_value: Some(value.to_owned()),
..test_config()
}).unwrap();
server.for_each_incoming(|message| {
client.for_each_incoming(|message| {
println!("{:?}", message);
}).unwrap();
}
#[test]
fn send() {
let server = IrcClient::from_config(test_config()).unwrap();
let client = IrcClient::from_config(test_config()).unwrap();
assert!(
server
client
.send(PRIVMSG(format!("#test"), format!("Hi there!")))
.is_ok()
);
assert_eq!(
&get_server_value(server)[..],
&get_client_value(client)[..],
"PRIVMSG #test :Hi there!\r\n"
);
}
#[test]
fn send_no_newline_injection() {
let server = IrcClient::from_config(test_config()).unwrap();
let client = IrcClient::from_config(test_config()).unwrap();
assert!(
server
client
.send(PRIVMSG(format!("#test"), format!("Hi there!\r\nJOIN #bad")))
.is_ok()
);
assert_eq!(&get_server_value(server)[..], "PRIVMSG #test :Hi there!\r\n");
assert_eq!(&get_client_value(client)[..], "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 = IrcClient::from_config(Config {
let client = IrcClient::from_config(Config {
mock_initial_value: Some(value.to_owned()),
..test_config()
}).unwrap();
server.for_each_incoming(|message| {
client.for_each_incoming(|message| {
println!("{:?}", message);
}).unwrap();
assert_eq!(server.list_channels().unwrap(), vec!["#test".to_owned()])
assert_eq!(client.list_channels().unwrap(), vec!["#test".to_owned()])
}
#[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 = IrcClient::from_config(Config {
let client = IrcClient::from_config(Config {
mock_initial_value: Some(value.to_owned()),
..test_config()
}).unwrap();
server.for_each_incoming(|message| {
client.for_each_incoming(|message| {
println!("{:?}", message);
}).unwrap();
assert!(server.send(PART(format!("#test"), None)).is_ok());
assert!(server.list_channels().unwrap().is_empty())
assert!(client.send(PART(format!("#test"), None)).is_ok());
assert!(client.list_channels().unwrap().is_empty())
}
#[test]
#[cfg(not(feature = "nochanlists"))]
fn user_tracking_names() {
let value = ":irc.test.net 353 test = #test :test ~owner &admin\r\n";
let server = IrcClient::from_config(Config {
let client = IrcClient::from_config(Config {
mock_initial_value: Some(value.to_owned()),
..test_config()
}).unwrap();
server.for_each_incoming(|message| {
client.for_each_incoming(|message| {
println!("{:?}", message);
}).unwrap();
assert_eq!(
server.list_users("#test").unwrap(),
client.list_users("#test").unwrap(),
vec![User::new("test"), User::new("~owner"), User::new("&admin")]
)
}
@ -1146,15 +1135,15 @@ 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 = IrcClient::from_config(Config {
let client = IrcClient::from_config(Config {
mock_initial_value: Some(value.to_owned()),
..test_config()
}).unwrap();
server.for_each_incoming(|message| {
client.for_each_incoming(|message| {
println!("{:?}", message);
}).unwrap();
assert_eq!(
server.list_users("#test").unwrap(),
client.list_users("#test").unwrap(),
vec![
User::new("test"),
User::new("~owner"),
@ -1169,15 +1158,15 @@ 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 = IrcClient::from_config(Config {
let client = IrcClient::from_config(Config {
mock_initial_value: Some(value.to_owned()),
..test_config()
}).unwrap();
server.for_each_incoming(|message| {
client.for_each_incoming(|message| {
println!("{:?}", message);
}).unwrap();
assert_eq!(
server.list_users("#test").unwrap(),
client.list_users("#test").unwrap(),
vec![User::new("test"), User::new("&admin")]
)
}
@ -1187,26 +1176,26 @@ 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 = IrcClient::from_config(Config {
let client = IrcClient::from_config(Config {
mock_initial_value: Some(value.to_owned()),
..test_config()
}).unwrap();
server.for_each_incoming(|message| {
client.for_each_incoming(|message| {
println!("{:?}", message);
}).unwrap();
assert_eq!(
server.list_users("#test").unwrap(),
client.list_users("#test").unwrap(),
vec![User::new("@test"), User::new("~owner"), User::new("&admin")]
);
let mut exp = User::new("@test");
exp.update_access_level(&Mode::Plus(ChannelMode::Voice, None));
assert_eq!(
server.list_users("#test").unwrap()[0].highest_access_level(),
client.list_users("#test").unwrap()[0].highest_access_level(),
exp.highest_access_level()
);
// The following tests if the maintained user contains the same entries as what is expected
// but ignores the ordering of these entries.
let mut levels = server.list_users("#test").unwrap()[0].access_levels();
let mut levels = client.list_users("#test").unwrap()[0].access_levels();
levels.retain(|l| exp.access_levels().contains(l));
assert_eq!(levels.len(), exp.access_levels().len());
}
@ -1215,29 +1204,29 @@ mod test {
#[cfg(feature = "nochanlists")]
fn no_user_tracking() {
let value = ":irc.test.net 353 test = #test :test ~owner &admin";
let server = IrcClient::from_config(Config {
let client = IrcClient::from_config(Config {
mock_initial_value: Some(value.to_owned()),
..test_config()
}).unwrap();
server.for_each_incoming(|message| {
client.for_each_incoming(|message| {
println!("{:?}", message);
}).unwrap();
assert!(server.list_users("#test").is_none())
assert!(client.list_users("#test").is_none())
}
#[test]
#[cfg(feature = "ctcp")]
fn finger_response() {
let value = ":test!test@test PRIVMSG test :\u{001}FINGER\u{001}\r\n";
let server = IrcClient::from_config(Config {
let client = IrcClient::from_config(Config {
mock_initial_value: Some(value.to_owned()),
..test_config()
}).unwrap();
server.for_each_incoming(|message| {
client.for_each_incoming(|message| {
println!("{:?}", message);
}).unwrap();
assert_eq!(
&get_server_value(server)[..],
&get_client_value(client)[..],
"NOTICE test :\u{001}FINGER :test (test)\u{001}\r\n"
);
}
@ -1246,15 +1235,15 @@ mod test {
#[cfg(feature = "ctcp")]
fn version_response() {
let value = ":test!test@test PRIVMSG test :\u{001}VERSION\u{001}\r\n";
let server = IrcClient::from_config(Config {
let client = IrcClient::from_config(Config {
mock_initial_value: Some(value.to_owned()),
..test_config()
}).unwrap();
server.for_each_incoming(|message| {
client.for_each_incoming(|message| {
println!("{:?}", message);
}).unwrap();
assert_eq!(
&get_server_value(server)[..],
&get_client_value(client)[..],
&format!(
"NOTICE test :\u{001}VERSION {}\u{001}\r\n",
::VERSION_STR,
@ -1266,15 +1255,15 @@ mod test {
#[cfg(feature = "ctcp")]
fn source_response() {
let value = ":test!test@test PRIVMSG test :\u{001}SOURCE\u{001}\r\n";
let server = IrcClient::from_config(Config {
let client = IrcClient::from_config(Config {
mock_initial_value: Some(value.to_owned()),
..test_config()
}).unwrap();
server.for_each_incoming(|message| {
client.for_each_incoming(|message| {
println!("{:?}", message);
}).unwrap();
assert_eq!(
&get_server_value(server)[..],
&get_client_value(client)[..],
"NOTICE test :\u{001}SOURCE https://github.com/aatxe/irc\u{001}\r\n\
NOTICE test :\u{001}SOURCE\u{001}\r\n"
);
@ -1284,15 +1273,15 @@ 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 = IrcClient::from_config(Config {
let client = IrcClient::from_config(Config {
mock_initial_value: Some(value.to_owned()),
..test_config()
}).unwrap();
server.for_each_incoming(|message| {
client.for_each_incoming(|message| {
println!("{:?}", message);
}).unwrap();
assert_eq!(
&get_server_value(server)[..],
&get_client_value(client)[..],
"NOTICE test :\u{001}PING test\u{001}\r\n"
);
}
@ -1301,14 +1290,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 = IrcClient::from_config(Config {
let client = IrcClient::from_config(Config {
mock_initial_value: Some(value.to_owned()),
..test_config()
}).unwrap();
server.for_each_incoming(|message| {
client.for_each_incoming(|message| {
println!("{:?}", message);
}).unwrap();
let val = get_server_value(server);
let val = get_client_value(client);
assert!(val.starts_with("NOTICE test :\u{001}TIME :"));
assert!(val.ends_with("\u{001}\r\n"));
}
@ -1317,15 +1306,15 @@ 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 = IrcClient::from_config(Config {
let client = IrcClient::from_config(Config {
mock_initial_value: Some(value.to_owned()),
..test_config()
}).unwrap();
server.for_each_incoming(|message| {
client.for_each_incoming(|message| {
println!("{:?}", message);
}).unwrap();
assert_eq!(
&get_server_value(server)[..],
&get_client_value(client)[..],
"NOTICE test :\u{001}USERINFO :Testing.\u{001}\
\r\n"
);
@ -1335,13 +1324,13 @@ 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 = IrcClient::from_config(Config {
let client = IrcClient::from_config(Config {
mock_initial_value: Some(value.to_owned()),
..test_config()
}).unwrap();
server.for_each_incoming(|message| {
client.for_each_incoming(|message| {
println!("{:?}", message);
}).unwrap();
assert_eq!(&get_server_value(server)[..], "");
assert_eq!(&get_client_value(client)[..], "");
}
}

View file

@ -1,15 +1,15 @@
//! A client-side IRC prelude, re-exporting the complete high-level IRC client API.
//!
//! # Structure
//! A connection to an IRC server is represented by an `IrcServer` which is configured using a
//! A connection to an IRC server is created via an `IrcClient` which is configured using a
//! `Config` struct that defines data such as which server to connect to, on what port, and
//! using what nickname. The `Server` trait provides an API for actually interacting with the
//! using what nickname. The `Client` trait provides an API for actually interacting with the
//! server once a connection has been established. This API intentionally offers only a single
//! method to send `Commands` because it makes it easy to see the whole set of possible
//! interactions with a server. The `ServerExt` trait addresses this deficiency by defining a
//! interactions with a server. The `ClientExt` trait addresses this deficiency by defining a
//! number of methods that provide a more clear and succinct interface for sending various
//! common IRC commands to the server. An `IrcReactor` can be used to create and manage multiple
//! `IrcServers` with more fine-grained control over error management.
//! `IrcClients` with more fine-grained control over error management.
//!
//! The various `proto` types capture details of the IRC protocol that are used throughout the
//! client API. `Message`, `Command`, and `Response` are used to send and receive messages along

View file

@ -5,7 +5,7 @@
//! on `tokio` and `futures` in the use of `IrcClient::new_future`. This means that knowledge of
//! those libraries should be unnecessary for the average user. Nevertheless, this API also provides
//! some escape hatches that let advanced users take further advantage of these dependencies.
//!
//!
//! # Example
//! ```no_run
//! # extern crate irc;
@ -34,9 +34,9 @@ use proto::Message;
/// A thin wrapper over an event loop.
///
/// An IRC reactor is used to create new connections to IRC clients and to drive the management of
/// all connected clients as the application runs. It can be used to run multiple clients on the
/// same thread, as well as to get better control over error management in an IRC client.
/// An IRC reactor is used to create new IRC clients and to drive the management of all connected
/// clients as the application runs. It can be used to run multiple clients on the same thread, as
/// well as to get better control over error management in an IRC client.
///
/// For a full example usage, see [`irc::client::reactor`](./index.html).
pub struct IrcReactor {
@ -54,8 +54,8 @@ impl IrcReactor {
}
/// Creates a representation of an IRC client that has not yet attempted to connect. In
/// particular, this representation is as a Future that when run will produce a connected
/// [IrcClient](./client/struct.IrcClient.html).
/// particular, this representation is as a `Future` that when run will produce a connected
/// [`IrcClient`](../struct.IrcClient.html).
///
/// # Example
/// ```no_run
@ -73,8 +73,8 @@ impl IrcReactor {
IrcClient::new_future(self.inner_handle(), config)
}
/// Runs an [IrcClientFuture](./client/struct.IrcClientFuture.html), such as one from
/// `prepare_client` to completion, yielding an [IrcClient](./client/struct.IrcClient.html).
/// Runs an [`IrcClientFuture`](../struct.IrcClientFuture.html), such as one from
/// `prepare_client` to completion, yielding an [`IrcClient`](../struct.IrcClient.html).
///
/// # Example
/// ```no_run
@ -97,8 +97,9 @@ impl IrcReactor {
})
}
/// Creates a new IRC client from the specified configuration, connecting immediately. This is
/// guaranteed to be the composition of prepare_client and connect_client.
/// Creates a new [`IrcClient`](../struct.IrcClient.html) from the specified configuration,
/// connecting immediately. This is guaranteed to be the composition of `prepare_client` and
/// `connect_client`.
///
/// # Example
/// ```no_run

View file

@ -1,18 +1,18 @@
//! A simple, thread-safe, and async-friendly library for IRC clients.
//!
//! # Quick Start
//! The main public API is entirely exported in [`client::prelude`](./client/prelude/index.html). This
//! should include everything necessary to write an IRC client or bot.
//! The main public API is entirely exported in [`client::prelude`](./client/prelude/index.html).
//! This should include everything necessary to write an IRC client or bot.
//!
//! # A Whirlwind Tour
//! The irc crate is divided into two main modules: [client](./client/index.html) and
//! [proto](./proto/index.html). As the names suggest, the client module captures the whole of the
//! client-side functionality, while the proto module features general components of an IRC protocol
//! implementation that could in principle be used in either client or client software. Both modules
//! feature a number of components that are low-level and can be used to build alternative APIs for
//! the IRC protocol. For the average user, the higher-level components for an IRC client are all
//! re-exported in [`client::prelude`](./client/prelude/index.html). That module serves as the best
//! starting point for a new user trying to understand the high-level API.
//! The irc crate is divided into two main modules: [`client`](./client/index.html) and
//! [`proto`](./proto/index.html). As the names suggest, the `client` module captures the whole of
//! the client-side functionality, while the `proto` module features general components of an IRC
//! protocol implementation that could in principle be used in either client or server software.
//! Both modules feature a number of components that are low-level and can be used to build
//! alternative APIs for the IRC protocol. For the average user, the higher-level components for an
//! IRC client are all re-exported in [`client::prelude`](./client/prelude/index.html). That module
//! serves as the best starting point for a new user trying to understand the high-level API.
//!
//! # Example
//!
@ -27,14 +27,13 @@
//! client.identify().unwrap();
//! // for_each_incoming comes from Client
//! client.for_each_incoming(|irc_msg| {
//! // irc_msg is a Message
//! match irc_msg.command {
//! Command::PRIVMSG(channel, message) => if message.contains(client.current_nickname()) {
//! // send_privmsg comes from ClientExt
//! client.send_privmsg(&channel, "beep boop").unwrap();
//! // irc_msg is a Message
//! if let Command::PRIVMSG(channel, message) = irc_msg.command {
//! if message.contains(client.current_nickname()) {
//! // send_privmsg comes from ClientExt
//! client.send_privmsg(&channel, "beep boop").unwrap();
//! }
//! }
//! _ => ()
//! }
//! }).unwrap();
//! # }
//! ```