Added documentation everywhere.

This commit is contained in:
Aaron Weiss 2014-11-03 00:52:15 -05:00
parent 63f4ca5097
commit 5bbde7e96c
7 changed files with 141 additions and 53 deletions

View file

@ -1,14 +1,20 @@
//! Thread-safe connections on any IrcWriters and IrcReaders
#![experimental]
use std::sync::Mutex;
use std::io::{BufferedReader, BufferedWriter, IoResult, TcpStream};
use data::kinds::{IrcWriter, IrcReader};
use data::message::Message;
/// A thread-safe connection
#[experimental]
pub struct Connection<T, U> where T: IrcWriter, U: IrcReader {
writer: Mutex<T>,
reader: Mutex<U>,
}
impl Connection<BufferedWriter<TcpStream>, BufferedReader<TcpStream>> {
/// Creates a thread-safe TCP connection to the specified server
#[experimental]
pub fn connect(host: &str, port: u16) -> IoResult<Connection<BufferedWriter<TcpStream>, BufferedReader<TcpStream>>> {
let socket = try!(TcpStream::connect(host, port));
Ok(Connection::new(BufferedWriter::new(socket.clone()), BufferedReader::new(socket)))
@ -16,6 +22,8 @@ impl Connection<BufferedWriter<TcpStream>, BufferedReader<TcpStream>> {
}
impl<T, U> Connection<T, U> where T: IrcWriter, U: IrcReader {
/// Creates a new connection from any arbitrary IrcWriter and IrcReader
#[experimental]
pub fn new(writer: T, reader: U) -> Connection<T, U> {
Connection {
writer: Mutex::new(writer),
@ -23,12 +31,16 @@ impl<T, U> Connection<T, U> where T: IrcWriter, U: IrcReader {
}
}
/// Sends a Message over this connection
#[experimental]
pub fn send(&self, message: Message) -> IoResult<()> {
let mut send = self.writer.lock();
try!(send.write_str(message.into_string()[]));
send.flush()
}
/// Receives a single line from this connection
#[experimental]
pub fn recv(&self) -> IoResult<String> {
self.reader.lock().read_line()
}

View file

@ -1,101 +1,104 @@
//! Enumeration of all available client commands
#![stable]
use std::io::{InvalidInput, IoError, IoResult};
use data::message::Message;
/// List of all client commands as defined in RFC 2812.
/// List of all client commands as defined in [RFC 2812](http://tools.ietf.org/html/rfc2812)
#[stable]
#[deriving(Show, PartialEq)]
pub enum Command {
// 3.1 Connection Registration
/// PASS <password>
/// PASS password
PASS(String),
/// NICK <nickname>
/// NICK nickname
NICK(String),
/// USER <user> <mode> * <realname>
/// USER user mode * realname
USER(String, String, String),
/// OPER <name> <password>
/// OPER name password
OPER(String, String),
/// MODE <nickname> <modes>
/// MODE <channel> <modes> [<modeparams>]
/// MODE nickname modes
/// MODE channel modes [modeparams]
MODE(String, String, Option<String>),
/// SERVICE <nickname> <reserved> <distribution> <type> <reserved> <info>
/// SERVICE nickname reserved distribution type reserved info
SERVICE(String, String, String, String, String, String),
/// QUIT <Quit Message>
/// QUIT Quit Message
QUIT(Option<String>),
/// SQUIT <server> <comment>
/// SQUIT server comment
SQUIT(String, String),
// 3.2 Channel operations
/// JOIN <chanlist> [<chankeys>]
/// JOIN chanlist [chankeys]
JOIN(String, Option<String>),
/// PART <chanlist> [<Part Message>]
/// PART chanlist [Part Message]
PART(String, Option<String>),
// MODE is already defined.
// MODE(String, String, Option<String>),
/// TOPIC <channel> [<topic>]
/// TOPIC channel [topic]
TOPIC(String, Option<String>),
/// NAMES [<chanlist> [<target>]]
/// NAMES [chanlist [target]]
NAMES(Option<String>, Option<String>),
/// LIST [<chanlist> [<target>]]
/// LIST [chanlist [target]]
LIST(Option<String>, Option<String>),
/// INVITE <nickname> <channel>
/// INVITE nickname channel
INVITE(String, String),
/// KICK <chanlist> <userlist> [<comment>]
/// KICK chanlist userlist [comment]
KICK(String, String, Option<String>),
// 3.3 Sending messages
/// PRIVMSG <msgtarget> <text to be sent>
/// PRIVMSG msgtarget text to be sent
PRIVMSG(String, String),
/// NOTICE <msgtarget> <text>
/// NOTICE msgtarget text
NOTICE(String, String),
// 3.4 Server queries and commands
/// MOTD [<target>]
/// MOTD [target]
MOTD(Option<String>),
/// LUSERS [<mask> [<target>]]
/// LUSERS [mask [target]]
LUSERS(Option<String>, Option<String>),
/// VERSION [<target>]
/// VERSION [target]
VERSION(Option<String>),
/// STATS [<query> [<target>]]
/// STATS [query [target]]
STATS(Option<String>, Option<String>),
/// LINKS [[<remote server>] <server mask>]
/// LINKS [[remote server] server mask]
LINKS(Option<String>, Option<String>),
/// TIME [<target>]
/// TIME [target]
TIME(Option<String>),
/// CONNECT <target server> <port> [<remote server>]
/// CONNECT target server port [remote server]
CONNECT(String, String, Option<String>),
/// TRACE [<target>]
/// TRACE [target]
TRACE(Option<String>),
/// ADMIN [<target>]
/// ADMIN [target]
ADMIN(Option<String>),
/// INFO [<target>]
/// INFO [target]
INFO(Option<String>),
// 3.5 Service Query and Commands
/// SERVLIST [<mask> [<type>]]
/// SERVLIST [mask [type]]
SERVLIST(Option<String>, Option<String>),
/// SQUERY <servicename> <text>
/// SQUERY servicename text
SQUERY(String, String),
// 3.6 User based queries
/// WHO [<mask> ["o"]]
/// WHO [mask ["o"]]
WHO(Option<String>, Option<bool>),
/// WHOIS [<target>] <masklist>
/// WHOIS [target] masklist
WHOIS(Option<String>, String),
/// WHOWAS <nicklist> [<count> [<target>]]
/// WHOWAS nicklist [count [target]]
WHOWAS(String, Option<String>, Option<String>),
// 3.7 Miscellaneous messages
/// KILL <nickname> <comment>
/// KILL nickname comment
KILL(String, String),
/// PING <server1> [<server2>]
/// PING server1 [server2]
PING(String, Option<String>),
/// PONG <server> [<server2>]
/// PONG server [server2]
PONG(String, Option<String>),
/// ERROR <error message>
/// ERROR error message
ERROR(String),
// 4 Optional Features
/// AWAY [<text>]
/// AWAY [text]
AWAY(Option<String>),
/// REHASH
REHASH,
@ -103,31 +106,33 @@ pub enum Command {
DIE,
/// RESTART
RESTART,
/// SUMMON <user> [<target> [<channel>]]
/// SUMMON user [target [channel]]
SUMMON(String, Option<String>, Option<String>),
/// USERS [<target>]
/// USERS [target]
USERS(Option<String>),
/// WALLOPS <Text to be sent>
/// WALLOPS Text to be sent
WALLOPS(String),
/// USERHOST <space-separated nicklist>
/// USERHOST space-separated nicklist
USERHOST(Vec<String>),
/// ISON <space-separated nicklist>
/// ISON space-separated nicklist
ISON(Vec<String>),
// Non-RFC commands from InspIRCd
/// SAJOIN <nickname> <channel>
/// SAJOIN nickname channel
SAJOIN(String, String),
/// SAMODE <target> <modes> [<modeparams>]
/// SAMODE target modes [modeparams]
SAMODE(String, String, Option<String>),
/// SANICK <old nickname> <new nickname>
/// SANICK old nickname new nickname
SANICK(String, String),
/// SAPART <nickname> <reason>
/// SAPART nickname reason
SAPART(String, String),
/// SAQUIT <nickname> <reason>
/// SAQUIT nickname reason
SAQUIT(String, String),
}
impl Command {
/// Converts a Command into a Message
#[stable]
pub fn to_message(self) -> Message {
match self {
PASS(p) => Message::new(None, "PASS", None, Some(p[])),
@ -221,6 +226,8 @@ impl Command {
}
}
/// Converts a Message into a Command
#[stable]
pub fn from_message(m: Message) -> IoResult<Command> {
Ok(if let "PASS" = m.command[] {
if m.suffix.is_some() {
@ -738,6 +745,8 @@ impl Command {
}
}
/// Produces an invalid_input IoError
#[stable]
fn invalid_input() -> IoError {
IoError {
kind: InvalidInput,

View file

@ -1,22 +1,37 @@
//! JSON configuration files using libserialize
#![stable]
use std::collections::HashMap;
use std::io::fs::File;
use std::io::{InvalidInput, IoError, IoResult};
use serialize::json::decode;
/// Configuration data
#[deriving(Clone, Decodable)]
#[unstable]
pub struct Config {
/// A list of the owners of the bot by nickname
pub owners: Vec<String>,
/// The bot's nickname
pub nickname: String,
/// The bot's username
pub username: String,
/// The bot's real name
pub realname: String,
/// The bot's password
pub password: String,
/// The server to connect to
pub server: String,
/// The port to connect on
pub port: u16,
/// A list of channels to join on connection
pub channels: Vec<String>,
/// A map of additional options to be stored in config
pub options: HashMap<String, String>,
}
impl Config {
/// Loads a JSON configuration from the desired path.
#[stable]
pub fn load(path: Path) -> IoResult<Config> {
let mut file = try!(File::open(&path));
let data = try!(file.read_to_string());
@ -27,10 +42,14 @@ impl Config {
})
}
/// Loads a JSON configuration using the string as a UTF-8 path.
#[stable]
pub fn load_utf8(path: &str) -> IoResult<Config> {
Config::load(Path::new(path))
}
/// Determines whether or not the nickname provided is the owner of the bot.
#[stable]
pub fn is_owner(&self, nickname: &str) -> bool {
self.owners[].contains(&String::from_str(nickname))
}

View file

@ -1,14 +1,25 @@
//! Messages to and from the server
#![experimental]
use std::from_str::FromStr;
/// IRC Message data
#[experimental]
#[deriving(Clone, PartialEq, Show)]
pub struct Message {
/// The message prefix (or source) as defined by [RFC 2812](http://tools.ietf.org/html/rfc2812)
pub prefix: Option<String>,
/// The IRC command as defined by [RFC 2812](http://tools.ietf.org/html/rfc2812)
pub command: String,
/// The command arguments
pub args: Vec<String>,
/// The message suffix as defined by [RFC 2812](http://tools.ietf.org/html/rfc2812)
/// This is the only part of the message that is allowed to contain spaces.
pub suffix: Option<String>,
}
impl Message {
/// Creates a new Message
#[experimental]
pub fn new(prefix: Option<&str>, command: &str, args: Option<Vec<&str>>, suffix: Option<&str>)
-> Message {
Message {
@ -19,6 +30,8 @@ impl Message {
}
}
/// Converts a Message into a String according to the IRC protocol
#[experimental]
pub fn into_string(&self) -> String {
let mut ret = String::new();
if let Some(ref prefix) = self.prefix {

View file

@ -1,6 +1,16 @@
//! Data related to IRC functionality
#![experimental]
pub mod kinds {
//! Trait definitions of appropriate Writers and Buffers for use with this library
#![unstable]
/// Trait describing all possible Writers for this library
#[unstable]
pub trait IrcWriter: Writer + Sized + Send + 'static {}
impl<T> IrcWriter for T where T: Writer + Sized + Send + 'static {}
/// Trait describing all possible Readers for this library
#[unstable]
pub trait IrcReader: Buffer + Sized + Send + 'static {}
impl<T> IrcReader for T where T: Buffer + Sized + Send + 'static {}
}

View file

@ -1,6 +1,7 @@
//! A simple, thread-safe IRC client library.
#![crate_name = "irc"]
#![crate_type = "lib"]
#![unstable]
#![feature(if_let)]
#![feature(slicing_syntax)]

View file

@ -1,3 +1,5 @@
//! Interface for working with IRC Servers
#![experimental]
use std::io::{BufferedReader, BufferedWriter, IoResult, TcpStream};
use conn::Connection;
use data::command::Command;
@ -5,18 +7,30 @@ use data::config::Config;
use data::kinds::{IrcReader, IrcWriter};
use data::message::Message;
/// Trait describing core Server functionality
#[experimental]
pub trait Server<'a, T, U> {
/// Gets the configuration being used with this Server
fn config(&self) -> &Config;
/// Sends a Command to this Server
fn send(&self, _: Command) -> IoResult<()>;
/// Gets an Iterator over Messages received by this Server
fn iter(&'a self) -> ServerIterator<'a, T, U>;
}
/// A thread-safe implementation of an IRC Server connection
#[experimental]
pub struct IrcServer<'a, T, U> where T: IrcWriter, U: IrcReader {
pub conn: Connection<T, U>,
pub config: Config
/// The thread-safe IRC connection
conn: Connection<T, U>,
/// The configuration used with this connection
config: Config
}
impl<'a> IrcServer<'a, BufferedWriter<TcpStream>, BufferedReader<TcpStream>> {
pub fn new(config: &str) -> IoResult<IrcServer<'a, BufferedWriter<TcpStream>, BufferedReader<TcpStream>>> {
/// Creates a new IRC Server connection from the specified configuration, connecting immediately.
#[experimental]
pub fn new(config: &str) -> IoResult<IrcServer<'a, BufferedWriter<TcpStream>, BufferedReader<TcpStream>>> {
let config = try!(Config::load_utf8(config));
let conn = try!(Connection::connect(config.server[], config.port));
Ok(IrcServer {
@ -26,7 +40,11 @@ impl<'a> IrcServer<'a, BufferedWriter<TcpStream>, BufferedReader<TcpStream>> {
}
}
impl<'a, T, U> Server<'a, T, U> for IrcServer<'a, T, U> where T: IrcWriter, U: IrcReader{
impl<'a, T, U> Server<'a, T, U> for IrcServer<'a, T, U> where T: IrcWriter, U: IrcReader {
fn config(&self) -> &Config {
&self.config
}
fn send(&self, command: Command) -> IoResult<()> {
self.conn.send(command.to_message())
}
@ -37,6 +55,8 @@ impl<'a, T, U> Server<'a, T, U> for IrcServer<'a, T, U> where T: IrcWriter, U: I
}
impl<'a, T, U> IrcServer<'a, T, U> where T: IrcWriter, U: IrcReader {
/// Creates an IRC server from the specified configuration, and any arbitrary Connection
#[experimental]
pub fn from_connection(config: &str, conn: Connection<T, U>) -> IoResult<IrcServer<'a, T, U>> {
Ok(IrcServer {
conn: conn,
@ -45,11 +65,15 @@ impl<'a, T, U> IrcServer<'a, T, U> where T: IrcWriter, U: IrcReader {
}
}
/// An Iterator over an IrcServer's incoming Messages
#[experimental]
pub struct ServerIterator<'a, T, U> where T: IrcWriter, U: IrcReader {
pub server: &'a IrcServer<'a, T, U>
}
impl<'a, T, U> ServerIterator<'a, T, U> where T: IrcWriter, U: IrcReader {
/// Creates a new ServerIterator for the desired IrcServer
#[experimental]
pub fn new(server: &'a IrcServer<'a, T, U>) -> ServerIterator<'a, T, U> {
ServerIterator {
server: server