From 67cca339a76b2cc9ad0027cd3636d97c4729ec18 Mon Sep 17 00:00:00 2001 From: Aaron Weiss Date: Sat, 27 Jan 2018 19:50:48 +0100 Subject: [PATCH] Eliminated a panic that can occur when using IrcServerFuture, and recommend using IrcReactor instead. --- src/client/reactor.rs | 17 ++++++++++------- src/client/server/mod.rs | 36 +++++++++++++++++++++++------------- 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/src/client/reactor.rs b/src/client/reactor.rs index bd54033..48e9aca 100644 --- a/src/client/reactor.rs +++ b/src/client/reactor.rs @@ -1,10 +1,10 @@ //! A system for creating and managing IRC server connections. //! //! This API provides the ability to create and manage multiple IRC servers that can run on the same -//! thread through the use of a shared event loop. It also replaces the old functionality of -//! `IrcServer::new_future` and better encapsulates dependencies on `tokio` and `futures`. Finally, -//! it provides some escape hatches that let advanced users take advantage of these dependencies -//! regardless. +//! thread through the use of a shared event loop. It can also be used to encapsulate the dependency +//! on `tokio` and `futures` in the use of `IrcServer::new_future`. This means that knowledge of +//! those libraries should be unnecessary for the average user. Nevertheless, this API also provides +//! some escape hatches that let advanced users take further advantage of these dependencies. //! //! # Example //! ```no_run @@ -28,7 +28,7 @@ use futures::future; use tokio_core::reactor::{Core, Handle}; use client::data::Config; -use client::server::{IrcServer, IrcServerFuture, Server}; +use client::server::{IrcServer, IrcServerFuture, PackedIrcServer, Server}; use error; use proto::Message; @@ -70,7 +70,7 @@ impl IrcReactor { /// # } /// ``` pub fn prepare_server<'a>(&mut self, config: &'a Config) -> error::Result> { - IrcServer::new_future(self.inner.handle(), config) + IrcServer::new_future(self.inner_handle(), config) } /// Runs an [IrcServerFuture](./server/struct.IrcServerFuture.html), such as one from @@ -91,7 +91,10 @@ impl IrcReactor { /// # } /// ``` pub fn connect_server(&mut self, future: IrcServerFuture) -> error::Result { - self.inner.run(future) + self.inner.run(future).map(|PackedIrcServer(server, future)| { + self.register_future(future); + server + }) } /// Creates a new IRC server from the specified configuration, connecting immediately. This is diff --git a/src/client/server/mod.rs b/src/client/server/mod.rs index c48d394..f0356f9 100644 --- a/src/client/server/mod.rs +++ b/src/client/server/mod.rs @@ -741,7 +741,9 @@ impl IrcServer { /// Proper usage requires familiarity with `tokio` and `futures`. You can find more information /// in the crate documentation for [tokio-core](http://docs.rs/tokio-core) or /// [futures](http://docs.rs/futures). Additionally, you can find detailed tutorials on using - /// both libraries on the [tokio website](https://tokio.rs/docs/getting-started/tokio/). + /// both libraries on the [tokio website](https://tokio.rs/docs/getting-started/tokio/). An easy + /// to use abstraction that does not require this knowledge is available via + /// [IrcReactors](../reactor/struct.IrcReactor.html). /// /// # Example /// ```no_run @@ -749,6 +751,7 @@ impl IrcServer { /// # extern crate tokio_core; /// # use std::default::Default; /// # use irc::client::prelude::*; + /// # use irc::client::server::PackedIrcServer; /// # use irc::error; /// # use tokio_core::reactor::Core; /// # fn main() { @@ -760,21 +763,21 @@ impl IrcServer { /// let mut reactor = Core::new().unwrap(); /// let future = IrcServer::new_future(reactor.handle(), &config).unwrap(); /// // immediate connection errors (like no internet) will turn up here... - /// let server = reactor.run(future).unwrap(); + /// let PackedIrcServer(server, future) = reactor.run(future).unwrap(); /// // runtime errors (like disconnections and so forth) will turn up here... /// reactor.run(server.stream().for_each(move |irc_msg| { /// // processing messages works like usual /// process_msg(&server, irc_msg) - /// })).unwrap(); + /// }).join(future)).unwrap(); /// # } /// # fn process_msg(server: &IrcServer, message: Message) -> error::Result<()> { Ok(()) } /// ``` - pub(crate) fn new_future(handle: Handle, config: &Config) -> error::Result { + pub fn new_future(handle: Handle, config: &Config) -> error::Result { let (tx_outgoing, rx_outgoing) = mpsc::unbounded(); Ok(IrcServerFuture { conn: Connection::new(config, &handle)?, - handle: handle, + _handle: handle, config: config, tx_outgoing: Some(tx_outgoing), rx_outgoing: Some(rx_outgoing), @@ -800,17 +803,18 @@ impl IrcServer { /// Interaction with this future relies on the `futures` API, but is only expected for more advanced /// use cases. To learn more, you can view the documentation for the /// [futures](https://docs.rs/futures/) crate, or the tutorials for -/// [tokio](https://tokio.rs/docs/getting-started/futures/). +/// [tokio](https://tokio.rs/docs/getting-started/futures/). An easy to use abstraction that does +/// not require this knowledge is available via [IrcReactors](../reactor/struct.IrcReactor.html). pub struct IrcServerFuture<'a> { conn: ConnectionFuture<'a>, - handle: Handle, + _handle: Handle, config: &'a Config, tx_outgoing: Option>, rx_outgoing: Option>, } impl<'a> Future for IrcServerFuture<'a> { - type Item = IrcServer; + type Item = PackedIrcServer; type Error = error::Error; fn poll(&mut self) -> Poll { @@ -822,19 +826,25 @@ impl<'a> Future for IrcServerFuture<'a> { let outgoing_future = sink.send_all(self.rx_outgoing.take().unwrap().map_err(|()| { let res: error::Error = error::ErrorKind::ChannelError.into(); res - })).map(|_| ()).map_err(|e| panic!(e)); + })).map(|_| ()); - self.handle.spawn(outgoing_future); - - Ok(Async::Ready(IrcServer { + let server = IrcServer { state: Arc::new(ServerState::new( stream, self.tx_outgoing.take().unwrap(), self.config.clone() )), view: view, - })) + }; + Ok(Async::Ready(PackedIrcServer(server, Box::new(outgoing_future)))) } } +/// An `IrcServer` packaged with a future that drives its message sending. In order for the server +/// to actually work properly, this future _must_ be running. +/// +/// This type should only be used by advanced users who are familiar with the implementation of this +/// crate. An easy to use abstraction that does not require this knowledge is available via +/// [IrcReactors](../reactor/struct.IrcReactor.html). +pub struct PackedIrcServer(pub IrcServer, pub Box>); #[cfg(test)] mod test {