initial commit
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
1361
Cargo.lock
generated
Normal file
1361
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
12
Cargo.toml
Normal file
12
Cargo.toml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "websocket-debug"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
tokio = { version = "1", features = ["full"] }
|
||||||
|
tokio-tungstenite = { version = "0.21", features = ["native-tls"] }
|
||||||
|
tracing = "0.1"
|
||||||
|
tracing-subscriber = { version = "0.3", features = ["fmt"] }
|
||||||
|
clap = { version = "4", features = ["derive"] }
|
||||||
|
futures-util = "0.3"
|
||||||
88
src/main.rs
Normal file
88
src/main.rs
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
use std::fs;
|
||||||
|
|
||||||
|
use clap::Parser;
|
||||||
|
use futures_util::StreamExt;
|
||||||
|
use tokio_tungstenite::{connect_async, tungstenite::Message};
|
||||||
|
use tracing::{error, info, warn};
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
#[command(name = "websocket-debug")]
|
||||||
|
#[command(about = "A WebSocket debugging tool that logs and saves messages")]
|
||||||
|
struct Args {
|
||||||
|
/// WebSocket URL to connect to (e.g., ws://localhost:8080 or wss://example.com/ws)
|
||||||
|
url: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
tracing_subscriber::fmt()
|
||||||
|
.with_target(false)
|
||||||
|
.with_thread_ids(false)
|
||||||
|
.init();
|
||||||
|
|
||||||
|
let args = Args::parse();
|
||||||
|
|
||||||
|
info!("Connecting to {}", args.url);
|
||||||
|
|
||||||
|
let (ws_stream, response) = connect_async(&args.url).await?;
|
||||||
|
info!("Connected successfully");
|
||||||
|
info!("Response status: {}", response.status());
|
||||||
|
|
||||||
|
let (_, mut read) = ws_stream.split();
|
||||||
|
|
||||||
|
let mut seq_num: u64 = 0;
|
||||||
|
|
||||||
|
while let Some(message_result) = read.next().await {
|
||||||
|
match message_result {
|
||||||
|
Ok(message) => {
|
||||||
|
match message {
|
||||||
|
Message::Text(text) => {
|
||||||
|
let preview: String = text.chars().take(50).collect();
|
||||||
|
let truncated = if text.len() > 50 { "..." } else { "" };
|
||||||
|
info!("[{}] Text: {}{}", seq_num, preview, truncated);
|
||||||
|
|
||||||
|
let filename = format!("{}.txt", seq_num);
|
||||||
|
if let Err(e) = fs::write(&filename, &text) {
|
||||||
|
error!("Failed to write {}: {}", filename, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Message::Binary(data) => {
|
||||||
|
info!("[{}] Binary: {} bytes", seq_num, data.len());
|
||||||
|
|
||||||
|
let filename = format!("{}.bin", seq_num);
|
||||||
|
if let Err(e) = fs::write(&filename, &data) {
|
||||||
|
error!("Failed to write {}: {}", filename, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Message::Ping(data) => {
|
||||||
|
info!("[{}] Ping: {} bytes", seq_num, data.len());
|
||||||
|
continue; // Don't increment seq_num for control frames
|
||||||
|
}
|
||||||
|
Message::Pong(data) => {
|
||||||
|
info!("[{}] Pong: {} bytes", seq_num, data.len());
|
||||||
|
continue; // Don't increment seq_num for control frames
|
||||||
|
}
|
||||||
|
Message::Close(frame) => {
|
||||||
|
if let Some(cf) = frame {
|
||||||
|
info!("Connection closed: {} - {}", cf.code, cf.reason);
|
||||||
|
} else {
|
||||||
|
info!("Connection closed");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Message::Frame(_) => {
|
||||||
|
continue; // Raw frames, skip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
seq_num += 1;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
warn!("Error receiving message: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("WebSocket connection ended. Received {} messages.", seq_num);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user