aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZachary Dremann <dremann@gmail.com>2014-06-03 18:57:24 -0400
committerZachary Dremann <dremann@gmail.com>2014-06-08 22:45:19 -0400
commit4098f06294a2a9c40f4183e9e2ce291550cb69fd (patch)
tree2c35b5cf0e434ed15993ce08bdfae900c765c2cc
parent7e10df8e0dbd5f74b79b027512628162f94c2f54 (diff)
downloadrusty-irc-4098f06294a2a9c40f4183e9e2ce291550cb69fd.tar.gz
rusty-irc-4098f06294a2a9c40f4183e9e2ce291550cb69fd.zip
tmp
-rw-r--r--.gitignore14
-rw-r--r--lib.rs154
-rw-r--r--libirc/lib.rs86
-rw-r--r--libirc/libirc-ad3d5237-0.1.rlibbin0 -> 757684 bytes
-rw-r--r--libirc/msg.rs185
-rw-r--r--main.rs31
6 files changed, 301 insertions, 169 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d87dbe6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,14 @@
+_Store
+/src/
+/bin/
+/doc/
+/target/
+/examples/
+/.rust
+rusti.sh
+.travis.yml
+cargo-lite.conf
+.symlink-info
+*.swp
+
+Cargo.toml
diff --git a/lib.rs b/lib.rs
deleted file mode 100644
index a6dfb7b..0000000
--- a/lib.rs
+++ /dev/null
@@ -1,154 +0,0 @@
-//#![crate_id = "irc#0.1"]
-//#![crate_type = "lib"]
-
-use std::io::net::tcp::TcpStream;
-use std::io::IoResult;
-use std::io::BufferedReader;
-use std::fmt;
-use std::from_str::FromStr;
-
-pub struct IrcConnection {
- callbacks: IrcCallbacks,
- stream: TcpStream
-}
-
-#[deriving(Clone)]
-pub enum Command {
- Nick,
- User,
- Quit,
- Join,
- Part,
- PrivMsg,
- Notice,
- Motd,
- Ping,
- Pong,
- Error,
- Away,
- Numeric(u16),
- UnknownStr(String)
-}
-
-impl fmt::Show for Command {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- write!(formatter, "{}",
- match *self {
- Nick => "NICK".into_maybe_owned(),
- User => "USER".into_maybe_owned(),
- Quit => "QUIT".into_maybe_owned(),
- Join => "JOIN".into_maybe_owned(),
- Part => "PART".into_maybe_owned(),
- PrivMsg => "PRIVMSG".into_maybe_owned(),
- Notice => "NOTICE".into_maybe_owned(),
- Motd => "MOTD".into_maybe_owned(),
- Ping => "PING".into_maybe_owned(),
- Pong => "PONG".into_maybe_owned(),
- Error => "ERROR".into_maybe_owned(),
- Away => "AWAY".into_maybe_owned(),
- Numeric(i) => i.to_str().into_maybe_owned(),
- UnknownStr(ref s) => s.as_slice().into_maybe_owned(),
- }
- )
- }
-}
-
-impl FromStr for Command {
- fn from_str(s: &str) -> Option<Command> {
- Some(match s {
- "NICK" => Nick,
- "USER" => User,
- "QUIT" => Quit,
- "JOIN" => Join,
- "PART" => Part,
- "PRIVMSG" => PrivMsg,
- "NOTICE" => Notice,
- "MOTD" => Motd,
- "PING" => Ping,
- "PONG" => Pong,
- "ERROR" => Error,
- "AWAY" => Away,
- other => match from_str::<u16>(other) {
- Some(i) => Numeric(i),
- None => UnknownStr(other.to_string())
- }
- })
- }
-}
-
-#[deriving(Clone)]
-pub struct Message {
- pub prefix: Option<String>,
- pub command: Command,
- pub arguments: Vec<String>,
-}
-
-impl<'a> fmt::Show for Message {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- if self.prefix.is_some() {
- try!(write!(formatter, ":{} ", self.prefix.get_ref()));
- }
- try!(write!(formatter, "{}", self.command));
- for argument in self.arguments.iter() {
- try!(write!(formatter, " {}", *argument));
- }
- Ok(())
- }
-}
-
-impl FromStr for Message {
- fn from_str(s: &str) -> Option<Message> {
- //TODO: Parse string
- unimplemented!();
- }
-}
-
-
-
-impl IrcConnection {
- pub fn connect(
- callbacks: IrcCallbacks, host: &str, port: u16,
- nick: &str, username: &str, real_name: &str) -> IoResult<IrcConnection> {
- let mut stream = try!(TcpStream::connect(host, port));
-
- Ok(IrcConnection {
- callbacks: callbacks,
- stream: stream
- })
- }
-
- pub fn start_loop(&mut self) {
- let stream = self.stream.clone();
-// spawn(proc() {
- let mut reader = BufferedReader::new(stream);
- loop {
- match reader.read_line() {
- Ok(line) => {
- let mut words: Vec<&str> = line.as_slice().words().collect();
-
- println!("{}", words);
- if words.is_empty() { continue; }
- if (*words.get(0)).starts_with(":") {
- words.shift();
- }
- match *words.get(0) {
- "PING" => println!("PING"),
- other => println!("other: {}", other),
- }
- }
- Err(e) => {
- println!("An Error occured: {}", e);
- break;
- }
- }
- break;
- }
-// });
- }
-}
-
-pub struct IrcCallbacks {
- pub on_connect: fn(&mut IrcConnection)->(),
- pub on_numeric: fn(&mut IrcConnection, uint, &str, &[&str])->(),
- //TODO: Add the rest
-}
diff --git a/libirc/lib.rs b/libirc/lib.rs
new file mode 100644
index 0000000..8b385ec
--- /dev/null
+++ b/libirc/lib.rs
@@ -0,0 +1,86 @@
+#![crate_id = "irc#0.1"]
+#![crate_type = "lib"]
+
+use std::io::net::tcp::TcpStream;
+use std::io::IoResult;
+use std::io::BufferedReader;
+use std::io::IoError;
+
+use msg::Message;
+use msg::cmd;
+
+pub mod msg;
+
+pub struct IrcConnection<'a> {
+ stream: TcpStream,
+ output_sender: Sender<Message>,
+ msg_callback: |&Message, &Sender<Message>|: 'a -> ()
+}
+
+impl<'a> IrcConnection<'a> {
+ pub fn connect<'b>(
+ host: &str, port: u16, nick: String, username: String,
+ real_name: String, msg_callback: |&Message, &Sender<Message>|: 'b -> ()) -> IoResult<IrcConnection<'b>> {
+
+ let (send_writer, rec_writer) = channel();
+
+ let mut connection = IrcConnection {
+ stream: try!(TcpStream::connect(host, port)),
+ output_sender: send_writer.clone(),
+ msg_callback: msg_callback,
+ };
+
+ let writer = connection.stream.clone();
+
+ // spawn writer thread
+ spawn(proc() {
+ let mut writer = writer;
+ for msg in rec_writer.iter() {
+ (write!(writer, "{}", msg)).ok().expect("Unable to write to stream");
+ }
+ });
+
+ connection.send(Message::new(cmd::Nick(nick)));
+ connection.send(Message::new(cmd::User(username, 0, real_name)));
+ Ok(connection)
+ }
+
+ pub fn send(&mut self, message: Message) {
+ self.output_sender.send(message);
+ }
+
+ fn on_msg_rec(msg: &Message, sender: &Sender<Message>) {
+ let prefix = &msg.prefix;
+ let cmd = &msg.command;
+ match *cmd {
+ cmd::Ping(ref s) => sender.send(Message::new(cmd::Pong(s.clone()))),
+ _ => { }
+ };
+ }
+
+ pub fn run_loop(&mut self) {
+ let reader = &mut self.stream;
+ loop {
+ fn reader_by_ref<'a, R: Reader>(reader: &'a mut R) -> std::io::RefReader<'a, R> { reader.by_ref() }
+
+ reader.set_read_timeout(Some(500));
+ let mut buf_reader = BufferedReader::new(reader_by_ref(reader));
+
+ let line = buf_reader.read_line();
+ match line {
+ Ok(line) => match from_str::<Message>(line.as_slice().trim_right()) {
+ Some(msg) => {
+ IrcConnection::on_msg_rec(&msg, &self.output_sender);
+ (self.msg_callback)(&msg, &self.output_sender);
+ },
+ None => println!("Invalid Message recieved"),
+ },
+ Err(IoError{kind: std::io::TimedOut, ..}) => continue,
+ Err(e) => {
+ println!("Unable to read line: {}", e);
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/libirc/libirc-ad3d5237-0.1.rlib b/libirc/libirc-ad3d5237-0.1.rlib
new file mode 100644
index 0000000..c367445
--- /dev/null
+++ b/libirc/libirc-ad3d5237-0.1.rlib
Binary files differ
diff --git a/libirc/msg.rs b/libirc/msg.rs
new file mode 100644
index 0000000..3471d75
--- /dev/null
+++ b/libirc/msg.rs
@@ -0,0 +1,185 @@
+use std::fmt;
+use std::from_str::FromStr;
+use std::ascii::OwnedStrAsciiExt;
+
+pub mod cmd {
+ #[deriving(Clone, Show)]
+ pub enum Command {
+ Nick(String),
+ User(String, u8, String),
+ Quit(Option<String>),
+ Join(String),
+ Part(String, Option<String>),
+ PrivMsg(String, String),
+ Notice(String, String),
+ //Motd(Option<String>),
+ Ping(String),
+ Pong(String),
+ Error(String),
+ Away(Option<String>),
+ Numeric(u16, Option<String>),
+ UnknownCmd(String, Vec<String>)
+ }
+}
+
+pub struct PrefixHost {
+ hostname: String,
+ user: Option<String>,
+}
+
+pub enum Prefix {
+ PrefixServer(String),
+ PrefixUser(String, Option<PrefixHost>),
+}
+
+#[deriving(Clone)]
+pub struct Message {
+ pub prefix: Option<String>,
+ pub command: cmd::Command,
+}
+
+impl Message {
+ pub fn new(command: cmd::Command) -> Message {
+ Message { prefix: None, command: command }
+ }
+
+ pub fn with_prefix(prefix: String, command: cmd::Command) -> Message {
+ Message { prefix: Some(prefix), command: command }
+ }
+}
+
+impl<'a> fmt::Show for Message {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ if self.prefix.is_some() {
+ try!(write!(formatter, ":{} ", self.prefix.get_ref()));
+ }
+
+ match self.command {
+ cmd::Nick(ref nickname) => write!(formatter, "NICK {}", nickname),
+ cmd::User(ref username, mode, ref real_name) => write!(formatter, "USER {} {} * :{}", username, mode, real_name),
+ cmd::Quit(ref msg) => if msg.is_some() { write!(formatter, "QUIT :{}", *msg.get_ref()) } else { write!(formatter, "QUIT") },
+ cmd::Join(ref channel) => write!(formatter, "JOIN :{}", channel),
+ cmd::Part(ref channel, ref msg) => if msg.is_some() { write!(formatter, "PART {} :{}", channel, *msg.get_ref()) } else { write!(formatter, "PART {}", channel) },
+ cmd::PrivMsg(ref target, ref msg) => write!(formatter, "PRIVMSG {} :{}", target, msg),
+ cmd::Notice(ref target, ref msg) => write!(formatter, "NOTICE {} :{}", target, msg),
+ cmd::Ping(ref msg) => write!(formatter, "PING :{}", msg),
+ cmd::Pong(ref msg) => write!(formatter, "PONG :{}", msg),
+ cmd::Error(ref msg) => write!(formatter, "ERROR :{}", msg),
+ cmd::Away(ref msg) => if msg.is_some() { write!(formatter, "AWAY :{}", msg.get_ref()) } else { write!(formatter, "AWAY") },
+ cmd::Numeric(i, ref msg) => if msg.is_some() { write!(formatter, "{:03u} :{}", i, msg.get_ref()) } else { write!(formatter, "{:03u}", i) },
+ cmd::UnknownCmd(ref cmd, ref args) => {
+ try!(write!(formatter, "{}", cmd));
+ let mut iter = args.iter().peekable();
+ loop {
+ match iter.next() {
+ Some(arg) => {
+ try!(
+ if iter.peek().is_some() {
+ write!(formatter, " {}", arg)
+ }
+ else {
+ write!(formatter, " :{}", arg)
+ }
+ )
+ }
+ None => break
+ }
+ }
+ Ok(())
+ }
+ }
+ }
+}
+
+impl FromStr for Message {
+ fn from_str(s: &str) -> Option<Message> {
+ let mut prefix = None;
+ let mut cmd = None;
+ let mut args = Vec::new();
+ let mut current_str: Option<String> = None;
+ let mut is_prefix = false;
+ let mut is_final = false;
+
+ for c in s.chars() {
+ match c {
+ c if is_final => {
+ current_str.get_mut_ref().push_char(c);
+ }
+ ' ' => {
+ if is_prefix {
+ prefix = current_str.take();
+ }
+ else if cmd.is_none() {
+ cmd = current_str.take();
+ }
+ else {
+ args.push(current_str.take_unwrap());
+ }
+ is_prefix = false;
+ }
+ ':' if current_str.is_none() => {
+ current_str = Some(String::new());
+ if cmd.is_none() {
+ is_prefix = true;
+ }
+ else {
+ is_final = true;
+ }
+ }
+ c => {
+ if current_str.is_none() {
+ current_str = Some(String::new());
+ }
+ current_str.get_mut_ref().push_char(c)
+ }
+ }
+ }
+
+ args.push(current_str.take_unwrap());
+
+ let cmd = match cmd.map(|s| s.into_ascii_upper()).as_ref().map(|s| s.as_slice()) {
+ Some("NICK") => {
+ if args.len() == 1 { Some(cmd::Nick(args.pop().unwrap())) }
+ else { None }
+ }
+ Some("USER") => {
+ if args.len() == 4 {
+ let mut iter = args.move_iter();
+ let uname = iter.next().unwrap();
+ let opt_mode: Option<u8> = from_str(iter.next().unwrap().as_slice());
+ iter.next();
+ let fullname = iter.next().unwrap();
+ if opt_mode.is_some() {
+ Some(cmd::User(uname, opt_mode.unwrap(), fullname))
+ }
+ else {
+ None
+ }
+ }
+ else { None }
+ }
+ Some("NOTICE") => {
+ if args.len() == 2 {
+ let mut iter = args.move_iter();
+ Some(cmd::Notice(iter.next().unwrap(), iter.next().unwrap()))
+ }
+ else { None }
+ }
+ Some("PRIVMSG") => {
+ if args.len() == 2 {
+ let mut iter = args.move_iter();
+ Some(cmd::PrivMsg(iter.next().unwrap(), iter.next().unwrap()))
+ }
+ else { None }
+ }
+ Some(other) => {
+ Some(cmd::UnknownCmd(other.to_string(), args))
+ }
+ None => {
+ None
+ }
+ };
+
+ cmd.map(|c| Message { prefix: prefix.take(), command: c })
+ }
+}
diff --git a/main.rs b/main.rs
index 1d975b2..6ec9134 100644
--- a/main.rs
+++ b/main.rs
@@ -1,24 +1,25 @@
+extern crate irc;
+
use std::io::net::tcp::TcpStream;
use std::io::BufferedReader;
-use lib::IrcCallbacks;
-use lib::IrcConnection;
-
-mod lib;
+use irc::IrcConnection;
+use irc::msg::Message;
+use irc::msg::cmd;
fn main() {
- fn on_connect(_connection: &mut IrcConnection) {
- println!("Connected");
- }
- fn on_numeric(_connection: &mut IrcConnection, n: uint, origin: &str, params: &[&str]) {
- println!("Numeric event \\#{} with params {}", n, params);
- }
- let callbacks = IrcCallbacks {
- on_connect: on_connect,
- on_numeric: on_numeric,
+ let message = Message {
+ prefix: None,
+ command: cmd::PrivMsg("#rust".to_string(), "Hi there everyone".to_string()),
+ };
+
+ println!("{}", message);
+
+ let on_msg = |message: &Message, _sender: &Sender<Message>| {
+ println!("{}", *message);
};
- let mut connection = IrcConnection::connect(callbacks, "irc.mozilla.org", 6667, "Dr-Emann", "dremann", "Zachary Dremann").unwrap();
- connection.start_loop();
+ let mut connection = IrcConnection::connect("irc.mozilla.org", 6667, "Dr-Emann".to_string(), "dremann".to_string(), "Zachary Dremann".to_string(), on_msg).unwrap();
+ connection.run_loop();
}