Skip to content

Instantly share code, notes, and snippets.

@ChetanBhasin
Last active March 20, 2024 22:27
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ChetanBhasin/b611bcb4dcf78a17fa9cf7e09f61c5b9 to your computer and use it in GitHub Desktop.
Save ChetanBhasin/b611bcb4dcf78a17fa9cf7e09f61c5b9 to your computer and use it in GitHub Desktop.
Rust web socket pub-sub example (very minimal)
extern crate websocket;
use std::thread;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::mpsc::{Sender, Receiver};
use std::sync::mpsc;
use websocket::Message;
use websocket::stream::sync::TcpStream;
use websocket::sync::{Server, Client};
pub fn main() {
let server = Server::bind("127.0.0.1:1234").unwrap();
let (ch_sender, ch_rec): (Sender<Client<TcpStream>>, Receiver<Client<TcpStream>>) = mpsc::channel();
thread::spawn(move || {
let ws_clients: Arc<Mutex<Box<Vec<Client<TcpStream>>>>> = Arc::new(Mutex::new(Box::new(Vec::new())));
let clients_writer: Arc<Mutex<Box<Vec<Client<TcpStream>>>>> = Arc::clone(&ws_clients);
let clients_reader: Arc<Mutex<Box<Vec<Client<TcpStream>>>>> = Arc::clone(&ws_clients);
thread::spawn(move || {
println!("Starting the subscriptions thread");
for client_sub in ch_rec.iter() {
let mut subscriber = clients_writer.lock().unwrap();
println!("Got a subscription!");
subscriber.push(client_sub);
}
});
thread::spawn(move || {
println!("Starting the sender thread");
loop {
thread::sleep(core::time::Duration::new(3, 0));
let mut idx: usize = 0;
let mut dead: Vec<usize> = vec!();
let mut subs = clients_reader.lock().unwrap();
for sub in subs.as_mut().iter_mut() {
match sub.send_message(&Message::text("fu".to_string())) {
Ok(_) => (),
_ => {
dead.push(idx);
}
}
idx += 1;
}
for &sub_idx in dead.iter() {
subs.remove(sub_idx);
}
}
});
});
for connection in server.filter_map(Result::ok) {
let client: Client<TcpStream> = connection.accept().unwrap();
println!("Got a connection.");
let _ = ch_sender.send(client);
}
}
@najamelan
Copy link

I only had a quick look, but I wonder why you put the Vec in a Box. Know that Vec stores the data on the heap anyway.

If you want it to be more polished, don't use unwrap. At least expect, and only if you know it will never fail and you document that in the code and verify it with unit tests. Better to return errors to callers and let them decide what should be done.

If you want it to be more generally usefull, you might implement a pattern like this over framed futures Streams and Sinks over some item T, that way you don't have to worry over websockets in your pub sub implementation, but it would work on any streamlike protocol. That might already exist on crates.io anyway.

There is work underway to implement asyncread and asyncwrite from tokio on WASM if you need it from the browser, here and here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment