From cd708c3ef3f8c070f4b0c566575fb043c4eb1e8e Mon Sep 17 00:00:00 2001 From: Till Hoeppner Date: Sun, 4 Jan 2015 23:34:37 +0100 Subject: I should make smaller commits. --- src/server.rs | 152 ++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 101 insertions(+), 51 deletions(-) (limited to 'src/server.rs') diff --git a/src/server.rs b/src/server.rs index 4c4479a..154e517 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,70 +1,120 @@ use std::io::{ BufferedReader, TcpStream, - IoError + IoError, + IoResult }; - -use std::sync::Arc; -use std::sync::Mutex; - -use std::borrow::ToOwned; +use std::mem; use callback::Callback; -use event; -use event::Event; +use message; +use message::{ Command, Message }; + +#[cfg(feature = "ssl")] +use openssl::ssl::{ SslContext, SslMethod, SslStream }; -#[deriving(Show, PartialEq, Eq, Clone)] +#[derive(Show, PartialEq, Eq, Clone)] pub enum Failure { AlreadyConnected, NotConnected, Io(IoError) } -#[deriving(Clone)] -pub struct Server { - stream: Arc>>, - pub events: Arc>>, +/// Yes, I don't like the name either, but it's private, so... +enum StreamKind { + Plain(TcpStream), + #[cfg(feature = "ssl")] + Ssl(SslStream) +} + +impl Writer for StreamKind { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { + match *self { + StreamKind::Plain(ref mut s) => s.write(buf), + #[cfg(feature = "ssl")] + StreamKind::Ssl(ref mut s) => s.write(buf) + } + } } -impl Server { - pub fn new() -> Server { +impl Reader for StreamKind { + fn read(&mut self, buf: &mut [u8]) -> IoResult { + match *self { + StreamKind::Plain(ref mut s) => s.read(buf), + #[cfg(feature = "ssl")] + StreamKind::Ssl(ref mut s) => s.read(buf) + } + } +} + +pub struct Event<'a> { + pub server: &'a mut Server<'a>, + pub message: &'a Message +} + +pub struct Server<'a> { + stream: Option, + pub events: Callback>, +} + +impl<'a> Server<'a> { + pub fn new() -> Server<'a> { Server { - stream: Arc::new(Mutex::new(None)), + stream: None, events: { let mut c = Callback::new(); - c.register(&(Server::handle_event as fn((Server,Event)))); - Arc::new(Mutex::new(c)) + c.register(Server::handle_event); + c } } } - fn handle_event(arg: (Server, Event)) { - let (mut server, event) = arg; - match event.command[] { - event::PING => { - server.sendraw(format!("PONG {}", event.content).as_slice(), true).unwrap(); + fn handle_event(e: &mut Event) { + match e.message.command { + Command::PING => { + e.server.sendraw(format!("PONG :{}", message::join(e.message.content.clone(), 0)).as_slice(), true).unwrap(); } _ => () } } pub fn connect(&mut self, host: String, port: u16) -> Result<(), Failure> { - let mut s = self.stream.lock(); + let s = &mut self.stream; match *s { Some(_) => return Err(Failure::AlreadyConnected), _ => () }; *s = match TcpStream::connect((host.as_slice(), port)) { + Ok(tcp) => Some(StreamKind::Plain(tcp)), + Err(e) => return Err(Failure::Io(e)) + }; + + Ok(()) + } + + #[cfg(feature = "ssl")] + pub fn connect_ssl(&mut self, host: String, port: u16) -> Result<(), Failure> { + let mut s = self.stream.lock(); + match *s { Some(_) => return Err(Failure::AlreadyConnected), _ => () }; + let tcp_stream = match TcpStream::connect((host.as_slice(), port)) { Ok(tcp) => Some(tcp), Err(e) => return Err(Failure::Io(e)) }; + let ssl = SslContext::new(SslMethod::Tlsv1); + let ssl_stream = SslStream::new(&ssl, tcp_stream); + *s = ssl_stream; + Ok(()) + } #[inline] fn sendraw(&mut self, s: &str, newline: bool) -> Result<(), Failure> { - info!("OUT: {}", s); - let mut locked_stream = self.stream.lock(); - if locked_stream.is_some() { - locked_stream.as_mut().map(|stream| { + info!(">> {}", s); + if cfg!(not(ndebug)) && s.len() > 510 { + panic!("Message too long, kitties will die if this runs in release mode. Msg: {}", s) + } + let stream = &mut self.stream; + if stream.is_some() { + stream.as_mut().map(|stream| { match stream.write_str(s) { Ok(_) => match { if newline { stream.write_str("\r\n") } else { Ok(()) } } { Ok(_) => match stream.flush() { @@ -81,10 +131,18 @@ impl Server { } } + pub fn send(&mut self, msg: message::Message) -> Result<(), Failure> { + self.sendraw(msg.format()[], true) + } + pub fn join(&mut self, channel: &str) -> Result<(), Failure> { self.sendraw(format!("JOIN {}", channel).as_slice(), true) } + pub fn part(&mut self, channel: &str) -> Result<(), Failure> { + self.sendraw(format!("PART {}", channel).as_slice(), true) + } + pub fn nick(&mut self, nick: &str) -> Result<(), Failure> { self.sendraw(format!("NICK {}", nick).as_slice(), true) } @@ -103,37 +161,29 @@ impl Server { pub fn listen(&mut self) -> Result<(), Failure> { let stream = { - let lock = self.stream.lock(); - match *lock { + match self.stream { Some(ref s) => s.clone(), None => return Err(Failure::NotConnected) } }; - let mut reader = BufferedReader::new(stream); + let mut reader = BufferedReader::new(match *stream { + StreamKind::Plain(ref s) => (*s).clone(), + #[cfg(feature = "ssl")] + StreamKind::Ssl(ref s) => (*s).clone() + }); + loop { let line = reader.read_line().unwrap(); - let mut parts = line.as_slice().split(' ').collect::>(); - - info!("IN: {}", line); - - if parts.len() == 0 { - continue; + info!("<< {}", line); + + if let Some(msg) = Message::parse(line[]) { + let mut e = self.events; + e.fire(&mut Event { + server: self, + message: &msg + }); } - - // if message has a prefix - let prefix = if parts[0].chars().next().unwrap() == ':' { - parts.remove(0).unwrap() - } else { "" }; - - let cmd = parts.remove(0).unwrap(); - let event = Event { - prefix: prefix.to_owned(), - command: cmd.to_owned(), - content: parts.into_iter().map(|s| s.to_owned()).collect() - }; - - self.events.lock().fire(&(self.clone(), event)); } } } -- cgit v1.2.3 From bb94e44ed6ec5b55823270192c00904cbfb24b6b Mon Sep 17 00:00:00 2001 From: Till Hoeppner Date: Sat, 18 Apr 2015 13:35:38 +0200 Subject: I forgot to keep track. Embarassing, huh? --- src/server.rs | 149 +++++++++++++++++++++++++--------------------------------- 1 file changed, 65 insertions(+), 84 deletions(-) (limited to 'src/server.rs') diff --git a/src/server.rs b/src/server.rs index 154e517..9c4bb65 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,25 +1,19 @@ use std::io::{ - BufferedReader, - TcpStream, - IoError, - IoResult + self, + Write, + Read, + BufRead, + BufReader, }; -use std::mem; -use callback::Callback; +use std::net::TcpStream; + use message; use message::{ Command, Message }; #[cfg(feature = "ssl")] use openssl::ssl::{ SslContext, SslMethod, SslStream }; -#[derive(Show, PartialEq, Eq, Clone)] -pub enum Failure { - AlreadyConnected, - NotConnected, - Io(IoError) -} - /// Yes, I don't like the name either, but it's private, so... enum StreamKind { Plain(TcpStream), @@ -27,18 +21,26 @@ enum StreamKind { Ssl(SslStream) } -impl Writer for StreamKind { - fn write(&mut self, buf: &[u8]) -> IoResult<()> { +impl Write for StreamKind { + fn write(&mut self, buf: &[u8]) -> io::Result { match *self { StreamKind::Plain(ref mut s) => s.write(buf), #[cfg(feature = "ssl")] StreamKind::Ssl(ref mut s) => s.write(buf) } } + + fn flush(&mut self) -> io::Result<()> { + match *self { + StreamKind::Plain(ref mut s) => s.flush(), + #[cfg(feature = "ssl")] + StreamKind::Ssl(ref mut s) => s.flush() + } + } } -impl Reader for StreamKind { - fn read(&mut self, buf: &mut [u8]) -> IoResult { +impl Read for StreamKind { + fn read(&mut self, buf: &mut [u8]) -> io::Result { match *self { StreamKind::Plain(ref mut s) => s.read(buf), #[cfg(feature = "ssl")] @@ -47,55 +49,41 @@ impl Reader for StreamKind { } } -pub struct Event<'a> { - pub server: &'a mut Server<'a>, - pub message: &'a Message -} - -pub struct Server<'a> { +pub struct Server { stream: Option, - pub events: Callback>, } -impl<'a> Server<'a> { - pub fn new() -> Server<'a> { +impl Server { + pub fn new() -> Server { Server { - stream: None, - events: { - let mut c = Callback::new(); - c.register(Server::handle_event); - c - } + stream: None } } - fn handle_event(e: &mut Event) { - match e.message.command { - Command::PING => { - e.server.sendraw(format!("PONG :{}", message::join(e.message.content.clone(), 0)).as_slice(), true).unwrap(); - } - _ => () + fn handle_event(&mut self, msg: &message::Message) { + if *msg.command == "PING" { + let _ = self.send(Command::Pong { server1: msg.suffix.clone(), server2: None }.to_message()); } } - pub fn connect(&mut self, host: String, port: u16) -> Result<(), Failure> { + pub fn connect(&mut self, host: String, port: u16) -> ::Result<()> { let s = &mut self.stream; - match *s { Some(_) => return Err(Failure::AlreadyConnected), _ => () }; + match *s { Some(_) => return Err(::IrscError::AlreadyConnected), _ => () }; *s = match TcpStream::connect((host.as_slice(), port)) { Ok(tcp) => Some(StreamKind::Plain(tcp)), - Err(e) => return Err(Failure::Io(e)) + Err(e) => return Err(::IrscError::Io(e)) }; Ok(()) } #[cfg(feature = "ssl")] - pub fn connect_ssl(&mut self, host: String, port: u16) -> Result<(), Failure> { + pub fn connect_ssl(&mut self, host: String, port: u16) -> ::Result<()> { let mut s = self.stream.lock(); - match *s { Some(_) => return Err(Failure::AlreadyConnected), _ => () }; + match *s { Some(_) => return Err(::IrscError::AlreadyConnected), _ => () }; let tcp_stream = match TcpStream::connect((host.as_slice(), port)) { Ok(tcp) => Some(tcp), - Err(e) => return Err(Failure::Io(e)) + Err(e) => return Err(::IrscError::Io(e)) }; let ssl = SslContext::new(SslMethod::Tlsv1); @@ -103,87 +91,80 @@ impl<'a> Server<'a> { *s = ssl_stream; Ok(()) - } #[inline] - fn sendraw(&mut self, s: &str, newline: bool) -> Result<(), Failure> { + fn sendraw(&mut self, s: &str, newline: bool) -> ::Result { info!(">> {}", s); - if cfg!(not(ndebug)) && s.len() > 510 { + if ::DEBUG && s.len() > 510 { panic!("Message too long, kitties will die if this runs in release mode. Msg: {}", s) } let stream = &mut self.stream; if stream.is_some() { stream.as_mut().map(|stream| { - match stream.write_str(s) { - Ok(_) => match { if newline { stream.write_str("\r\n") } else { Ok(()) } } { - Ok(_) => match stream.flush() { - Ok(_) => Ok(()), - Err(e) => return Err(Failure::Io(e)) + match stream.write(s.as_bytes()) { + Ok(a) => match { if newline { stream.write(b"\r\n").map(|s| s + a) } else { Ok(a) } } { + Ok(b) => match stream.flush() { + Ok(_) => Ok(b), + Err(e) => return Err(::IrscError::Io(e)) }, - Err(e) => return Err(Failure::Io(e)) + Err(e) => return Err(::IrscError::Io(e)) }, - Err(e) => return Err(Failure::Io(e)) + Err(e) => return Err(::IrscError::Io(e)) } }).unwrap() } else { - Err(Failure::NotConnected) + Err(::IrscError::NotConnected) } } - pub fn send(&mut self, msg: message::Message) -> Result<(), Failure> { - self.sendraw(msg.format()[], true) + pub fn send(&mut self, msg: message::Message) -> ::Result { + self.sendraw(&msg.to_string(), true) } - pub fn join(&mut self, channel: &str) -> Result<(), Failure> { + pub fn join(&mut self, channel: &str) -> ::Result { self.sendraw(format!("JOIN {}", channel).as_slice(), true) } - pub fn part(&mut self, channel: &str) -> Result<(), Failure> { + pub fn part(&mut self, channel: &str) -> ::Result { self.sendraw(format!("PART {}", channel).as_slice(), true) } - pub fn nick(&mut self, nick: &str) -> Result<(), Failure> { + pub fn nick(&mut self, nick: &str) -> ::Result { self.sendraw(format!("NICK {}", nick).as_slice(), true) } - pub fn user(&mut self, username: &str, hostname: &str, servername: &str, realname: &str) -> Result<(), Failure> { + pub fn user(&mut self, username: &str, hostname: &str, servername: &str, realname: &str) -> ::Result { self.sendraw(format!("USER {} {} {} :{}", username, hostname, servername, realname).as_slice(), true) } - pub fn password(&mut self, password: &str) -> Result<(), Failure> { + pub fn password(&mut self, password: &str) -> ::Result { self.sendraw(format!("PASS {}", password).as_slice(), true) } - pub fn msg(&mut self, target: &str, message: &str) -> Result<(), Failure> { + pub fn msg(&mut self, target: &str, message: &str) -> ::Result { self.sendraw(format!("PRIVMSG {} :{}", target, message).as_slice(), true) } - pub fn listen(&mut self) -> Result<(), Failure> { - let stream = { - match self.stream { - Some(ref s) => s.clone(), - None => return Err(Failure::NotConnected) - } - }; - - let mut reader = BufferedReader::new(match *stream { - StreamKind::Plain(ref s) => (*s).clone(), + pub fn listen(&mut self, events: &[fn(&mut Server, &Message)]) -> ::Result<()> { + let mut reader = BufReader::new(match self.stream { + Some(StreamKind::Plain(ref s)) => (*s).try_clone().unwrap(), #[cfg(feature = "ssl")] - StreamKind::Ssl(ref s) => (*s).clone() + Some(StreamKind::Ssl(ref s)) => (*s).try_clone().unwrap(), + None => return Err(::IrscError::NotConnected) }); - loop { - let line = reader.read_line().unwrap(); - info!("<< {}", line); + /*for line in reader.lines() { + let line = line.unwrap().parse(); - if let Some(msg) = Message::parse(line[]) { - let mut e = self.events; - e.fire(&mut Event { - server: self, - message: &msg - }); + if let Ok(msg) = line { + println!("{:?}", msg); + self.handle_event(&msg); + for e in events.iter() { + e(self, &msg) + } } - } + }*/ + Ok(()) } } -- cgit v1.2.3 From a8c80253d6361728db95e6a5640a91a341ad4ea5 Mon Sep 17 00:00:00 2001 From: Till Hoeppner Date: Sat, 18 Apr 2015 14:55:40 +0200 Subject: Fix Option/Result confusions + fixes for stability --- src/server.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src/server.rs') diff --git a/src/server.rs b/src/server.rs index 9c4bb65..dfe5051 100644 --- a/src/server.rs +++ b/src/server.rs @@ -2,7 +2,7 @@ use std::io::{ self, Write, Read, - BufRead, +// BufRead, BufReader, }; @@ -69,7 +69,7 @@ impl Server { pub fn connect(&mut self, host: String, port: u16) -> ::Result<()> { let s = &mut self.stream; match *s { Some(_) => return Err(::IrscError::AlreadyConnected), _ => () }; - *s = match TcpStream::connect((host.as_slice(), port)) { + *s = match TcpStream::connect((host.as_ref(), port)) { Ok(tcp) => Some(StreamKind::Plain(tcp)), Err(e) => return Err(::IrscError::Io(e)) }; @@ -81,7 +81,7 @@ impl Server { pub fn connect_ssl(&mut self, host: String, port: u16) -> ::Result<()> { let mut s = self.stream.lock(); match *s { Some(_) => return Err(::IrscError::AlreadyConnected), _ => () }; - let tcp_stream = match TcpStream::connect((host.as_slice(), port)) { + let tcp_stream = match TcpStream::connect((host.as_ref(), port)) { Ok(tcp) => Some(tcp), Err(e) => return Err(::IrscError::Io(e)) }; @@ -123,27 +123,27 @@ impl Server { } pub fn join(&mut self, channel: &str) -> ::Result { - self.sendraw(format!("JOIN {}", channel).as_slice(), true) + self.sendraw(format!("JOIN {}", channel).as_ref(), true) } pub fn part(&mut self, channel: &str) -> ::Result { - self.sendraw(format!("PART {}", channel).as_slice(), true) + self.sendraw(format!("PART {}", channel).as_ref(), true) } pub fn nick(&mut self, nick: &str) -> ::Result { - self.sendraw(format!("NICK {}", nick).as_slice(), true) + self.sendraw(format!("NICK {}", nick).as_ref(), true) } pub fn user(&mut self, username: &str, hostname: &str, servername: &str, realname: &str) -> ::Result { - self.sendraw(format!("USER {} {} {} :{}", username, hostname, servername, realname).as_slice(), true) + self.sendraw(format!("USER {} {} {} :{}", username, hostname, servername, realname).as_ref(), true) } pub fn password(&mut self, password: &str) -> ::Result { - self.sendraw(format!("PASS {}", password).as_slice(), true) + self.sendraw(format!("PASS {}", password).as_ref(), true) } pub fn msg(&mut self, target: &str, message: &str) -> ::Result { - self.sendraw(format!("PRIVMSG {} :{}", target, message).as_slice(), true) + self.sendraw(format!("PRIVMSG {} :{}", target, message).as_ref(), true) } pub fn listen(&mut self, events: &[fn(&mut Server, &Message)]) -> ::Result<()> { -- cgit v1.2.3 From 3483b65e9173d9ef7ea709de898b3a7866045fbd Mon Sep 17 00:00:00 2001 From: Till Hoeppner Date: Sat, 18 Apr 2015 15:12:41 +0200 Subject: Make tests/examples compile, not work though --- src/server.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/server.rs') diff --git a/src/server.rs b/src/server.rs index dfe5051..8f48938 100644 --- a/src/server.rs +++ b/src/server.rs @@ -2,7 +2,7 @@ use std::io::{ self, Write, Read, -// BufRead, + BufRead, BufReader, }; @@ -154,7 +154,7 @@ impl Server { None => return Err(::IrscError::NotConnected) }); - /*for line in reader.lines() { + for line in reader.lines() { let line = line.unwrap().parse(); if let Ok(msg) = line { @@ -164,7 +164,7 @@ impl Server { e(self, &msg) } } - }*/ + } Ok(()) } } -- cgit v1.2.3