Repository: housleyjk/ws-rs (language: rust)

Issue:
Ability to return Result from io::Handler::handle_queue
In working on https://github.com/servo/servo/issues/14517, I discovered a need for the `handle_queue` function in `io::Handler` to be able to return a `Result`, so that servo can properly handle a connection failure. Currently, if there is e.g. an invalid domain passed to the websocket `connect` function, the `handle_queue` function can either swallow the error or panic, depending on the configuration of `panic_on_new_connection`. Unfortunately neither of these options are suitable for the use case in servo.


Discussion / hints:

There is no `handle_queue` anymore.


Edit: never mind I didn't notice it is in the private API.
@housleyjk Could you take a look at it?
Evidence that there really hasn't been an upgrade to Mio 5+ in truth, yet. Yes, I think this will be possible and appropriate now. Since hopefully it's a relatively small change, I will see if I can get it out before the major refactor I have been planning to support Mio 5+ better. 

Exciting things also appear to be happening [here](https://github.com/housleyjk/ws-rs/pull/95#issuecomment-287384467). We may be getting more options for WebSockets in Rust, which is good thing. I haven't seen any of this new code or tested anything out, but I think it's good if developers have choices and I wanted to make sure you were aware.
> Exciting things also appear to be happening here. We may be getting more options for WebSockets in Rust, which is good thing. I haven't seen any of this new code or tested anything out, but I think it's good if developers have choices and I wanted to make sure you were aware.

We will need the openssl bump in Servo too.
If you fix this issue, we can switch to ws in Servo, and then try the openssl bump PR with the Servo tests.
@housleyjk Don't we just need to call `connection_made` earlier, and then immediately afterwards call `connection_lost`?

Fix patch:
diff --git a/src/io.rs b/src/io.rs
index 472d9a8..75213a7 100644
--- a/src/io.rs
+++ b/src/io.rs
@@ -129,17 +129,32 @@ impl<F> Handler<F>
     #[cfg(feature="ssl")]
     pub fn connect(&mut self, poll: &mut Poll, url: &Url) -> Result<()> {
         let settings = self.settings;
-        let mut addresses = try!(url_to_addrs(url));
-        let tok = {
-            let sock;
+
+        let (tok, addresses) = {
+            let (tok, entry, handler) = if let Some(entry) = self.connections.vacant_entry() {
+                let tok = entry.index();
+                (tok, entry, self.factory.client_connected(Sender::new(tok, self.queue_tx.clone())))
+            } else {
+                return Err(Error::new(Kind::Capacity, "Unable to add another connection to the event loop."));
+            };
+
+            let mut addresses = match url_to_addrs(url) {
+                Ok(addresses) => addresses,
+                Err(err) => {
+                    self.factory.connection_lost(handler);
+                    return Err(err);
+                }
+            };
+
             loop {
                 if let Some(addr) = addresses.pop() {
-                    if let Ok(s) = TcpStream::connect(&addr) {
-                        sock = s;
+                    if let Ok(sock) = TcpStream::connect(&addr) {
                         addresses.push(addr); // Replace the first addr in case ssl fails and we fallback
+                        entry.insert(Connection::new(tok, sock, handler, settings));
                         break
                     }
                 } else {
+                    self.factory.connection_lost(handler);
                     return Err(
                         Error::new(
                             Kind::Internal,
@@ -147,16 +162,7 @@ impl<F> Handler<F>
                 }
             }
 
-            let factory = &mut self.factory;
-
-            if let Some(entry) = self.connections.vacant_entry() {
-                let tok = entry.index();
-                let handler = factory.client_connected(Sender::new(tok, self.queue_tx.clone()));
-                entry.insert(Connection::new(tok, sock, handler, settings));
-                tok
-            } else {
-                return Err(Error::new(Kind::Capacity, "Unable to add another connection to the event loop."));
-            }
+            (tok, addresses)
         };
 
         if let Err(error) = self.connections[tok].as_client(url, addresses) {
@@ -203,32 +209,39 @@ impl<F> Handler<F>
     #[cfg(not(feature="ssl"))]
     pub fn connect(&mut self, poll: &mut Poll, url: &Url) -> Result<()> {
         let settings = self.settings;
-        let mut addresses = try!(url_to_addrs(url));
-        let tok = {
-            let sock;
+
+        let (tok, addresses) = {
+            let (tok, entry, handler) = if let Some(entry) = self.connections.vacant_entry() {
+                let tok = entry.index();
+                (tok, entry, self.factory.client_connected(Sender::new(tok, self.queue_tx.clone())))
+            } else {
+                return Err(Error::new(Kind::Capacity, "Unable to add another connection to the event loop."));
+            };
+
+            let mut addresses = match url_to_addrs(url) {
+                Ok(addresses) => addresses,
+                Err(err) => {
+                    self.factory.connection_lost(handler);
+                    return Err(err);
+                }
+            };
+
             loop {
                 if let Some(addr) = addresses.pop() {
-                    if let Ok(s) = TcpStream::connect(&addr) {
-                        sock = s;
+                    if let Ok(sock) = TcpStream::connect(&addr) {
+                        entry.insert(Connection::new(tok, sock, handler, settings));
                         break
                     }
                 } else {
+                    self.factory.connection_lost(handler);
                     return Err(
                         Error::new(
                             Kind::Internal,
                             format!("Unable to obtain any socket address for {}", url)))
                 }
             }
-            let factory = &mut self.factory;
 
-            if let Some(entry) = self.connections.vacant_entry() {
-                let tok = entry.index();
-                let handler = factory.client_connected(Sender::new(tok, self.queue_tx.clone()));
-                entry.insert(Connection::new(tok, sock, handler, settings));
-                tok
-            } else {
-                return Err(Error::new(Kind::Capacity, "Unable to add another connection to the event loop."));
-            }
+            (tok, addresses)
         };
 
         if let Err(error) = self.connections[tok].as_client(url, addresses) {


Test patch: