Sending msg to all connected sockets

I'm testing ws-rs websockect (not sure if this is the best one), and need my server to send/broadcast any msg it received from any socket to all other sockets, so I created a Vec to which I add all sockects, this send them one by one, wrote this block:

    static mut all_sockets: Vec<&mut Server> = Vec::new();

    fn on_message(&mut self, msg: Message) -> Result<()> {
        unsafe { all_sockets.push(self); };
        println!("Server got message '{}'. ", msg);
        // self.out.send(msg)
        unsafe {
            for ws in all_sockets {
                ws.out.send(msg);
            }
        }
        Ok(())
    }

But getting this error:

error[E0312]: lifetime of reference outlives lifetime of borrowed content...
  --> src/main.rs:45:35
   |
45 |         unsafe { all_sockets.push(self); };
   |                                   ^^^^
   |
   = note: ...the reference is valid for the static lifetime...
note: ...but the borrowed content is only valid for the anonymous lifetime #1 defined on the method body at 44:5
  --> src/main.rs:44:5
   |
44 | /     fn on_message(&mut self, msg: Message) -> Result<()> {
45 | |         unsafe { all_sockets.push(self); };
46 | |         println!("Server got message '{}'. ", msg);
47 | |         // self.out.send(msg)
...  |
53 | |         Ok(())
54 | |     }
   | |_____^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0312`.
error: Could not compile `ws`.

My full code is:

use ws::{listen, Handler, Message, Request, Response, Result, Sender, CloseCode};
use std::{thread, io};
use std::io::BufRead;

// This can be read from a file
static INDEX_HTML: &'static [u8] = br#"
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
	</head>
	<body>
      <pre id="messages"></pre>
			<form id="form">
				<input type="text" id="msg">
				<input type="submit" value="Send">
			</form>
      <script>
        var socket = new WebSocket("ws://" + window.location.host + "/ws");
        socket.onmessage = function (event) {
          var messages = document.getElementById("messages");
          messages.append(event.data + "\n");
        };
        var form = document.getElementById("form");
        form.addEventListener('submit', function (event) {
          event.preventDefault();
          var input = document.getElementById("msg");
          socket.send(input.value);
          input.value = "";
        });
		</script>
	</body>
</html>
    "#;

struct Server {
    out: Sender,
}

static mut all_sockets: Vec<&mut Server> = Vec::new();

impl Handler for Server {

    fn on_message(&mut self, msg: Message) -> Result<()> {
        unsafe { all_sockets.push(self); };
        println!("Server got message '{}'. ", msg);
        // self.out.send(msg)
        unsafe {
            for ws in all_sockets {
                ws.out.send(msg);
            }
        }
        Ok(())
    }

    fn on_close(&mut self, code: CloseCode, reason: &str) {
        unsafe { all_sockets.retain(|&x| x != self); }
        match code {
            CloseCode::Normal => println!("The client is done with the connection."),
            CloseCode::Away   => println!("The client is leaving the site."),
            _ => println!("The client encountered an error: {}", reason),
        }
    }

    fn on_request(&mut self, req: &Request) -> Result<(Response)> {
        // Using multiple handlers is better (see router example)
        match req.resource() {
            // The default trait implementation
            "/ws" => Response::from_request(req),

            // Create a custom response
            "/" => Ok(Response::new(200, "OK", INDEX_HTML.to_vec())),

            _ => Ok(Response::new(404, "Not Found", b"404 - Not Found".to_vec())),
        }
    }

}

fn main() {

    let my_addr = "127.0.0.1:8080";
    let mut me = ws::WebSocket::new(|out| Server { out }).unwrap();
    me.listen(my_addr).unwrap();
}

I seems indeed that a better crate exists : websocket.

You should have a look at the server example from their repository.

The immediate problem is that you can't store references in a static Vec like that. You might be able to store Vec<Sender> (though I haven't tested). As a rule of thumb, if you feel that you need to write unsafe code to use a library you've probably taken a wrong turn somewhere.

In this case it sounds like you're looking for the WS-RS broadcast method.

use ws::listen;

fn main() {
    listen("127.0.0.1:3012", |out| {
        move |msg| {
            out.broadcast(msg)
        }
    }).unwrap()
}

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.