Architecture and program shutdown for wscat clone


#1

Hello,

I’m trying to build a wscat clone (basically a cli to send and receive messages to a websocket).

Basic architecture is:

extern crate chan;
extern crate chan_signal;
extern crate readline;
extern crate websocket;

use websocket::*;

fn main() {
    // Set up websocket client
    let client = response.begin();
    let (mut sender, mut receiver) = client.split();

    //set up a signal notify through chan_signal crate

    //set up a channel for quit
    let (quit_s, quit_r) = chan::sync(0);

    //thread for reading stdin
    let quit_r1 = quit_r.clone()
    thread::spawn( move || {
        loop {
            //readline
            sender.send(message);
            chan_select! {
                quit_r1.recv() => {
                    break;
                }
            }
        }
    });
    //thread for getting messages from ws
    let quit_r2 = quit_r.clone();
    thread::spawn( move || {
        while let Ok(message) = receiver.recv_mesage() {
            //match on message and output text to stdout
            chan_select! {
                quit_r2.recv() => {
                    break;
                }
            }
        }
    });
}

Questions:

  1. I think that threads could be used, but is there a better way to organize this program? I used threads because I figured that the send and receive of the websocket could be fairly asynchronous.

  2. I’m having a lot of trouble trying to exit the program cleanly on sigINT. On the first thread (reading from stdin), waiting for input for stdin appeares to block any messages I might pass through a channel. In the second thread, I usually don’t reach the chan_select!, as determined by using some println!

  3. I think basically, I’m just not sure how to close out the ws receive and the thread. It just doesn’t close as I expect, even if the ws closes the thread. I’ve also tried explicitly using receiver.shutdown(). I think what may be happening is that chan_select has to wait on a message or err to be received from ws before acting.

  4. Not sure I’m using chan_select correctly, but I’ve tried it in various positions inside each loop (including putting other loop logic inside a default).

I’m not very experienced with threads, so any help is appreciated. I haven’t put in some details, but can provide more if it’s helpful. Sorry for mistakes in the above code.


#2

I think that this may answer at least a part of my questions: https://github.com/rust-lang/rust/issues/26446

I think that link says that, since I’m waiting on the ws for IO, it may block a channel from receiving/dropping. And that there’s no clear solution right now?

I still get some unexpected behavior from running readline inside of its own thread, also… I’ll get

     Running `target/debug/wscat-rs`
> 
readline-test (master|✚3) > ^C

where the ^C only appears after pressing enter at the prompt that appears after ctrl-C. If the readline loop is put in the main() thread, it exits on ctrl-C like this:

     Running `target/debug/wscat-rs`
> ^C
readline-test (master|✚3) > 

#3

Got it working. The example in the websocket library was very helpful. (it took me a long time for me to look there for help though!)

Basically, I’ve added readline, formatting output, error handling, and a cli interface.

Any tips on more idiomatic Rust would be greatly appreciated.