From acc6d7f0f0f5246ba6f2040ddc5b10eaf93511a3 Mon Sep 17 00:00:00 2001 From: Frederik B Date: Wed, 16 May 2018 11:15:43 +0200 Subject: [PATCH 01/19] Remove unnecessary [..] Replaces (&self[..]).strip_formatting() with (&self).strip_formatting() in `impl FormattedStringExt for String` --- src/proto/colors.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/proto/colors.rs b/src/proto/colors.rs index f86548c..6ffb492 100644 --- a/src/proto/colors.rs +++ b/src/proto/colors.rs @@ -102,10 +102,10 @@ impl FormattedStringExt for str { impl FormattedStringExt for String { fn is_formatted(&self) -> bool { - (&self[..]).is_formatted() + (&self).is_formatted() } fn strip_formatting(&self) -> Cow { - (&self[..]).strip_formatting() + (&self).strip_formatting() } } @@ -160,4 +160,4 @@ mod test { fn test_strip_string_with_digit_after_2digit_color() { assert_eq!("\x031212\x031111\x031010".strip_formatting(), "121110"); } -} \ No newline at end of file +} From a23f3417f18bd150baa9634da7ae16a76a5f96ad Mon Sep 17 00:00:00 2001 From: Aaron Weiss Date: Sun, 27 May 2018 23:15:05 +0200 Subject: [PATCH 02/19] Added the tooter example, an async version of tweeter. --- examples/tooter.rs | 51 +++++++++++++++++++++++++++++++++++++++++++++ examples/tweeter.rs | 1 + 2 files changed, 52 insertions(+) create mode 100644 examples/tooter.rs diff --git a/examples/tooter.rs b/examples/tooter.rs new file mode 100644 index 0000000..aee8ab9 --- /dev/null +++ b/examples/tooter.rs @@ -0,0 +1,51 @@ +extern crate irc; +extern crate tokio_timer; + +use std::default::Default; +use std::time::Duration; +use irc::client::prelude::*; +use irc::error::IrcError; + +// NOTE: this example is a conversion of `tweeter.rs` to an asynchronous style with `IrcReactor`. +fn main() { + let config = Config { + nickname: Some("mastodon".to_owned()), + server: Some("irc.fyrechat.net".to_owned()), + channels: Some(vec!["#irc-crate".to_owned()]), + ..Default::default() + }; + + // We need to create a reactor first and foremost + let mut reactor = IrcReactor::new().unwrap(); + // and then create a client via its API. + let client = reactor.prepare_client_and_connect(&config).unwrap(); + // Then, we identify + client.identify().unwrap(); + // and clone just as before. + let send_client = client.clone(); + + // Rather than spawn a thread that reads the messages separately, we register a handler with the + // reactor. just as in the original version, we don't do any real handling and instead just print + // the messages that are received. + reactor.register_client_with_handler(client, |_, message| { + print!("{}", message); + Ok(()) + }); + + // We construct an interval using a wheel timer from tokio_timer. This interval will fire + // every 10 seconds (and is roughly accurate to the second). + let send_interval = tokio_timer::wheel() + .tick_duration(Duration::from_secs(1)) + .num_slots(256) + .build() + .interval(Duration::from_secs(10)); + + // And then spawn a new future that performs the given action each time it fires. + reactor.register_future(send_interval.map_err(IrcError::Timer).for_each(move |()| { + // Anything in here will happen every 10 seconds! + send_client.send_privmsg("#irc-crate", "TOOT TOOT") + })); + + // Then, on the main thread, we finally run the reactor which blocks the program indefinitely. + reactor.run().unwrap(); +} diff --git a/examples/tweeter.rs b/examples/tweeter.rs index 94de21a..830ca0d 100644 --- a/examples/tweeter.rs +++ b/examples/tweeter.rs @@ -5,6 +5,7 @@ use std::thread; use std::time::Duration; use irc::client::prelude::*; +// NOTE: you can find an asynchronous version of this example with `IrcReactor` in `tooter.rs`. fn main() { let config = Config { nickname: Some("pickles".to_owned()), From d4283f6071815104326250441401004df84d86a4 Mon Sep 17 00:00:00 2001 From: Aaron Weiss Date: Sun, 27 May 2018 23:24:37 +0200 Subject: [PATCH 03/19] Rewrapped comments in tooter.rs. --- examples/tooter.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/tooter.rs b/examples/tooter.rs index aee8ab9..42a2ad8 100644 --- a/examples/tooter.rs +++ b/examples/tooter.rs @@ -25,15 +25,15 @@ fn main() { let send_client = client.clone(); // Rather than spawn a thread that reads the messages separately, we register a handler with the - // reactor. just as in the original version, we don't do any real handling and instead just print - // the messages that are received. + // reactor. just as in the original version, we don't do any real handling and instead just + // print the messages that are received. reactor.register_client_with_handler(client, |_, message| { print!("{}", message); Ok(()) }); - // We construct an interval using a wheel timer from tokio_timer. This interval will fire - // every 10 seconds (and is roughly accurate to the second). + // We construct an interval using a wheel timer from tokio_timer. This interval will fire every + // ten seconds (and is roughly accurate to the second). let send_interval = tokio_timer::wheel() .tick_duration(Duration::from_secs(1)) .num_slots(256) From 791edb2bd724cb433efeaa6efc6b2b19e466b340 Mon Sep 17 00:00:00 2001 From: Aaron Weiss Date: Tue, 5 Jun 2018 20:04:06 +0200 Subject: [PATCH 04/19] Added a small optimization (suggested in tokio guide) to `LineCodec`. --- src/proto/line.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/proto/line.rs b/src/proto/line.rs index 2e1ade2..2c88d7e 100644 --- a/src/proto/line.rs +++ b/src/proto/line.rs @@ -12,13 +12,14 @@ use error; /// A line-based codec parameterized by an encoding. pub struct LineCodec { encoding: EncodingRef, + next_index: usize, } impl LineCodec { /// Creates a new instance of LineCodec from the specified encoding. pub fn new(label: &str) -> error::Result { encoding_from_whatwg_label(label) - .map(|enc| LineCodec { encoding: enc }) + .map(|enc| LineCodec { encoding: enc, next_index: 0 }) .ok_or_else(|| io::Error::new( io::ErrorKind::InvalidInput, &format!("Attempted to use unknown codec {}.", label)[..], @@ -31,9 +32,12 @@ impl Decoder for LineCodec { type Error = error::IrcError; fn decode(&mut self, src: &mut BytesMut) -> error::Result> { - if let Some(n) = src.as_ref().iter().position(|b| *b == b'\n') { + if let Some(offset) = src[self.next_index..].iter().position(|b| *b == b'\n') { // Remove the next frame from the buffer. - let line = src.split_to(n + 1); + let line = src.split_to(self.next_index + offset + 1); + + // Set the search start index back to 0 since we found a newline. + self.next_index = 0; // Decode the line using the codec's encoding. match self.encoding.decode(line.as_ref(), DecoderTrap::Replace) { @@ -46,6 +50,9 @@ impl Decoder for LineCodec { ), } } else { + // Set the search start index to the current length since we know that none of the + // characters we've already looked at are newlines. + self.next_index = src.len(); Ok(None) } } From 3aba7250b0cab774b497a230847e8c55d754b62d Mon Sep 17 00:00:00 2001 From: Aaron Weiss Date: Tue, 10 Jul 2018 03:36:18 +0200 Subject: [PATCH 05/19] Moved Travis CI bot to pdgn.co. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index be06bf3..a7e0d6a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ notifications: email: false irc: channels: - - "irc.fyrechat.net#vana-commits" + - "ircs://irc.pdgn.co:6697/#commits" template: - "%{repository_slug}/%{branch} (%{commit} - %{author}): %{message}" skip_join: true From b5b035faa75f79c63bb49fc71d907813216c214b Mon Sep 17 00:00:00 2001 From: Aaron Weiss Date: Tue, 10 Jul 2018 04:15:08 +0200 Subject: [PATCH 06/19] Switched all the examples to use #rust-spam on irc.mozilla.org. --- examples/multiserver.rs | 8 ++++---- examples/reactor.rs | 4 ++-- examples/reconnector.rs | 8 ++++---- examples/simple.rs | 4 ++-- examples/simple_ssl.rs | 4 ++-- examples/tooter.rs | 6 +++--- examples/tweeter.rs | 6 +++--- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/examples/multiserver.rs b/examples/multiserver.rs index c88311e..2e3bc27 100644 --- a/examples/multiserver.rs +++ b/examples/multiserver.rs @@ -7,15 +7,15 @@ use irc::client::prelude::*; fn main() { let cfg1 = Config { nickname: Some("pickles".to_owned()), - server: Some("irc.fyrechat.net".to_owned()), - channels: Some(vec!["#irc-crate".to_owned()]), + server: Some("irc.mozilla.org".to_owned()), + channels: Some(vec!["#rust-spam".to_owned()]), ..Default::default() }; let cfg2 = Config { nickname: Some("bananas".to_owned()), - server: Some("irc.fyrechat.net".to_owned()), - channels: Some(vec!["#irc-crate".to_owned()]), + server: Some("irc.mozilla.org".to_owned()), + channels: Some(vec!["#rust-spam".to_owned()]), ..Default::default() }; diff --git a/examples/reactor.rs b/examples/reactor.rs index 66dea6b..1a0d2b0 100644 --- a/examples/reactor.rs +++ b/examples/reactor.rs @@ -8,8 +8,8 @@ fn main() { let config = Config { nickname: Some("pickles".to_owned()), alt_nicks: Some(vec!["bananas".to_owned(), "apples".to_owned()]), - server: Some("irc.fyrechat.net".to_owned()), - channels: Some(vec!["#irc-crate".to_owned()]), + server: Some("irc.mozilla.org".to_owned()), + channels: Some(vec!["#rust-spam".to_owned()]), ..Default::default() }; diff --git a/examples/reconnector.rs b/examples/reconnector.rs index f879f48..da6fc8b 100644 --- a/examples/reconnector.rs +++ b/examples/reconnector.rs @@ -7,15 +7,15 @@ use irc::client::prelude::*; fn main() { let cfg1 = Config { nickname: Some("pickles".to_owned()), - server: Some("irc.fyrechat.net".to_owned()), - channels: Some(vec!["#irc-crate".to_owned()]), + server: Some("irc.mozilla.org".to_owned()), + channels: Some(vec!["#rust-spam".to_owned()]), ..Default::default() }; let cfg2 = Config { nickname: Some("bananas".to_owned()), - server: Some("irc.fyrechat.net".to_owned()), - channels: Some(vec!["#irc-crate".to_owned()]), + server: Some("irc.mozilla.org".to_owned()), + channels: Some(vec!["#rust-spam".to_owned()]), ..Default::default() }; diff --git a/examples/simple.rs b/examples/simple.rs index f6a621b..83bb777 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -7,8 +7,8 @@ fn main() { let config = Config { nickname: Some("pickles".to_owned()), alt_nicks: Some(vec!["bananas".to_owned(), "apples".to_owned()]), - server: Some("irc.fyrechat.net".to_owned()), - channels: Some(vec!["#irc-crate".to_owned()]), + server: Some("irc.mozilla.org".to_owned()), + channels: Some(vec!["#rust-spam".to_owned()]), ..Default::default() }; diff --git a/examples/simple_ssl.rs b/examples/simple_ssl.rs index 86ce6f3..201935a 100644 --- a/examples/simple_ssl.rs +++ b/examples/simple_ssl.rs @@ -6,8 +6,8 @@ use irc::client::prelude::*; fn main() { let config = Config { nickname: Some("pickles".to_owned()), - server: Some("irc.fyrechat.net".to_owned()), - channels: Some(vec!["#irc-crate".to_owned()]), + server: Some("irc.mozilla.org".to_owned()), + channels: Some(vec!["#rust-spam".to_owned()]), use_ssl: Some(true), ..Default::default() }; diff --git a/examples/tooter.rs b/examples/tooter.rs index 42a2ad8..409765c 100644 --- a/examples/tooter.rs +++ b/examples/tooter.rs @@ -10,8 +10,8 @@ use irc::error::IrcError; fn main() { let config = Config { nickname: Some("mastodon".to_owned()), - server: Some("irc.fyrechat.net".to_owned()), - channels: Some(vec!["#irc-crate".to_owned()]), + server: Some("irc.mozilla.org".to_owned()), + channels: Some(vec!["#rust-spam".to_owned()]), ..Default::default() }; @@ -43,7 +43,7 @@ fn main() { // And then spawn a new future that performs the given action each time it fires. reactor.register_future(send_interval.map_err(IrcError::Timer).for_each(move |()| { // Anything in here will happen every 10 seconds! - send_client.send_privmsg("#irc-crate", "TOOT TOOT") + send_client.send_privmsg("#rust-spam", "AWOOOOOOOOOO") })); // Then, on the main thread, we finally run the reactor which blocks the program indefinitely. diff --git a/examples/tweeter.rs b/examples/tweeter.rs index 830ca0d..824fab3 100644 --- a/examples/tweeter.rs +++ b/examples/tweeter.rs @@ -9,8 +9,8 @@ use irc::client::prelude::*; fn main() { let config = Config { nickname: Some("pickles".to_owned()), - server: Some("irc.fyrechat.net".to_owned()), - channels: Some(vec!["#irc-crate".to_owned()]), + server: Some("irc.mozilla.org".to_owned()), + channels: Some(vec!["#rust-spam".to_owned()]), ..Default::default() }; let client = IrcClient::from_config(config).unwrap(); @@ -21,7 +21,7 @@ fn main() { client2.stream().map(|m| print!("{}", m)).wait().count(); }); loop { - client.send_privmsg("#irc-crate", "TWEET TWEET").unwrap(); + client.send_privmsg("#rust-spam", "TWEET TWEET").unwrap(); thread::sleep(Duration::new(10, 0)); } } From 1abed4c5521acc3b651086271e1a9874ab573e2f Mon Sep 17 00:00:00 2001 From: Aaron Weiss Date: Wed, 8 Aug 2018 20:13:50 -0400 Subject: [PATCH 07/19] Removed some langauge that I don't like (simple, easy). --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 89a4b7b..d1f369d 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ [doc]: https://docs.rs/irc [rfc2812]: http://tools.ietf.org/html/rfc2812 -[ircv3.1]: http://ircv3.net/irc/3.1.html +[ircv3.1]: http://ircv3.net/irc/3.1.html [ircv3.2]: http://ircv3.net/irc/3.2.html "the irc crate" is a thread-safe and async-friendly IRC client library written in Rust. It's @@ -39,7 +39,7 @@ Making your own project? [Submit a pull request](https://github.com/aatxe/irc/pu ## Getting Started -To start using the irc crate with cargo, you can simply add `irc = "0.13"` to your dependencies in +To start using the irc crate with cargo, you can add `irc = "0.13"` to your dependencies in your Cargo.toml file. The high-level API can be found in [`irc::client::prelude`][irc-prelude]. You'll find a number of examples to help you get started in `examples/`, throughout the documentation, and below. @@ -72,7 +72,7 @@ fn main() { let mut reactor = IrcReactor::new().unwrap(); let client = reactor.prepare_client_and_connect(&config).unwrap(); client.identify().unwrap(); - + reactor.register_client_with_handler(client, |client, message| { print!("{}", message); // And here we can do whatever we want with the messages. @@ -173,8 +173,8 @@ You can convert between different configuration formats with `convertconf` like cargo run --example convertconf -- -i client_config.json -o client_config.toml ``` -Note that the formats are automatically determined based on the selected file extensions. This -tool should make it easy for users to migrate their old configurations to TOML. +Note that the formats are automatically determined based on the selected file extensions. This +tool should make it easier for users to migrate their old configurations to TOML. ## Contributing the irc crate is a free, open source library that relies on contributions from its maintainers, From abbf1eafcb29ce1253ffac5d251e338ed2b01843 Mon Sep 17 00:00:00 2001 From: Aaron Weiss Date: Thu, 16 Aug 2018 12:18:05 -0400 Subject: [PATCH 08/19] Added notes for PRIVMSG and NOTICE about responses (re: #144). --- src/proto/command.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/proto/command.rs b/src/proto/command.rs index f0ec551..022e886 100644 --- a/src/proto/command.rs +++ b/src/proto/command.rs @@ -49,8 +49,32 @@ pub enum Command { // 3.3 Sending messages /// PRIVMSG msgtarget :message + /// + /// ## Responding to a `PRIVMSG` + /// + /// When responding to a message, it is not sufficient to simply copy the message target + /// (msgtarget). This will work just fine for responding to messages in channels where the + /// target is the same for all participants. However, when the message is sent directly to a + /// user, this target will be that client's username, and responding to that same target will + /// actually mean sending itself a response. In such a case, you should instead respond to the + /// user sending the message as specified in the message prefix. Since this is a common + /// pattern, there is a utility function + /// [`Message::response_target`](../message/struct.Message.html#method.response_target) + /// which is used for this exact purpose. PRIVMSG(String, String), /// NOTICE msgtarget :message + /// + /// ## Responding to a `NOTICE` + /// + /// When responding to a notice, it is not sufficient to simply copy the message target + /// (msgtarget). This will work just fine for responding to messages in channels where the + /// target is the same for all participants. However, when the message is sent directly to a + /// user, this target will be that client's username, and responding to that same target will + /// actually mean sending itself a response. In such a case, you should instead respond to the + /// user sending the message as specified in the message prefix. Since this is a common + /// pattern, there is a utility function + /// [`Message::response_target`](../message/struct.Message.html#method.response_target) + /// which is used for this exact purpose. NOTICE(String, String), // 3.4 Server queries and commands From 6f2820d7f68b6396fd1324ce4c6dea19e90c2be9 Mon Sep 17 00:00:00 2001 From: Eunchong Yu Date: Sun, 19 Aug 2018 08:45:15 +0900 Subject: [PATCH 09/19] Upgrade log to 0.4 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 61165ae..65c5486 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ chrono = "0.4" encoding = "0.2" failure = "0.1" futures = "0.1" -log = "0.3" +log = "0.4" native-tls = "0.1" serde = "1.0" serde_derive = "1.0" From 12003c880ca7f8fec8ca320470a220fc447e7118 Mon Sep 17 00:00:00 2001 From: Eunchong Yu Date: Sun, 19 Aug 2018 08:50:38 +0900 Subject: [PATCH 10/19] Remove deprecated AsciiExt --- src/client/mod.rs | 2 -- src/proto/command.rs | 1 - 2 files changed, 3 deletions(-) diff --git a/src/client/mod.rs b/src/client/mod.rs index 0a05f56..258c94b 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -45,8 +45,6 @@ //! # } //! ``` -#[cfg(feature = "ctcp")] -use std::ascii::AsciiExt; use std::collections::HashMap; use std::path::Path; use std::sync::{Arc, Mutex, RwLock}; diff --git a/src/proto/command.rs b/src/proto/command.rs index 022e886..10af3ea 100644 --- a/src/proto/command.rs +++ b/src/proto/command.rs @@ -1,5 +1,4 @@ //! Enumeration of all available client commands. -use std::ascii::AsciiExt; use std::str::FromStr; use error::MessageParseError; From 1cf77441560bab4c789e59cb38471c4b68838960 Mon Sep 17 00:00:00 2001 From: Eunchong Yu Date: Sun, 19 Aug 2018 08:54:22 +0900 Subject: [PATCH 11/19] Clarify to prevent unintended recursions --- src/proto/colors.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/proto/colors.rs b/src/proto/colors.rs index 6ffb492..ba2afb3 100644 --- a/src/proto/colors.rs +++ b/src/proto/colors.rs @@ -102,10 +102,10 @@ impl FormattedStringExt for str { impl FormattedStringExt for String { fn is_formatted(&self) -> bool { - (&self).is_formatted() + (&self[..]).is_formatted() } fn strip_formatting(&self) -> Cow { - (&self).strip_formatting() + (&self[..]).strip_formatting() } } From 8ffac6bef05415efa90c02e6b43a1ef069914cf5 Mon Sep 17 00:00:00 2001 From: Eunchong Yu Date: Sun, 19 Aug 2018 09:18:50 +0900 Subject: [PATCH 12/19] Replace deprecated tokio_io::codec to tokio_codec --- Cargo.toml | 1 + src/client/conn.rs | 11 +++++++---- src/client/transport.rs | 2 +- src/lib.rs | 1 + src/proto/irc.rs | 2 +- 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 65c5486..b39910c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,7 @@ serde = "1.0" serde_derive = "1.0" serde_json = { version = "1.0", optional = true } serde_yaml = { version = "0.7", optional = true } +tokio-codec = "0.1" tokio-core = "0.1" tokio-io = "0.1" tokio-mockstream = "1.1" diff --git a/src/client/conn.rs b/src/client/conn.rs index e9552d2..1d90230 100644 --- a/src/client/conn.rs +++ b/src/client/conn.rs @@ -7,9 +7,9 @@ use encoding::EncoderTrap; use encoding::label::encoding_from_whatwg_label; use futures::{Async, Poll, Future, Sink, StartSend, Stream}; use native_tls::{Certificate, TlsConnector, Pkcs12}; +use tokio_codec::Decoder; use tokio_core::reactor::Handle; use tokio_core::net::{TcpStream, TcpStreamNew}; -use tokio_io::AsyncRead; use tokio_mockstream::MockStream; use tokio_tls::{TlsConnectorExt, TlsStream}; @@ -81,13 +81,15 @@ impl<'a> Future for ConnectionFuture<'a> { fn poll(&mut self) -> Poll { match *self { ConnectionFuture::Unsecured(config, ref mut inner) => { - let framed = try_ready!(inner.poll()).framed(IrcCodec::new(config.encoding())?); + let stream = try_ready!(inner.poll()); + let framed = IrcCodec::new(config.encoding())?.framed(stream); let transport = IrcTransport::new(config, framed); Ok(Async::Ready(Connection::Unsecured(transport))) } ConnectionFuture::Secured(config, ref mut inner) => { - let framed = try_ready!(inner.poll()).framed(IrcCodec::new(config.encoding())?); + let stream = try_ready!(inner.poll()); + let framed = IrcCodec::new(config.encoding())?.framed(stream); let transport = IrcTransport::new(config, framed); Ok(Async::Ready(Connection::Secured(transport))) @@ -109,7 +111,8 @@ impl<'a> Future for ConnectionFuture<'a> { }) }; - let framed = MockStream::new(&initial?).framed(IrcCodec::new(config.encoding())?); + let stream = MockStream::new(&initial?); + let framed = IrcCodec::new(config.encoding())?.framed(stream); let transport = IrcTransport::new(config, framed); Ok(Async::Ready(Connection::Mock(Logged::wrap(transport)))) diff --git a/src/client/transport.rs b/src/client/transport.rs index 39dc2e5..a05f594 100644 --- a/src/client/transport.rs +++ b/src/client/transport.rs @@ -6,8 +6,8 @@ use std::time::{Duration, Instant}; use futures::{Async, AsyncSink, Future, Poll, Sink, StartSend, Stream}; use chrono::prelude::*; +use tokio_codec::Framed; use tokio_io::{AsyncRead, AsyncWrite}; -use tokio_io::codec::Framed; use tokio_timer; use tokio_timer::{Interval, Sleep, Timer}; diff --git a/src/lib.rs b/src/lib.rs index 3c9d32d..ed5f542 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,6 +58,7 @@ extern crate serde_derive; extern crate serde_json; #[cfg(feature = "yaml")] extern crate serde_yaml; +extern crate tokio_codec; extern crate tokio_core; extern crate tokio_io; extern crate tokio_mockstream; diff --git a/src/proto/irc.rs b/src/proto/irc.rs index e10ae27..e87c322 100644 --- a/src/proto/irc.rs +++ b/src/proto/irc.rs @@ -1,6 +1,6 @@ //! Implementation of IRC codec for Tokio. use bytes::BytesMut; -use tokio_io::codec::{Decoder, Encoder}; +use tokio_codec::{Decoder, Encoder}; use error; use proto::line::LineCodec; From c7c65ef671852e872d7d7202db5b1fb906aebfa7 Mon Sep 17 00:00:00 2001 From: Eunchong Yu Date: Sun, 19 Aug 2018 10:39:20 +0900 Subject: [PATCH 13/19] Fix infinite recursive calls It reverts #137. --- src/proto/colors.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/proto/colors.rs b/src/proto/colors.rs index ba2afb3..8e20e33 100644 --- a/src/proto/colors.rs +++ b/src/proto/colors.rs @@ -102,10 +102,10 @@ impl FormattedStringExt for str { impl FormattedStringExt for String { fn is_formatted(&self) -> bool { - (&self[..]).is_formatted() + self.as_str().is_formatted() } fn strip_formatting(&self) -> Cow { - (&self[..]).strip_formatting() + self.as_str().strip_formatting() } } @@ -117,6 +117,10 @@ mod test { fn test_strip_bold() { assert_eq!("l\x02ol".strip_formatting(), "lol"); } + #[test] + fn test_strip_bold_from_string() { + assert_eq!(String::from("l\x02ol").strip_formatting(), "lol"); + } #[test] fn test_strip_fg_color() { From 4feafc681a581373fb6954a8eb5d635573e632fc Mon Sep 17 00:00:00 2001 From: Eunchong Yu Date: Sun, 19 Aug 2018 10:58:36 +0900 Subject: [PATCH 14/19] Reduce memcpy case in strip_formatting This makes the return type of FormattedStringExt::strip_formatting more meaningful. Drawbacks: In theory, it breaks backward compatbility due to the shape of FormattedStringExt trait was changed. But I expected it's not the problem for the most case because it's rare to implement that trait while using this library. --- src/proto/colors.rs | 45 ++++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/src/proto/colors.rs b/src/proto/colors.rs index 8e20e33..6836073 100644 --- a/src/proto/colors.rs +++ b/src/proto/colors.rs @@ -15,18 +15,18 @@ struct Parser { } /// An extension trait giving strings a function to strip IRC colors -pub trait FormattedStringExt { +pub trait FormattedStringExt<'a> { /// Returns true if the string contains color, bold, underline or italics fn is_formatted(&self) -> bool; /// Returns the string with all color, bold, underline and italics stripped - fn strip_formatting(&self) -> Cow; + fn strip_formatting(self) -> Cow<'a, str>; } -impl FormattedStringExt for str { +impl<'a> FormattedStringExt<'a> for &'a str { fn is_formatted(&self) -> bool { self.contains('\x02') || // bold self.contains('\x1F') || // underline @@ -35,12 +35,22 @@ impl FormattedStringExt for str { self.contains('\x03') // color } - fn strip_formatting(&self) -> Cow { + fn strip_formatting(self) -> Cow<'a, str> { + if !self.is_formatted() { + return Cow::Borrowed(self); + } + Cow::Owned(internal::strip_formatting(self)) + } +} + +mod internal { // to reduce commit diff + use super::*; + pub(super) fn strip_formatting(input: &str) -> String { let mut parser = Parser { state: ParserState::Text, }; let mut prev: char = '\x00'; - let result: Cow = self + input .chars() .filter(move |cur| { let result = match parser.state { @@ -92,25 +102,25 @@ impl FormattedStringExt for str { prev = *cur; return result }) - .collect(); - - result + .collect() } - - } -impl FormattedStringExt for String { +impl FormattedStringExt<'static> for String { fn is_formatted(&self) -> bool { self.as_str().is_formatted() } - fn strip_formatting(&self) -> Cow { - self.as_str().strip_formatting() + fn strip_formatting(self) -> Cow<'static, str> { + if !self.is_formatted() { + return Cow::Owned(self); + } + Cow::Owned(internal::strip_formatting(&self)) } } #[cfg(test)] mod test { + use std::borrow::Cow; use proto::colors::FormattedStringExt; #[test] @@ -164,4 +174,13 @@ mod test { fn test_strip_string_with_digit_after_2digit_color() { assert_eq!("\x031212\x031111\x031010".strip_formatting(), "121110"); } + + #[test] + fn test_strip_no_allocation_for_unformatted_text() { + if let Cow::Borrowed(formatted) = "plain text".strip_formatting() { + assert_eq!(formatted, "plain text"); + } else { + panic!("allocation detected"); + } + } } From b108c833bb5b7b12ce59b9569d818d6e34fe16cf Mon Sep 17 00:00:00 2001 From: Eunchong Yu Date: Sun, 19 Aug 2018 11:28:45 +0900 Subject: [PATCH 15/19] Reduce allocation more String::strip_formatting will do most of operations in place. --- src/proto/colors.rs | 123 +++++++++++++++++++++----------------------- 1 file changed, 60 insertions(+), 63 deletions(-) diff --git a/src/proto/colors.rs b/src/proto/colors.rs index 6836073..c53470f 100644 --- a/src/proto/colors.rs +++ b/src/proto/colors.rs @@ -39,82 +39,79 @@ impl<'a> FormattedStringExt<'a> for &'a str { if !self.is_formatted() { return Cow::Borrowed(self); } - Cow::Owned(internal::strip_formatting(self)) + let mut s = String::from(self); + strip_formatting(&mut s); + Cow::Owned(s) } } -mod internal { // to reduce commit diff - use super::*; - pub(super) fn strip_formatting(input: &str) -> String { - let mut parser = Parser { - state: ParserState::Text, +fn strip_formatting(buf: &mut String) { + let mut parser = Parser { + state: ParserState::Text, + }; + let mut prev: char = '\x00'; + buf.retain(|cur| { + let result = match parser.state { + ParserState::Text | ParserState::Foreground1 | ParserState::Foreground2 if cur == '\x03' => { + parser.state = ParserState::ColorCode; + false + }, + ParserState::Text => !['\x02', '\x1F', '\x16', '\x0F'].contains(&cur), + ParserState::ColorCode if cur.is_digit(10) => { + parser.state = ParserState::Foreground1; + false + }, + ParserState::Foreground1 if cur.is_digit(6) => { + // can only consume another digit if previous char was 1. + if prev == '1' { + parser.state = ParserState::Foreground2; + false + } else { + parser.state = ParserState::Text; + true + } + }, + ParserState::Foreground1 if cur == ',' => { + parser.state = ParserState::Comma; + false + }, + ParserState::Foreground2 if cur == ',' => { + parser.state = ParserState::Comma; + false + }, + ParserState::Comma if (cur.is_digit(10)) => { + parser.state = ParserState::Background1; + false + }, + ParserState::Background1 if cur.is_digit(6) => { + // can only consume another digit if previous char was 1. + parser.state = ParserState::Text; + if prev == '1' { + false + } else { + true + } + } + _ => { + parser.state = ParserState::Text; + true + } }; - let mut prev: char = '\x00'; - input - .chars() - .filter(move |cur| { - let result = match parser.state { - ParserState::Text | ParserState::Foreground1 | ParserState::Foreground2 if *cur == '\x03' => { - parser.state = ParserState::ColorCode; - false - }, - ParserState::Text => !['\x02', '\x1F', '\x16', '\x0F'].contains(cur), - ParserState::ColorCode if (*cur).is_digit(10) => { - parser.state = ParserState::Foreground1; - false - }, - ParserState::Foreground1 if (*cur).is_digit(6) => { - // can only consume another digit if previous char was 1. - if (prev) == '1' { - parser.state = ParserState::Foreground2; - false - } else { - parser.state = ParserState::Text; - true - } - }, - ParserState::Foreground1 if *cur == ',' => { - parser.state = ParserState::Comma; - false - }, - ParserState::Foreground2 if *cur == ',' => { - parser.state = ParserState::Comma; - false - }, - ParserState::Comma if ((*cur).is_digit(10)) => { - parser.state = ParserState::Background1; - false - }, - ParserState::Background1 if (*cur).is_digit(6) => { - // can only consume another digit if previous char was 1. - parser.state = ParserState::Text; - if (prev) == '1' { - false - } else { - true - } - } - _ => { - parser.state = ParserState::Text; - true - } - }; - prev = *cur; - return result - }) - .collect() - } + prev = cur; + return result + }); } impl FormattedStringExt<'static> for String { fn is_formatted(&self) -> bool { self.as_str().is_formatted() } - fn strip_formatting(self) -> Cow<'static, str> { + fn strip_formatting(mut self) -> Cow<'static, str> { if !self.is_formatted() { return Cow::Owned(self); } - Cow::Owned(internal::strip_formatting(&self)) + strip_formatting(&mut self); + Cow::Owned(self) } } From e7fe08f29dce6a718c4f337710b6377c5fd0dce6 Mon Sep 17 00:00:00 2001 From: Eunchong Yu Date: Sun, 19 Aug 2018 11:38:34 +0900 Subject: [PATCH 16/19] Make is_formatted simple --- src/proto/colors.rs | 88 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 82 insertions(+), 6 deletions(-) diff --git a/src/proto/colors.rs b/src/proto/colors.rs index c53470f..58c32bf 100644 --- a/src/proto/colors.rs +++ b/src/proto/colors.rs @@ -25,14 +25,17 @@ pub trait FormattedStringExt<'a> { } +const FORMAT_CHARACTERS: &[char] = &[ + '\x02', // bold + '\x1F', // underline + '\x16', // reverse + '\x0F', // normal + '\x03', // color +]; impl<'a> FormattedStringExt<'a> for &'a str { fn is_formatted(&self) -> bool { - self.contains('\x02') || // bold - self.contains('\x1F') || // underline - self.contains('\x16') || // reverse - self.contains('\x0F') || // normal - self.contains('\x03') // color + self.contains(FORMAT_CHARACTERS) } fn strip_formatting(self) -> Cow<'a, str> { @@ -56,7 +59,7 @@ fn strip_formatting(buf: &mut String) { parser.state = ParserState::ColorCode; false }, - ParserState::Text => !['\x02', '\x1F', '\x16', '\x0F'].contains(&cur), + ParserState::Text => !FORMAT_CHARACTERS.contains(&cur), ParserState::ColorCode if cur.is_digit(10) => { parser.state = ParserState::Foreground1; false @@ -120,6 +123,79 @@ mod test { use std::borrow::Cow; use proto::colors::FormattedStringExt; + #[test] + fn test_is_formatted_blank() { + assert!(!"".is_formatted()); + } + #[test] + fn test_is_formatted_blank2() { + assert!(!" ".is_formatted()); + } + #[test] + fn test_is_formatted_blank3() { + assert!(!"\t\r\n".is_formatted()); + } + #[test] + fn test_is_formatted_bold() { + assert!("l\x02ol".is_formatted()); + } + #[test] + fn test_is_formatted_fg_color() { + assert!("l\x033ol".is_formatted()); + } + #[test] + fn test_is_formatted_fg_color2() { + assert!("l\x0312ol".is_formatted()); + } + #[test] + fn test_is_formatted_fg_bg_11() { + assert!("l\x031,2ol".is_formatted()); + } + #[test] + fn test_is_formatted_fg_bg_21() { + assert!("l\x0312,3ol".is_formatted()); + } + #[test] + fn test_is_formatted_fg_bg_12() { + assert!("l\x031,12ol".is_formatted()); + } + #[test] + fn test_is_formatted_fg_bg_22() { + assert!("l\x0312,13ol".is_formatted()); + } + #[test] + fn test_is_formatted_string_with_multiple_colors() { + assert!("hoo\x034r\x033a\x0312y".is_formatted()); + } + #[test] + fn test_is_formatted_string_with_digit_after_color() { + assert!("\x0344\x0355\x0366".is_formatted()); + } + #[test] + fn test_is_formatted_string_with_multiple_2digit_colors() { + assert!("hoo\x0310r\x0311a\x0312y".is_formatted()); + } + #[test] + fn test_is_formatted_string_with_digit_after_2digit_color() { + assert!("\x031212\x031111\x031010".is_formatted()); + } + #[test] + fn test_is_formatted_unformatted() { + assert!(!"a plain text".is_formatted()); + } + + #[test] + fn test_strip_blank() { + assert_eq!("".strip_formatting(), ""); + } + #[test] + fn test_strip_blank2() { + assert_eq!(" ".strip_formatting(), " "); + } + #[test] + fn test_strip_blank3() { + assert_eq!("\t\r\n".strip_formatting(), "\t\r\n"); + } #[test] fn test_strip_bold() { assert_eq!("l\x02ol".strip_formatting(), "lol"); From c311d37902caf0750f3100b8dabed859317a8c8e Mon Sep 17 00:00:00 2001 From: Eunchong Yu Date: Sun, 19 Aug 2018 12:14:25 +0900 Subject: [PATCH 17/19] Use macro --- src/proto/colors.rs | 169 +++++++++++++------------------------------- 1 file changed, 48 insertions(+), 121 deletions(-) diff --git a/src/proto/colors.rs b/src/proto/colors.rs index 58c32bf..c8eb052 100644 --- a/src/proto/colors.rs +++ b/src/proto/colors.rs @@ -123,129 +123,56 @@ mod test { use std::borrow::Cow; use proto::colors::FormattedStringExt; - #[test] - fn test_is_formatted_blank() { - assert!(!"".is_formatted()); - } - #[test] - fn test_is_formatted_blank2() { - assert!(!" ".is_formatted()); - } - #[test] - fn test_is_formatted_blank3() { - assert!(!"\t\r\n".is_formatted()); - } - #[test] - fn test_is_formatted_bold() { - assert!("l\x02ol".is_formatted()); - } - #[test] - fn test_is_formatted_fg_color() { - assert!("l\x033ol".is_formatted()); - } - #[test] - fn test_is_formatted_fg_color2() { - assert!("l\x0312ol".is_formatted()); - } - #[test] - fn test_is_formatted_fg_bg_11() { - assert!("l\x031,2ol".is_formatted()); - } - #[test] - fn test_is_formatted_fg_bg_21() { - assert!("l\x0312,3ol".is_formatted()); - } - #[test] - fn test_is_formatted_fg_bg_12() { - assert!("l\x031,12ol".is_formatted()); - } - #[test] - fn test_is_formatted_fg_bg_22() { - assert!("l\x0312,13ol".is_formatted()); - } - #[test] - fn test_is_formatted_string_with_multiple_colors() { - assert!("hoo\x034r\x033a\x0312y".is_formatted()); - } - #[test] - fn test_is_formatted_string_with_digit_after_color() { - assert!("\x0344\x0355\x0366".is_formatted()); - } - #[test] - fn test_is_formatted_string_with_multiple_2digit_colors() { - assert!("hoo\x0310r\x0311a\x0312y".is_formatted()); - } - #[test] - fn test_is_formatted_string_with_digit_after_2digit_color() { - assert!("\x031212\x031111\x031010".is_formatted()); - } - #[test] - fn test_is_formatted_unformatted() { - assert!(!"a plain text".is_formatted()); + macro_rules! test_formatted_string_ext { + { $( $name:ident ( $($line:tt)* ), )* } => { + $( + mod $name { + use super::*; + test_formatted_string_ext!(@ $($line)*); + } + )* + }; + (@ $text:expr, should stripped into $expected:expr) => { + #[test] + fn test_formatted() { + assert!($text.is_formatted()); + } + #[test] + fn test_strip() { + assert_eq!($text.strip_formatting(), $expected); + } + }; + (@ $text:expr, is not formatted) => { + #[test] + fn test_formatted() { + assert!(!$text.is_formatted()); + } + #[test] + fn test_strip() { + assert_eq!($text.strip_formatting(), $text); + } + } } - #[test] - fn test_strip_blank() { - assert_eq!("".strip_formatting(), ""); - } - #[test] - fn test_strip_blank2() { - assert_eq!(" ".strip_formatting(), " "); - } - #[test] - fn test_strip_blank3() { - assert_eq!("\t\r\n".strip_formatting(), "\t\r\n"); - } - #[test] - fn test_strip_bold() { - assert_eq!("l\x02ol".strip_formatting(), "lol"); - } - #[test] - fn test_strip_bold_from_string() { - assert_eq!(String::from("l\x02ol").strip_formatting(), "lol"); - } - - #[test] - fn test_strip_fg_color() { - assert_eq!("l\x033ol".strip_formatting(), "lol"); - } - - #[test] - fn test_strip_fg_color2() { - assert_eq!("l\x0312ol".strip_formatting(), "lol"); - } - - #[test] - fn test_strip_fg_bg_11() { - assert_eq!("l\x031,2ol".strip_formatting(), "lol"); - } - #[test] - fn test_strip_fg_bg_21() { - assert_eq!("l\x0312,3ol".strip_formatting(), "lol"); - } - #[test] - fn test_strip_fg_bg_12() { - assert_eq!("l\x031,12ol".strip_formatting(), "lol"); - } - #[test] - fn test_strip_fg_bg_22() { - assert_eq!("l\x0312,13ol".strip_formatting(), "lol"); - } - #[test] - fn test_strip_string_with_multiple_colors() { - assert_eq!("hoo\x034r\x033a\x0312y".strip_formatting(), "hooray"); - } - #[test] - fn test_strip_string_with_digit_after_color() { - assert_eq!("\x0344\x0355\x0366".strip_formatting(), "456"); - } - #[test] - fn test_strip_string_with_multiple_2digit_colors() { - assert_eq!("hoo\x0310r\x0311a\x0312y".strip_formatting(), "hooray"); - } - #[test] - fn test_strip_string_with_digit_after_2digit_color() { - assert_eq!("\x031212\x031111\x031010".strip_formatting(), "121110"); + test_formatted_string_ext! { + blank("", is not formatted), + blank2(" ", is not formatted), + blank3("\t\r\n", is not formatted), + bold("l\x02ol", should stripped into "lol"), + bold_from_string(String::from("l\x02ol"), should stripped into "lol"), + bold_hangul("우왕\x02굳", should stripped into "우왕굳"), + fg_color("l\x033ol", should stripped into "lol"), + fg_color2("l\x0312ol", should stripped into "lol"), + fg_bg_11("l\x031,2ol", should stripped into "lol"), + fg_bg_21("l\x0312,3ol", should stripped into "lol"), + fg_bg_12("l\x031,12ol", should stripped into "lol"), + fg_bg_22("l\x0312,13ol", should stripped into "lol"), + string_with_multiple_colors("hoo\x034r\x033a\x0312y", should stripped into "hooray"), + string_with_digit_after_color("\x0344\x0355\x0366", should stripped into "456"), + string_with_multiple_2digit_colors("hoo\x0310r\x0311a\x0312y", should stripped into "hooray"), + string_with_digit_after_2digit_color("\x031212\x031111\x031010", should stripped into "121110"), + thinking("🤔...", is not formatted), + unformatted("a plain text", is not formatted), } #[test] From 8d07c117bb149fb8e3bf3e6ea6213c2054176b1b Mon Sep 17 00:00:00 2001 From: Eunchong Yu Date: Sun, 19 Aug 2018 12:36:16 +0900 Subject: [PATCH 18/19] Polish the parser --- src/proto/colors.rs | 108 ++++++++++++++++++++++---------------------- 1 file changed, 55 insertions(+), 53 deletions(-) diff --git a/src/proto/colors.rs b/src/proto/colors.rs index c8eb052..d70fb12 100644 --- a/src/proto/colors.rs +++ b/src/proto/colors.rs @@ -1,14 +1,13 @@ //! An extension trait that provides the ability to strip IRC colors from a string use std::borrow::Cow; -#[derive(PartialEq)] enum ParserState { Text, ColorCode, - Foreground1, + Foreground1(char), Foreground2, Comma, - Background1, + Background1(char), } struct Parser { state: ParserState, @@ -49,60 +48,63 @@ impl<'a> FormattedStringExt<'a> for &'a str { } fn strip_formatting(buf: &mut String) { - let mut parser = Parser { - state: ParserState::Text, - }; - let mut prev: char = '\x00'; - buf.retain(|cur| { - let result = match parser.state { - ParserState::Text | ParserState::Foreground1 | ParserState::Foreground2 if cur == '\x03' => { - parser.state = ParserState::ColorCode; + let mut parser = Parser::new(); + buf.retain(|cur| parser.next(cur)); +} + +impl Parser { + fn new() -> Self { + Parser { + state: ParserState::Text, + } + } + + fn next(&mut self, cur: char) -> bool { + use self::ParserState::*; + match self.state { + Text | Foreground1(_) | Foreground2 if cur == '\x03' => { + self.state = ColorCode; false - }, - ParserState::Text => !FORMAT_CHARACTERS.contains(&cur), - ParserState::ColorCode if cur.is_digit(10) => { - parser.state = ParserState::Foreground1; - false - }, - ParserState::Foreground1 if cur.is_digit(6) => { - // can only consume another digit if previous char was 1. - if prev == '1' { - parser.state = ParserState::Foreground2; - false - } else { - parser.state = ParserState::Text; - true - } - }, - ParserState::Foreground1 if cur == ',' => { - parser.state = ParserState::Comma; - false - }, - ParserState::Foreground2 if cur == ',' => { - parser.state = ParserState::Comma; - false - }, - ParserState::Comma if (cur.is_digit(10)) => { - parser.state = ParserState::Background1; - false - }, - ParserState::Background1 if cur.is_digit(6) => { - // can only consume another digit if previous char was 1. - parser.state = ParserState::Text; - if prev == '1' { - false - } else { - true - } } - _ => { - parser.state = ParserState::Text; + Text => { + !FORMAT_CHARACTERS.contains(&cur) + } + ColorCode if cur.is_digit(10) => { + self.state = Foreground1(cur); + false + } + Foreground1('1') if cur.is_digit(6) => { + // can only consume another digit if previous char was 1. + self.state = Foreground2; + false + } + Foreground1(_) if cur.is_digit(6) => { + self.state = Text; true } - }; - prev = cur; - return result - }); + Foreground1(_) if cur == ',' => { + self.state = Comma; + false + } + Foreground2 if cur == ',' => { + self.state = Comma; + false + } + Comma if (cur.is_digit(10)) => { + self.state = Background1(cur); + false + } + Background1(prev) if cur.is_digit(6) => { + // can only consume another digit if previous char was 1. + self.state = Text; + prev != '1' + } + _ => { + self.state = Text; + true + } + } + } } impl FormattedStringExt<'static> for String { From 0be5cb26c876f8ac0033616b4b09a48920101e7c Mon Sep 17 00:00:00 2001 From: Jokler Date: Mon, 17 Sep 2018 02:11:25 +0200 Subject: [PATCH 19/19] Upgrade native-tls and tokio-tls to 0.2 --- Cargo.toml | 4 ++-- src/client/conn.rs | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b39910c..ec2db0c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,7 @@ encoding = "0.2" failure = "0.1" futures = "0.1" log = "0.4" -native-tls = "0.1" +native-tls = "0.2" serde = "1.0" serde_derive = "1.0" serde_json = { version = "1.0", optional = true } @@ -40,7 +40,7 @@ tokio-core = "0.1" tokio-io = "0.1" tokio-mockstream = "1.1" tokio-timer = "0.1" -tokio-tls = "0.1" +tokio-tls = "0.2" toml = { version = "0.4", optional = true } [dev-dependencies] diff --git a/src/client/conn.rs b/src/client/conn.rs index 1d90230..3c8ea22 100644 --- a/src/client/conn.rs +++ b/src/client/conn.rs @@ -6,12 +6,12 @@ use std::io::Read; use encoding::EncoderTrap; use encoding::label::encoding_from_whatwg_label; use futures::{Async, Poll, Future, Sink, StartSend, Stream}; -use native_tls::{Certificate, TlsConnector, Pkcs12}; +use native_tls::{Certificate, TlsConnector, Identity}; use tokio_codec::Decoder; use tokio_core::reactor::Handle; use tokio_core::net::{TcpStream, TcpStreamNew}; use tokio_mockstream::MockStream; -use tokio_tls::{TlsConnectorExt, TlsStream}; +use tokio_tls::{self, TlsStream}; use error; use client::data::Config; @@ -129,13 +129,13 @@ impl Connection { } else if config.use_ssl() { let domain = format!("{}", config.server()?); info!("Connecting via SSL to {}.", domain); - let mut builder = TlsConnector::builder()?; + let mut builder = TlsConnector::builder(); if let Some(cert_path) = config.cert_path() { let mut file = File::open(cert_path)?; let mut cert_data = vec![]; file.read_to_end(&mut cert_data)?; let cert = Certificate::from_der(&cert_data)?; - builder.add_root_certificate(cert)?; + builder.add_root_certificate(cert); info!("Added {} to trusted certificates.", cert_path); } if let Some(client_cert_path) = config.client_cert_path() { @@ -143,16 +143,16 @@ impl Connection { let mut file = File::open(client_cert_path)?; let mut client_cert_data = vec![]; file.read_to_end(&mut client_cert_data)?; - let pkcs12_archive = Pkcs12::from_der(&client_cert_data, &client_cert_pass)?; - builder.identity(pkcs12_archive)?; + let pkcs12_archive = Identity::from_pkcs12(&client_cert_data, &client_cert_pass)?; + builder.identity(pkcs12_archive); info!("Using {} for client certificate authentication.", client_cert_path); } - let connector = builder.build()?; + let connector: tokio_tls::TlsConnector = builder.build()?.into(); let stream = Box::new(TcpStream::connect(&config.socket_addr()?, handle).map_err(|e| { let res: error::IrcError = e.into(); res }).and_then(move |socket| { - connector.connect_async(&domain, socket).map_err( + connector.connect(&domain, socket).map_err( |e| e.into(), ) }));