feat: v0.1.1
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -1226,7 +1226,7 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wscat-rs"
|
name = "wscat-rs"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wscat-rs"
|
name = "wscat-rs"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
authors = ["Hatter Jiang <jht5945@gmail.com>"]
|
authors = ["Hatter Jiang <jht5945@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
|
|||||||
155
src/main.rs
155
src/main.rs
@@ -1,17 +1,21 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate rust_util;
|
extern crate rust_util;
|
||||||
|
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
use clap::{App, Arg};
|
use clap::{App, Arg};
|
||||||
use tokio_tungstenite::connect_async;
|
use futures_util::{SinkExt, StreamExt};
|
||||||
|
use futures_util::stream::SplitSink;
|
||||||
|
use rust_util::util_msg::{clear_lastline, flush_stdout};
|
||||||
use rust_util::XResult;
|
use rust_util::XResult;
|
||||||
use futures_util::{StreamExt, SinkExt};
|
|
||||||
use tokio_tungstenite::tungstenite::Message;
|
|
||||||
use tokio::sync::mpsc::channel;
|
|
||||||
use url::Url;
|
|
||||||
use rustyline::Editor;
|
use rustyline::Editor;
|
||||||
use rustyline::error::ReadlineError;
|
use rustyline::error::ReadlineError;
|
||||||
use std::time::Duration;
|
use tokio::net::TcpStream;
|
||||||
use rust_util::util_msg::{clear_lastline, flush_stdout};
|
use tokio::runtime::Runtime;
|
||||||
|
use tokio::sync::mpsc::{channel, Receiver, Sender};
|
||||||
|
use tokio_tungstenite::{connect_async, MaybeTlsStream, WebSocketStream};
|
||||||
|
use tokio_tungstenite::tungstenite::{Error, Message};
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
@@ -41,22 +45,74 @@ async fn main() {
|
|||||||
|
|
||||||
async fn connect_to_and_loop(url: &Url, enable_ping_pong: bool) -> XResult<()> {
|
async fn connect_to_and_loop(url: &Url, enable_ping_pong: bool) -> XResult<()> {
|
||||||
let (ws_stream, _) = connect_async(url).await?;
|
let (ws_stream, _) = connect_async(url).await?;
|
||||||
let (mut ws_write, mut ws_read) = ws_stream.split();
|
let (ws_write, mut ws_read) = ws_stream.split();
|
||||||
|
|
||||||
let (sender, mut receiver) = channel(2);
|
let (mut sender, receiver) = channel(2);
|
||||||
|
|
||||||
|
// receiver from `receiver`, then send to `ws_write`
|
||||||
|
spawn_loop_write_to_ws(ws_write, receiver);
|
||||||
|
// read from `console`, then send to `sender`
|
||||||
|
spawn_loop_console(sender.clone());
|
||||||
|
|
||||||
|
if !enable_ping_pong {
|
||||||
|
wrap_output(|| debugging!("Ping/Pong is disabled"));
|
||||||
|
} else {
|
||||||
|
wrap_output(|| debugging!("Ping/Pong is enabled"));
|
||||||
|
spawn_loop_ping_pong(sender.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let next_message: Option<Result<Message, Error>> = ws_read.next().await;
|
||||||
|
match next_message {
|
||||||
|
None => return process_ws_end(),
|
||||||
|
Some(Err(e)) => return simple_error!("WebSocket got error: {}", e),
|
||||||
|
Some(Ok(message)) => process_message(&mut sender, message).await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_ws_end() -> XResult<()> {
|
||||||
|
information!("WebSocket ended.");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn process_message(sender: &mut Sender<Message>, message: Message) {
|
||||||
|
match message {
|
||||||
|
Message::Ping(msg) => {
|
||||||
|
wrap_output(|| debugging!("Received ping message: {:?}", msg));
|
||||||
|
let r = sender.send(Message::Pong(msg)).await;
|
||||||
|
r.ok();
|
||||||
|
}
|
||||||
|
Message::Pong(msg) => {
|
||||||
|
wrap_output(|| debugging!("Received pong message: {:?}", msg));
|
||||||
|
}
|
||||||
|
Message::Close(close_frame) => {
|
||||||
|
wrap_output(|| information!("WebSocket closed: {:?}", close_frame));
|
||||||
|
}
|
||||||
|
Message::Binary(msg) => {
|
||||||
|
wrap_output(|| information!("Received binary message: {:?}", msg));
|
||||||
|
}
|
||||||
|
Message::Text(msg) => {
|
||||||
|
wrap_output(|| information!("Received text message: {}", msg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spawn_loop_ping_pong(sender: Sender<Message>) {
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
while let Some(msg) = receiver.recv().await {
|
loop {
|
||||||
if let Err(e) = ws_write.send(msg).await {
|
tokio::time::sleep(Duration::from_secs(10)).await;
|
||||||
failure!("Send message to server failed: {}", e);
|
wrap_output(|| debugging!("Send ping message"));
|
||||||
ws_write.close().await.ok();
|
if let Err(e) = sender.send(Message::Ping(vec![])).await {
|
||||||
break;
|
wrap_output(|| debugging!("Send ping message failed: {}", e));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
fn spawn_loop_console(sender: Sender<Message>) {
|
||||||
let cloned_sender = sender.clone();
|
let rt = Runtime::new().unwrap();
|
||||||
let _t = std::thread::spawn(move || {
|
let _t = std::thread::spawn(move || {
|
||||||
let mut rl = Editor::<()>::new();
|
let mut rl = Editor::<()>::new();
|
||||||
loop {
|
loop {
|
||||||
@@ -65,7 +121,7 @@ async fn connect_to_and_loop(url: &Url, enable_ping_pong: bool) -> XResult<()> {
|
|||||||
Ok(line) => {
|
Ok(line) => {
|
||||||
if !line.is_empty() {
|
if !line.is_empty() {
|
||||||
rl.add_history_entry(line.as_str());
|
rl.add_history_entry(line.as_str());
|
||||||
let cloned_sender = cloned_sender.clone();
|
let cloned_sender = sender.clone();
|
||||||
rt.spawn(async move {
|
rt.spawn(async move {
|
||||||
if let Err(e) = cloned_sender.send(Message::Text(line)).await {
|
if let Err(e) = cloned_sender.send(Message::Text(line)).await {
|
||||||
failure!("Send message failed: {}", e);
|
failure!("Send message failed: {}", e);
|
||||||
@@ -88,60 +144,21 @@ async fn connect_to_and_loop(url: &Url, enable_ping_pong: bool) -> XResult<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if !enable_ping_pong {
|
|
||||||
wrap_output(|| debugging!("Ping/Pong is disabled"));
|
|
||||||
} else {
|
|
||||||
wrap_output(|| debugging!("Ping/Pong is enabled"));
|
|
||||||
let time_cloned_sender = sender.clone();
|
|
||||||
tokio::spawn(async move {
|
|
||||||
loop {
|
|
||||||
tokio::time::sleep(Duration::from_secs(10)).await;
|
|
||||||
wrap_output(|| debugging!("Send ping message"));
|
|
||||||
if let Err(e) = time_cloned_sender.send(Message::Ping(vec![])).await {
|
|
||||||
wrap_output(|| debugging!("Send ping message failed: {}", e));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let next = ws_read.next().await;
|
|
||||||
match next {
|
|
||||||
None => {
|
|
||||||
information!("WebSocket ended.");
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
Some(Err(e)) => {
|
|
||||||
return simple_error!("WebSocket got error: {}", e);
|
|
||||||
}
|
|
||||||
Some(Ok(message)) => {
|
|
||||||
match message {
|
|
||||||
Message::Ping(msg) => {
|
|
||||||
wrap_output(|| debugging!("Received ping message: {:?}", msg));
|
|
||||||
let r = sender.send(Message::Pong(msg)).await;
|
|
||||||
r.ok();
|
|
||||||
}
|
|
||||||
Message::Pong(msg) => {
|
|
||||||
wrap_output(|| debugging!("Received pong message: {:?}", msg));
|
|
||||||
}
|
|
||||||
Message::Close(close_frame) => {
|
|
||||||
wrap_output(|| information!("WebSocket closed: {:?}", close_frame));
|
|
||||||
}
|
|
||||||
Message::Binary(msg) => {
|
|
||||||
wrap_output(|| information!("Received binary message: {:?}", msg));
|
|
||||||
}
|
|
||||||
Message::Text(msg) => {
|
|
||||||
wrap_output(|| information!("Received text message: {}", msg));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrap_output<F>(f: F) where F: Fn() -> () {
|
fn spawn_loop_write_to_ws(mut ws_write: SplitSink<WebSocketStream<MaybeTlsStream<TcpStream>>, Message>, mut receiver: Receiver<Message>) {
|
||||||
|
tokio::spawn(async move {
|
||||||
|
while let Some(msg) = receiver.recv().await {
|
||||||
|
if let Err(e) = ws_write.send(msg).await {
|
||||||
|
failure!("Send message to server failed: {}", e);
|
||||||
|
ws_write.close().await.ok();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wrap_output<F>(f: F) where F: Fn() {
|
||||||
clear_lastline();
|
clear_lastline();
|
||||||
f();
|
f();
|
||||||
print!("ws $ ");
|
print!("ws $ ");
|
||||||
|
|||||||
Reference in New Issue
Block a user