Added written to Connection interface and eliminated code duplication in Connection implementations.

This commit is contained in:
Aaron Weiss 2016-02-10 00:23:44 -05:00
parent 3314c93c3e
commit 75bcc42af5

View file

@ -7,8 +7,6 @@ use std::io::ErrorKind;
use std::net::TcpStream; use std::net::TcpStream;
#[cfg(feature = "ssl")] use std::result::Result as StdResult; #[cfg(feature = "ssl")] use std::result::Result as StdResult;
use std::sync::Mutex; use std::sync::Mutex;
#[cfg(feature = "encode")] use encoding::{DecoderTrap, EncoderTrap, Encoding};
#[cfg(feature = "encode")] use encoding::label::encoding_from_whatwg_label;
#[cfg(feature = "ssl")] use openssl::ssl::{SslContext, SslMethod, SslStream}; #[cfg(feature = "ssl")] use openssl::ssl::{SslContext, SslMethod, SslStream};
#[cfg(feature = "ssl")] use openssl::ssl::error::SslError; #[cfg(feature = "ssl")] use openssl::ssl::error::SslError;
@ -113,59 +111,22 @@ fn ssl_to_io<T>(res: StdResult<T, SslError>) -> Result<T> {
impl Connection for NetConnection { impl Connection for NetConnection {
#[cfg(feature = "encode")] #[cfg(feature = "encode")]
fn send(&self, msg: &str, encoding: &str) -> Result<()> { fn send(&self, msg: &str, encoding: &str) -> Result<()> {
let encoding = match encoding_from_whatwg_label(encoding) { imp::send(&self.writer, msg, encoding)
Some(enc) => enc,
None => return Err(Error::new(
ErrorKind::InvalidInput, &format!("Failed to find encoder. ({})", encoding)[..]
))
};
let data = match encoding.encode(msg, EncoderTrap::Replace) {
Ok(data) => data,
Err(data) => return Err(Error::new(ErrorKind::InvalidInput,
&format!("Failed to encode {} as {}.", data, encoding.name())[..]
))
};
let mut writer = self.writer.lock().unwrap();
try!(writer.write_all(&data));
writer.flush()
} }
#[cfg(not(feature = "encode"))] #[cfg(not(feature = "encode"))]
fn send(&self, msg: &str) -> Result<()> { fn send(&self, msg: &str) -> Result<()> {
let mut writer = self.writer.lock().unwrap(); imp::send(&self.writer, msg)
try!(writer.write_all(msg.as_bytes()));
writer.flush()
} }
#[cfg(feature = "encoding")] #[cfg(feature = "encoding")]
fn recv(&self, encoding: &str) -> Result<String> { fn recv(&self, encoding: &str) -> Result<String> {
let encoding = match encoding_from_whatwg_label(encoding) { imp::recv(&self.reader, encoding)
Some(enc) => enc,
None => return Err(Error::new(
ErrorKind::InvalidInput, &format!("Failed to find decoder. ({})", encoding)[..]
))
};
let mut buf = Vec::new();
self.reader.lock().unwrap().read_until(b'\n', &mut buf).and_then(|_|
match encoding.decode(&buf, DecoderTrap::Replace) {
_ if buf.is_empty() => Err(Error::new(ErrorKind::Other, "EOF")),
Ok(data) => Ok(data),
Err(data) => return Err(Error::new(ErrorKind::InvalidInput,
&format!("Failed to decode {} as {}.", data, encoding.name())[..]
))
}
)
} }
#[cfg(not(feature = "encoding"))] #[cfg(not(feature = "encoding"))]
fn recv(&self) -> Result<String> { fn recv(&self) -> Result<String> {
let mut ret = String::new(); imp::recv(&self.reader)
try!(self.reader.lock().unwrap().read_line(&mut ret));
if ret.is_empty() {
Err(Error::new(ErrorKind::Other, "EOF"))
} else {
Ok(ret)
}
} }
fn written(&self) -> Option<String> { fn written(&self) -> Option<String> {
@ -215,6 +176,45 @@ impl MockConnection {
impl Connection for MockConnection { impl Connection for MockConnection {
#[cfg(feature = "encode")] #[cfg(feature = "encode")]
fn send(&self, msg: &str, encoding: &str) -> Result<()> { fn send(&self, msg: &str, encoding: &str) -> Result<()> {
imp::send(&self.writer, msg, encoding)
}
#[cfg(not(feature = "encode"))]
fn send(&self, msg: &str) -> Result<()> {
imp::send(&self.writer, msg)
}
#[cfg(feature = "encoding")]
fn recv(&self, encoding: &str) -> Result<String> {
imp::recv(&self.reader, encoding)
}
#[cfg(not(feature = "encoding"))]
fn recv(&self) -> Result<String> {
imp::recv(&self.reader)
}
fn written(&self) -> Option<String> {
String::from_utf8(self.writer.lock().unwrap().clone()).ok()
}
fn reconnect(&self) -> Result<()> {
Ok(())
}
}
mod imp {
use std::io::prelude::*;
use std::io::Result;
use std::io::Error;
use std::io::ErrorKind;
use std::sync::Mutex;
#[cfg(feature = "encode")] use encoding::{DecoderTrap, EncoderTrap, Encoding};
#[cfg(feature = "encode")] use encoding::label::encoding_from_whatwg_label;
use client::data::kinds::{IrcRead, IrcWrite};
#[cfg(feature = "encode")]
pub fn send<T: IrcWrite>(writer: &Mutex<T>, msg: &str, encoding: &str) -> Result<()> {
let encoding = match encoding_from_whatwg_label(encoding) { let encoding = match encoding_from_whatwg_label(encoding) {
Some(enc) => enc, Some(enc) => enc,
None => return Err(Error::new( None => return Err(Error::new(
@ -227,20 +227,20 @@ impl Connection for MockConnection {
&format!("Failed to encode {} as {}.", data, encoding.name())[..] &format!("Failed to encode {} as {}.", data, encoding.name())[..]
)) ))
}; };
let mut writer = self.writer.lock().unwrap(); let mut writer = writer.lock().unwrap();
try!(writer.write_all(&data)); try!(writer.write_all(&data));
writer.flush() writer.flush()
} }
#[cfg(not(feature = "encode"))] #[cfg(not(feature = "encode"))]
fn send(&self, msg: &str) -> Result<()> { pub fn send<T: IrcWrite>(writer: &Mutex<T>, msg: &str) -> Result<()> {
let mut writer = self.writer.lock().unwrap(); let mut writer = self.writer.lock().unwrap();
try!(writer.write_all(msg.as_bytes())); try!(writer.write_all(msg.as_bytes()));
writer.flush() writer.flush()
} }
#[cfg(feature = "encoding")] #[cfg(feature = "encoding")]
fn recv(&self, encoding: &str) -> Result<String> { pub fn recv<T: IrcRead>(reader: &Mutex<T>, encoding: &str) -> Result<String> {
let encoding = match encoding_from_whatwg_label(encoding) { let encoding = match encoding_from_whatwg_label(encoding) {
Some(enc) => enc, Some(enc) => enc,
None => return Err(Error::new( None => return Err(Error::new(
@ -248,7 +248,7 @@ impl Connection for MockConnection {
)) ))
}; };
let mut buf = Vec::new(); let mut buf = Vec::new();
self.reader.lock().unwrap().read_until(b'\n', &mut buf).and_then(|_| reader.lock().unwrap().read_until(b'\n', &mut buf).and_then(|_|
match encoding.decode(&buf, DecoderTrap::Replace) { match encoding.decode(&buf, DecoderTrap::Replace) {
_ if buf.is_empty() => Err(Error::new(ErrorKind::Other, "EOF")), _ if buf.is_empty() => Err(Error::new(ErrorKind::Other, "EOF")),
Ok(data) => Ok(data), Ok(data) => Ok(data),
@ -260,27 +260,17 @@ impl Connection for MockConnection {
} }
#[cfg(not(feature = "encoding"))] #[cfg(not(feature = "encoding"))]
fn recv(&self) -> Result<String> { pub fn recv<T: IrcRead>(reader: &Mutex<T>) -> Result<String> {
let mut ret = String::new(); let mut ret = String::new();
try!(self.reader.lock().unwrap().read_line(&mut ret)); try!(reader.lock().unwrap().read_line(&mut ret));
if ret.is_empty() { if ret.is_empty() {
Err(Error::new(ErrorKind::Other, "EOF")) Err(Error::new(ErrorKind::Other, "EOF"))
} else { } else {
Ok(ret) Ok(ret)
} }
} }
fn written(&self) -> Option<String> {
String::from_utf8(self.writer.lock().unwrap().clone()).ok()
} }
fn reconnect(&self) -> Result<()> {
Ok(())
}
}
/// An abstraction over different networked streams. /// An abstraction over different networked streams.
pub enum NetStream { pub enum NetStream {
/// An unsecured TcpStream. /// An unsecured TcpStream.