summaryrefslogtreecommitdiffstats
path: root/third_party/rust/ws/examples/cli.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/ws/examples/cli.rs
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/ws/examples/cli.rs')
-rw-r--r--third_party/rust/ws/examples/cli.rs180
1 files changed, 180 insertions, 0 deletions
diff --git a/third_party/rust/ws/examples/cli.rs b/third_party/rust/ws/examples/cli.rs
new file mode 100644
index 0000000000..80ebf8cc6b
--- /dev/null
+++ b/third_party/rust/ws/examples/cli.rs
@@ -0,0 +1,180 @@
+extern crate clap;
+extern crate env_logger;
+extern crate term;
+/// Run this cli like this:
+/// cargo run --example server
+/// cargo run --example cli -- ws://127.0.0.1:3012
+extern crate ws;
+
+use std::io;
+use std::io::prelude::*;
+use std::sync::mpsc::Sender as TSender;
+use std::sync::mpsc::channel;
+use std::thread;
+
+use clap::{App, Arg};
+use ws::{connect, CloseCode, Error, ErrorKind, Handler, Handshake, Message, Result, Sender};
+
+fn main() {
+ // Setup logging
+ env_logger::init();
+
+ // setup command line arguments
+ let matches = App::new("WS Command Line Client")
+ .version("1.1")
+ .author("Jason Housley <housleyjk@gmail.com>")
+ .about("Connect to a WebSocket and send messages from the command line.")
+ .arg(
+ Arg::with_name("URL")
+ .help("The URL of the WebSocket server.")
+ .required(true)
+ .index(1),
+ )
+ .get_matches();
+
+ let url = matches.value_of("URL").unwrap().to_string();
+
+ let (tx, rx) = channel();
+
+ // Run client thread with channel to give it's WebSocket message sender back to us
+ let client = thread::spawn(move || {
+ println!("Connecting to {}", url);
+ connect(url, |sender| Client {
+ ws_out: sender,
+ thread_out: tx.clone(),
+ }).unwrap();
+ });
+
+ if let Ok(Event::Connect(sender)) = rx.recv() {
+ // If we were able to connect, print the instructions
+ instructions();
+
+ // Main loop
+ loop {
+ // Get user input
+ let mut input = String::new();
+ io::stdin().read_line(&mut input).unwrap();
+
+ if let Ok(Event::Disconnect) = rx.try_recv() {
+ break;
+ }
+
+ if input.starts_with("/h") {
+ // Show help
+ instructions()
+ } else if input.starts_with("/c") {
+ // If the close arguments are good, close the connection
+ let args: Vec<&str> = input.split(' ').collect();
+ if args.len() == 1 {
+ // Simple close
+ println!("Closing normally, please wait...");
+ sender.close(CloseCode::Normal).unwrap();
+ } else if args.len() == 2 {
+ // Close with a specific code
+ if let Ok(code) = args[1].trim().parse::<u16>() {
+ let code = CloseCode::from(code);
+ println!("Closing with code: {:?}, please wait...", code);
+ sender.close(code).unwrap();
+ } else {
+ display(&format!("Unable to parse {} as close code.", args[1]));
+ // Keep accepting input if the close arguments are invalid
+ continue;
+ }
+ } else {
+ // Close with a code and a reason
+ if let Ok(code) = args[1].trim().parse::<u16>() {
+ let code = CloseCode::from(code);
+ let reason = args[2..].join(" ");
+ println!(
+ "Closing with code: {:?} and reason: {}, please wait...",
+ code,
+ reason.trim()
+ );
+ sender
+ .close_with_reason(code, reason.trim().to_string())
+ .unwrap();
+ } else {
+ display(&format!("Unable to parse {} as close code.", args[1]));
+ // Keep accepting input if the close arguments are invalid
+ continue;
+ }
+ }
+ break;
+ } else {
+ // Send the message
+ display(&format!(">>> {}", input.trim()));
+ sender.send(input.trim()).unwrap();
+ }
+ }
+ }
+
+ // Ensure the client has a chance to finish up
+ client.join().unwrap();
+}
+
+fn display(string: &str) {
+ let mut view = term::stdout().unwrap();
+ view.carriage_return().unwrap();
+ view.delete_line().unwrap();
+ println!("{}", string);
+ print!("?> ");
+ io::stdout().flush().unwrap();
+}
+
+fn instructions() {
+ println!("Type /close [code] [reason] to close the connection.");
+ println!("Type /help to show these instructions.");
+ println!("Other input will be sent as messages.\n");
+ print!("?> ");
+ io::stdout().flush().unwrap();
+}
+
+struct Client {
+ ws_out: Sender,
+ thread_out: TSender<Event>,
+}
+
+impl Handler for Client {
+ fn on_open(&mut self, _: Handshake) -> Result<()> {
+ self.thread_out
+ .send(Event::Connect(self.ws_out.clone()))
+ .map_err(|err| {
+ Error::new(
+ ErrorKind::Internal,
+ format!("Unable to communicate between threads: {:?}.", err),
+ )
+ })
+ }
+
+ fn on_message(&mut self, msg: Message) -> Result<()> {
+ display(&format!("<<< {}", msg));
+ Ok(())
+ }
+
+ fn on_close(&mut self, code: CloseCode, reason: &str) {
+ if reason.is_empty() {
+ display(&format!(
+ "<<< Closing<({:?})>\nHit any key to end session.",
+ code
+ ));
+ } else {
+ display(&format!(
+ "<<< Closing<({:?}) {}>\nHit any key to end session.",
+ code, reason
+ ));
+ }
+
+ if let Err(err) = self.thread_out.send(Event::Disconnect) {
+ display(&format!("{:?}", err))
+ }
+ }
+
+ fn on_error(&mut self, err: Error) {
+ display(&format!("<<< Error<{:?}>", err))
+ }
+}
+
+enum Event {
+ Connect(Sender),
+ Disconnect,
+}