Added Command iterator. Added a test and a use case example.
This commit is contained in:
parent
0ac5737f7f
commit
04dccf5ce2
4 changed files with 83 additions and 1 deletions
43
examples/simple_cmd.rs
Normal file
43
examples/simple_cmd.rs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
extern crate irc;
|
||||||
|
|
||||||
|
use std::default::Default;
|
||||||
|
use irc::client::prelude::*;
|
||||||
|
use irc::client::data::message::ToMessage;
|
||||||
|
|
||||||
|
// This is the same as simple.rs, except we use an Iterator over Commands
|
||||||
|
// instead of an Iterator over Messages. A Command is basically a parsed Message,
|
||||||
|
// so Commands and Messages are interchangeable. It is up to the library user to
|
||||||
|
// choose one.
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let config = Config {
|
||||||
|
nickname: Some(format!("pickles")),
|
||||||
|
alt_nicks: Some(vec![format!("bananas"), format!("apples")]),
|
||||||
|
server: Some(format!("irc.fyrechat.net")),
|
||||||
|
channels: Some(vec![format!("#vana")]),
|
||||||
|
.. Default::default()
|
||||||
|
};
|
||||||
|
let irc_server = IrcServer::from_config(config).unwrap();
|
||||||
|
// The wrapper provides us with methods like send_privmsg(...) and identify(...)
|
||||||
|
let server = Wrapper::new(&irc_server);
|
||||||
|
server.identify().unwrap();
|
||||||
|
for command in server.iter_cmd() {
|
||||||
|
// Ignore errors
|
||||||
|
// Use of unwrap() with iter_cmd() is discouraged because iter_cmd() is still unstable
|
||||||
|
// and has trouble converting some custom Messages into Commands
|
||||||
|
match command {
|
||||||
|
Ok(cmd) => {
|
||||||
|
print!("{}", cmd.to_message().into_string());
|
||||||
|
match cmd {
|
||||||
|
Command::PRIVMSG(target, text) => {
|
||||||
|
if text[..].contains("pickles") {
|
||||||
|
server.send_privmsg(&target[..], "Hi!").unwrap();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(_) => ()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -1145,6 +1145,12 @@ impl Command {
|
||||||
return Err(invalid_input())
|
return Err(invalid_input())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts an `IoResult<Message>` holding a Message into an `IoResult<Command>`
|
||||||
|
#[unstable = "This feature is still relatively new."]
|
||||||
|
pub fn from_message_io(m: IoResult<Message>) -> IoResult<Command> {
|
||||||
|
m.and_then(|msg| Command::from_message(&msg))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A list of all of the subcommands for the capabilities extension.
|
/// A list of all of the subcommands for the capabilities extension.
|
||||||
|
|
|
@ -4,6 +4,7 @@ use std::borrow::ToOwned;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::old_io::{BufferedReader, BufferedWriter, IoError, IoErrorKind, IoResult};
|
use std::old_io::{BufferedReader, BufferedWriter, IoError, IoErrorKind, IoResult};
|
||||||
use std::sync::{Mutex, RwLock};
|
use std::sync::{Mutex, RwLock};
|
||||||
|
use std::iter::Map;
|
||||||
use client::conn::{Connection, NetStream};
|
use client::conn::{Connection, NetStream};
|
||||||
use client::data::{Command, Config, Message, Response, User};
|
use client::data::{Command, Config, Message, Response, User};
|
||||||
use client::data::Command::{JOIN, NICK, NICKSERV, PONG, MODE};
|
use client::data::Command::{JOIN, NICK, NICKSERV, PONG, MODE};
|
||||||
|
@ -24,6 +25,9 @@ pub trait Server<'a, T, U> {
|
||||||
/// Gets an Iterator over Messages received by this Server.
|
/// Gets an Iterator over Messages received by this Server.
|
||||||
#[stable]
|
#[stable]
|
||||||
fn iter(&'a self) -> ServerIterator<'a, T, U>;
|
fn iter(&'a self) -> ServerIterator<'a, T, U>;
|
||||||
|
/// Gets an Iterator over Commands received by this Server.
|
||||||
|
#[unstable = "Feature is still relatively new."]
|
||||||
|
fn iter_cmd(&'a self) -> ServerCmdIterator<'a, T, U>;
|
||||||
/// Gets a list of Users in the specified channel. This will be none if the channel is not
|
/// Gets a list of Users in the specified channel. This will be none if the channel is not
|
||||||
/// being tracked, or if tracking is not supported altogether.
|
/// being tracked, or if tracking is not supported altogether.
|
||||||
#[stable]
|
#[stable]
|
||||||
|
@ -95,6 +99,10 @@ impl<'a, T: IrcReader, U: IrcWriter> Server<'a, T, U> for IrcServer<T, U> {
|
||||||
ServerIterator::new(self)
|
ServerIterator::new(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn iter_cmd(&'a self) -> ServerCmdIterator<'a, T, U> {
|
||||||
|
self.iter().map(Command::from_message_io)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "nochanlists"))]
|
#[cfg(not(feature = "nochanlists"))]
|
||||||
fn list_users(&self, chan: &str) -> Option<Vec<User>> {
|
fn list_users(&self, chan: &str) -> Option<Vec<User>> {
|
||||||
self.chanlists.lock().unwrap().get(&chan.to_owned()).cloned()
|
self.chanlists.lock().unwrap().get(&chan.to_owned()).cloned()
|
||||||
|
@ -257,6 +265,12 @@ pub struct ServerIterator<'a, T: IrcReader, U: IrcWriter> {
|
||||||
server: &'a IrcServer<T, U>
|
server: &'a IrcServer<T, U>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An Iterator over an IrcServer's incoming Commands.
|
||||||
|
/// Commands and Messages are interchangeable. This is just a convenient way to get
|
||||||
|
/// a sanitized, already-parsed IRC message.
|
||||||
|
pub type ServerCmdIterator<'a, T, U> =
|
||||||
|
Map<ServerIterator<'a, T, U>, fn(IoResult<Message>) -> IoResult<Command>>;
|
||||||
|
|
||||||
#[unstable = "Design is liable to change to accomodate new functionality."]
|
#[unstable = "Design is liable to change to accomodate new functionality."]
|
||||||
impl<'a, T: IrcReader, U: IrcWriter> ServerIterator<'a, T, U> {
|
impl<'a, T: IrcReader, U: IrcWriter> ServerIterator<'a, T, U> {
|
||||||
/// Creates a new ServerIterator for the desired IrcServer.
|
/// Creates a new ServerIterator for the desired IrcServer.
|
||||||
|
@ -312,6 +326,7 @@ mod test {
|
||||||
use client::data::{Config, User};
|
use client::data::{Config, User};
|
||||||
use client::data::command::Command::PRIVMSG;
|
use client::data::command::Command::PRIVMSG;
|
||||||
use client::data::kinds::IrcReader;
|
use client::data::kinds::IrcReader;
|
||||||
|
use client::data::message::ToMessage;
|
||||||
|
|
||||||
pub fn test_config() -> Config {
|
pub fn test_config() -> Config {
|
||||||
Config {
|
Config {
|
||||||
|
@ -344,6 +359,20 @@ mod test {
|
||||||
assert_eq!(&messages[..], exp);
|
assert_eq!(&messages[..], exp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn iterator_cmd() {
|
||||||
|
let exp = "PRIVMSG test :Hi!\r\nPRIVMSG test :This is a test!\r\n\
|
||||||
|
JOIN #test\r\n";
|
||||||
|
let server = IrcServer::from_connection(test_config(), Connection::new(
|
||||||
|
MemReader::new(exp.as_bytes().to_vec()), NullWriter
|
||||||
|
));
|
||||||
|
let mut messages = String::new();
|
||||||
|
for command in server.iter_cmd() {
|
||||||
|
messages.push_str(&command.unwrap().to_message().into_string());
|
||||||
|
}
|
||||||
|
assert_eq!(&messages[..], exp);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn handle_message() {
|
fn handle_message() {
|
||||||
let value = "PING :irc.test.net\r\n:irc.test.net 376 test :End of /MOTD command.\r\n";
|
let value = "PING :irc.test.net\r\n:irc.test.net 376 test :End of /MOTD command.\r\n";
|
||||||
|
|
|
@ -9,7 +9,7 @@ use client::data::Command::{OPER, PASS, PONG, PRIVMSG, QUIT, SAMODE, SANICK, TOP
|
||||||
use client::data::command::CapSubCommand::{END, REQ};
|
use client::data::command::CapSubCommand::{END, REQ};
|
||||||
use client::data::kinds::{IrcReader, IrcWriter};
|
use client::data::kinds::{IrcReader, IrcWriter};
|
||||||
#[cfg(feature = "ctcp")] use time::get_time;
|
#[cfg(feature = "ctcp")] use time::get_time;
|
||||||
use client::server::{Server, ServerIterator};
|
use client::server::{Server, ServerIterator, ServerCmdIterator};
|
||||||
|
|
||||||
/// Functionality-providing wrapper for Server.
|
/// Functionality-providing wrapper for Server.
|
||||||
/// Wrappers are currently not thread-safe, and should be created per-thread, as needed.
|
/// Wrappers are currently not thread-safe, and should be created per-thread, as needed.
|
||||||
|
@ -31,6 +31,10 @@ impl<'a, T: IrcReader, U: IrcWriter> Server<'a, T, U> for Wrapper<'a, T, U> {
|
||||||
self.server.iter()
|
self.server.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn iter_cmd(&'a self) -> ServerCmdIterator<'a, T, U> {
|
||||||
|
self.server.iter_cmd()
|
||||||
|
}
|
||||||
|
|
||||||
fn list_users(&self, chan: &str) -> Option<Vec<User>> {
|
fn list_users(&self, chan: &str) -> Option<Vec<User>> {
|
||||||
self.server.list_users(chan)
|
self.server.list_users(chan)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue