A CLI development tool for WebSocket APIs

Overview

wsta

The WebSocket Transfer Agent

Build Status Build status

wsta is a cli tool written in rust for interfacing with WebSockets. wsta has the philosophy of being an easy tool to learn and thus gets out of your way to let you work your UNIX magic directly on the WebSocket traffic. The way wsta does this is to be as pipe-friendly as possible, letting you chain it into complex pipelines or bash scripts as you see fit, or just keep it simple and use it as is.

See the manual or type man wsta for details.

Cool things you can do

Since wsta is really pipe-friendly, you can easily work with your output in a way that suits you. If you have a websocket-service that returns JSON, you might want to have your data printed in a nice, readable format. jq is perfect for that.

$ wsta ws://echo.websocket.org '{"values":{"test": "what?"}}' | jq .values
Connected to ws://echo.websocket.org
{
  "test": "what?"
}

Because wsta reads from stdin, it can also be used as an interactive prompt if you wish to send messages to the server interactively.

$ wsta ws://echo.websocket.org
Connected to ws://echo.websocket.org
ping
ping
hello
hello

If you're debugging some nasty problem with your stream, you are probably only interested in frames related to your problem. Good news, grep is here to save the day!

$ while true; do echo  $(( RANDOM %= 200 )); sleep 0.2; done | wsta ws://echo.websocket.org | grep '147'
147
147
147
147
147
147

Use wsta to monitor your websocket uptime. Use the --ping option to keep the connection alive, and check the exit code for issues. You can also send the last few messages with POST data for a higher quality alert.

while true; do

  # Start persistent connection, pinging evey 10 seconds to stay alive
  wsta -v --ping 10 ws://echo.websocket.org > messages.txt

  if [ $? -gt 0 ]; then
    tail messages.txt | curl -F "messages=@-" https://SOUNDTHEALARM.yourcompany.com
  fi

  sleep 30
done

If you need to load test your server over a WebSocket connection, it is simple to write a short bash script to do this. The following example uses a loop to continously send messages to the server and saturate the connection as much as possible. This example could also be ran in parallel as many times as required to add more saturated connections to the load test.

for i in {1..1000}
do
  echo "subscribe?giveMeLotsOfData=true&id=$i"
  echo "unsubscribe?id=$i"
done | wsta ws://echo.websocket.org

wsta also supports binary data using the --binary argument. When provided, all data read from stdin is assumed to be in binary format. The following simplified example records a binary stream from the microphone and sends it continously to the server, reading the response JSON as it comes in.

For more information on binary mode, see the manual and #5.

$ arecord --format=S16_LE --rate=44100 | wsta -b 'wss://example.com' | jq .results
"hello "
"hello this is me "
"hello this is me talking to "
"hello this is me talking to people "
"hello this is me talking to people "

Configuration profiles

A neat feature of wsta is the ability to have several separate configuration profiles. Configuration profiles are basically presets of CLI arguments like urls and headers saved to a file for easy reuse at a later point.

If you have web services in different environments, you might for example want to have a foo-dev and foo-prod configuration file. This makes it easy to at a later date connect to foo by simply running wsta -P foo-dev,

These files could be checked into VCS and shared between colleagues.

An example of a configuration file:

url = "ws://echo.websocket.org";
headers = ["Origin:google.com", "Foo:Bar"];
show_headers = true;

See the manual for more information.

Installation

Requirements

Currently the only requirement to run wsta is rust-openssl. If you get an error about a missing ssllib.so or similar, try installing OpenSSL runtime libraries and headers. Have a look at this link for instructions on how to do so.

64-bit Linux

I've set up a download page here that you can get wsta

https://software.opensuse.org/download.html?project=home%3Aesphen&package=wsta

I'm working on getting more distributions, as well as 32-bit into the Open Build Service pipeline, which is what creates the releases on that page. For now, you need a 64-bit system to use that page. If you don't use a 64-bit system, have a look below at binaries or compiling it yourself.

Gentoo Linux

wsta can be found in the Gentoo portage tree as dev-util/wsta. In order to install it, simply run the following command.

emerge dev-util/wsta

Mac OS X

To install on Max OS X, ensure you have homebrew installed, then run the following commands. It's going to take a while, please be patient.

brew tap esphen/wsta https://github.com/esphen/wsta.git
brew install wsta

You can also find binary releases on the releases page.

Other Linux distributions

I only provide so many Linux distros on OBS, and only 64-bit versions. If your computer does not fit into the distros provided, then have a look at the download section of the most recent release, and place the attached binary into your $PATH.

https://github.com/esphen/wsta/releases

Windows

Windows binaries are compiled for each release. Ensure you have a command prompt with GNU libraries, for example the git prompt, and run the provided binary file from there.

You can find binary releases on the releases page.

Compile it yourself

DON'T PANIC. It's really easy to compile and install wsta yourself! Rust provides solid tools like cargo for automating the compilation. If you compile wsta yourself, it should run on all of rust's supported platforms.

# Install the rust language and tools
curl https://sh.rustup.rs -sSf | sh

# Install gcc and OpenSSL on your OS
dnf install -y gcc openssl-devel

# Install wsta to `$HOME/.cargo` or `$CARGO_HOME` if set.
# To change the install path, try setting --root to a directory like /usr/local
cargo install --git https://github.com/esphen/wsta.git

Development setup

Install the rust language and tools.

curl https://sh.rustup.rs -sSf | sh

Run the program

cargo run -- -vvv -I -e ws://echo.websocket.org

In order to generate the man page, groff is needed

make man

If updates to the man page are done, remember to generate the markdown manual afterwards

make wsta.md
Comments
  • Issue sending JSON and then audio Watson Speech to Text service

    Issue sending JSON and then audio Watson Speech to Text service

    Hey, this is a followup to the comments I left on hacker news. I'm trying to send an opening JSON message and then audio data to the Watson STT service. It was suggested that something like this would work:

    arecord -fdat | cat start.json - | wsta 'wss://stream.watsonplatform.net/speech-to-text/api/v1/recognize?watson-token=...
    

    (Getting a token requires some fiddling around with bluemix for credentials and converting it to a token via either curl or your favorite SDK... or just go to the demo, open the dev console, and grab one - they're reusable for a short period of time. OR, if wsta supports custom headers, you can stick the credentials into a basic auth header and skip the token.)

    And, start.json looks like this:

    {"action":"start","content-type":"audio/wav","interim_results":"true"}
    

    However, when I do that, I get a ton of error: stream did not contain valid UTF-8 messages, and then the normal {"state": "listening"} message that acknowledges my initial JSON, and then a "No JSON object could be decoded" error.

    My best guess is that wsta is correctly marking the opening JSON as a UTF-8 message, and then incorrectly marking all of the audio data as UTF-8 messages also. Does this sound likely? Is that reasonably easy to fix?

    FWIW, the service also expects a closing JSON message at the end.. but that's not nearly as important because it will automatically kill the connection after 30 seconds of silence.

    opened by nfriedly 7
  • Need customizable ping.

    Need customizable ping.

    I'm planning on using your tool to automate connection to the PubSub system that twitch uses.

    It requires the pings be sent as '{"type": "PING"}' and through the standard -p system I do not see a responce pong for a ping with this flag set.

    Here is what I get by default and I am sure this is expected behavior for you:

    $ wsta -e -p 10  wss://pubsub-edge.twitch.tv
    Connected to wss://pubsub-edge.twitch.tv
    > ping
    > ping
    > ping
    

    Here is what I need to be able to tell it to do from a ping. A flag that allowed you to set the ping string sent would resolve the issue.

    $ wsta -e wss://pubsub-edge.twitch.tv '{"type": "PING"}'
    Connected to wss://pubsub-edge.twitch.tv
    > {"type": "PING"}
    { "type": "PONG" }
    

    If the ping command allowed me to send '{"type": "PING"}' as the ping data this would be perfect.

    opened by edge226 3
  • Homebrew installation fails

    Homebrew installation fails

    `$ brew install wsta ==> Installing wsta from esphen/wsta ==> Downloading https://github.com/esphen/wsta/archive/0.2.1.tar.gz ==> Downloading from https://codeload.github.com/esphen/wsta/tar.gz/0.2.1

    ################################################################## 100.0%

    Error: SHA256 mismatch Expected: 7923e9bd8310b5a72d8390324bd5150615d0e587ec793f808e12cddbb03e238f Actual: 48c2c1a73cab9955df0c2cb494d536e904dafa19a7c8ac7c6dac64ae2cb6240a Archive: /Library/Caches/Homebrew/wsta-0.2.1.tar.gz To retry an incomplete download, remove the file above.`

    Yes, I did delete the file and try again with the same result.

    opened by oyvindwe 3
  • Thanks!

    Thanks!

    This tool is a life saver! Great work.
    My team and I really appreciate the care and effort you put into building and maintaining this.
    Keep up the awesome work.

    Thank you!

    opened by ohall 1
  • Debian build - Not published since 0.3.0

    Debian build - Not published since 0.3.0

    The debian build was not published properly with 0.4.0. I need to fix the build to ensure it is using the release toolchain of rust, as it is still using the beta version

    opened by esphen 0
  • Argument conflict between -p (profile) and -p (ping)

    Argument conflict between -p (profile) and -p (ping)

    Today -p PING is ignored, and -p PROFILE is used instead. Workaround is to use --ping PING

    Need to release 0.4.1 and rename -p PROFILE to -P PROFILE (as -p PING has been around for longer)

    bug 
    opened by esphen 0
  • Binary data

    Binary data

    Add support for binary frames, both from stdin to the server, and from the server to stdout

    Adds a new argument, -b, --binary. This turns wsta into sending binary mode. Everything from stdin will then be parsed as binary, and sent in 256B frames. You can increase or decrease this frame size using the environment variable WSTA_BINARY_FRAME_SIZE.

    See #5

    Also closes #4

    The merge diff is a bit messy because I rebased the rust-everywhere branch, but this branch is not aware of it.

    opened by esphen 0
  • Write everything that is not websocket frames to stderr

    Write everything that is not websocket frames to stderr

    For a user, this is confusing:

    $ wsta -I ws://example.com | jq .
    parse error: Invalid numeric literal at line 1, column 13
    Connected to ws://example.com/
    thread '<unnamed>' panicked at 'failed printing to stdout: Broken pipe (os error 32)', ../src/libstd/io/stdio.rs:617
    note: Run with `RUST_BACKTRACE=1` for a backtrace.
    

    This happens because -I prints headers, which jq cannot parse. jq then exits, breaking the pipe.

    The problem is twofold, both of which should be adressed:

    • [x] To be as pipe-friendly as possible, wsta should only write content the user would want to pipe into stdout.
    • [x] Handle breaking pipes with a better error message
    enhancement 
    opened by esphen 0
  • Brew install fails

    Brew install fails

    I tried installing wsta on my M1 MacBook Pro. Dunno if Rust has changed since it was last updated, but I got an error compiling:

    ==> Installing esphen/wsta/wsta
    ==> cargo build --release
    Last 15 lines from /Users/rmann/Library/Logs/Homebrew/wsta/01.cargo:
    error[E0713]: borrow may still be in use when destructor runs
       --> /Users/rmann/Library/Caches/Homebrew/cargo_cache/registry/src/github.com-1ecc6299db9ec823/url-1.2.4/src/form_urlencoded.rs:246:40
        |
    244 | impl<'a> Target for ::UrlQuery<'a> {
        |      -- lifetime `'a` defined here
    245 |     fn as_mut_string(&mut self) -> &mut String { &mut self.url.serialization }
    246 |     fn finish(self) -> &'a mut ::Url { self.url }
        |                                        ^^^^^^^^ - here, drop of `self` needs exclusive access to `*self.url`, because the type `UrlQuery<'_>` implements the `Drop` trait
        |                                        |
        |                                        returning this value requires that `*self.url` is borrowed for `'a`
    
    For more information about this error, try `rustc --explain E0713`.
    error: could not compile `url` due to previous error
    warning: build failed, waiting for other jobs to finish...
    error: build failed
    
    If reporting this issue please do so to (not Homebrew/brew or Homebrew/core):
      esphen/wsta
    
    /opt/homebrew/Library/Homebrew/utils/github/api.rb:304:in `raise_error': Validation Failed: [{"message"=>"The listed users and repositories cannot be searched either because the resources do not exist or you do not have permission to view them.", "resource"=>"Search", "field"=>"q", "code"=>"invalid"}] (GitHub::API::ValidationFailedError)
    	from /opt/homebrew/Library/Homebrew/utils/github/api.rb:234:in `open_rest'
    	from /opt/homebrew/Library/Homebrew/utils/github.rb:166:in `search'
    	from /opt/homebrew/Library/Homebrew/utils/github.rb:34:in `search_issues'
    	from /opt/homebrew/Library/Homebrew/utils/github.rb:67:in `issues_for_formula'
    	from /opt/homebrew/Library/Homebrew/exceptions.rb:491:in `fetch_issues'
    	from /opt/homebrew/Library/Homebrew/exceptions.rb:487:in `issues'
    	from /opt/homebrew/Library/Homebrew/exceptions.rb:541:in `dump'
    	from /opt/homebrew/Library/Homebrew/brew.rb:155:in `rescue in <main>'
    	from /opt/homebrew/Library/Homebrew/brew.rb:143:in `<main>'
    /opt/homebrew/Library/Homebrew/formula.rb:2307:in `block in system': Failed executing: cargo build --release (BuildError)
    	from /opt/homebrew/Library/Homebrew/formula.rb:2243:in `open'
    	from /opt/homebrew/Library/Homebrew/formula.rb:2243:in `system'
    	from /opt/homebrew/Library/Taps/esphen/homebrew-wsta/HomebrewFormula/wsta.rb:12:in `install'
    	from /opt/homebrew/Library/Homebrew/build.rb:172:in `block (3 levels) in install'
    	from /opt/homebrew/Library/Homebrew/utils.rb:588:in `with_env'
    	from /opt/homebrew/Library/Homebrew/build.rb:134:in `block (2 levels) in install'
    	from /opt/homebrew/Library/Homebrew/formula.rb:1297:in `block in brew'
    	from /opt/homebrew/Library/Homebrew/formula.rb:2473:in `block (2 levels) in stage'
    	from /opt/homebrew/Library/Homebrew/utils.rb:588:in `with_env'
    	from /opt/homebrew/Library/Homebrew/formula.rb:2472:in `block in stage'
    	from /opt/homebrew/Library/Homebrew/resource.rb:126:in `block (2 levels) in unpack'
    	from /opt/homebrew/Library/Homebrew/download_strategy.rb:115:in `chdir'
    	from /opt/homebrew/Library/Homebrew/download_strategy.rb:115:in `chdir'
    	from /opt/homebrew/Library/Homebrew/download_strategy.rb:102:in `stage'
    	from /opt/homebrew/Library/Homebrew/resource.rb:122:in `block in unpack'
    	from /opt/homebrew/Library/Homebrew/mktemp.rb:63:in `block in run'
    	from /opt/homebrew/Library/Homebrew/mktemp.rb:63:in `chdir'
    	from /opt/homebrew/Library/Homebrew/mktemp.rb:63:in `run'
    	from /opt/homebrew/Library/Homebrew/resource.rb:208:in `mktemp'
    	from /opt/homebrew/Library/Homebrew/resource.rb:121:in `unpack'
    	from /opt/homebrew/Library/Homebrew/resource.rb:96:in `stage'
    	from /System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/forwardable.rb:230:in `stage'
    	from /opt/homebrew/Library/Homebrew/formula.rb:2452:in `stage'
    	from /opt/homebrew/Library/Homebrew/formula.rb:1290:in `brew'
    	from /opt/homebrew/Library/Homebrew/build.rb:129:in `block in install'
    	from /opt/homebrew/Library/Homebrew/utils.rb:588:in `with_env'
    	from /opt/homebrew/Library/Homebrew/build.rb:124:in `install'
    	from /opt/homebrew/Library/Homebrew/build.rb:224:in `<main>'
    
    opened by JetForMe 2
  • Can't write long string in payload field

    Can't write long string in payload field

    I'm sending a WebRTC SDP offer which is a bit over 2k characters, but when copy-pasting it wsta stops receiving any more input and can't finish the payload for the request.

    opened by AminArria 0
  • RFC: New name?

    RFC: New name?

    I've been getting some feedback from the english-speaking community about the name wsta. Consensus is that it's very difficult at best to pronounce, so I'm considering changing it.

    Any suggestions? Feel free to leave a comment. It should be short enough to be a CLI command, and have something to do with ws.

    help wanted question 
    opened by esphen 1
  • Support ping/pong control frames

    Support ping/pong control frames

    I've written a server that sends pings messages to clients, in order to detect broken connections, and I'd like to use wsta to interact with it. However it seems that wsta does not send pong messages in response to pings.

    In my opinion wsta should (by default) reply to ping messages with pong, by just replying with the ping payload.

    The current options for "ping" (e.g. -p) are a little confusing, since they're really just sending plain messages as opposed to ping frames.

    opened by bradleyayers 1
  • Compiling on macOS with HomeBrew

    Compiling on macOS with HomeBrew

    I needed the following to get wsta to compile:

    LD_LIBRARY_PATH=$(brew --prefix openssl)/lib:"${LD_LIBRARY_PATH}"
    CPATH=$(brew --prefix openssl)/include:"${CPATH}"
    PKG_CONFIG_PATH=$(brew --prefix openssl)/lib/pkgconfig:"${PKG_CONFIG_PATH}"
    export LD_LIBRARY_PATH CPATH PKG_CONFIG_PATH
    

    Maybe this could be mentioned in the README in a suitable manner. Unfortunately, I don't feel confident in providing an actual PR.

    Source: https://github.com/libimobiledevice/libimobiledevice/issues/389

    opened by akauppi 5
Releases(0.5.0)
Owner
Espen Henriksen
Web developer and Linuxphile
Espen Henriksen
Lightweight stream-based WebSocket implementation for Rust.

Tungstenite Lightweight stream-based WebSocket implementation for Rust. use std::net::TcpListener; use std::thread::spawn; use tungstenite::server::ac

Snapview GmbH 1.3k Jan 2, 2023
Websocket generic library for Bitwyre WS-API

Websocket Core (Rust) Websocket generic server library for: Periodic message broadcast Eventual (Pubsub) message broadcast Async request reply Authors

Bitwyre 13 Oct 28, 2022
Jamsocket is a lightweight framework for building WebSocket-based application backends.

Jamsocket is a lightweight framework for building services that are accessed through WebSocket connections.

null 94 Dec 30, 2022
Spawn process IO to websocket with full PTY support.

Cliws Spawn process IO to websocket with full PTY support. Features Any process IO through Websocket Full pty support: VIM, SSH, readline, Ctrl+X Auto

B23r0 91 Jan 5, 2023
A lightweight framework for building WebSocket-based application backends.

Jamsocket Jamsocket is a lightweight framework for building services that are accessed through WebSocket connections. Services can either be native Ru

drifting in space 94 Dec 30, 2022
A WebSocket (RFC6455) library written in Rust

Rust-WebSocket Rust-WebSocket is a WebSocket (RFC6455) library written in Rust. Rust-WebSocket provides a framework for dealing with WebSocket connect

Jason N 19 Aug 22, 2022
An aria2 websocket jsonrpc in Rust.

aria2-ws An aria2 websocket jsonrpc in Rust. Built with tokio. Docs.rs aria2 RPC docs Features Almost all methods and structed responses Auto reconnec

null 8 Sep 7, 2022
A simple toy websocket client to connect to Bitstamp.net and print the live order book written in Rust.

A simple toy websocket client to connect to Bitstamp.net and print the live order book written in Rust.

Nate Houk 1 Feb 14, 2022
The ever fast websocket tunnel built on top of lightws

Kaminari The ever fast websocket tunnel built on top of lightws. Intro Client side receives tcp then sends [tcp/ws/tls/wss]. Server side receives [tcp

zephyr 261 Dec 27, 2022
Lightweight websocket implement for stream transmission.

Lightws Lightweight websocket implement for stream transmission. Features Avoid heap allocation. Avoid buffering frame payload. Use vectored-io if ava

zephyr 25 Dec 27, 2022
websocket client

#websocket client async fn test_websocket()->anyhow::Result<()> { wasm_logger::init(wasm_logger::Config::default()); let (tx, rx) = futures_c

null 1 Feb 11, 2022
A webserver and websocket pair to stop your viewers from spamming !np and "what's the song?" all the time.

spotify-np ?? spotify-np is a Rust-based local webserver inspired by l3lackShark's gosumemory application, but the catch is that it's for Spotify! ??

Noire 2 Aug 27, 2022
WebSocket-to-HTTP reverse proxy

websocket-bridge This is a simple reverse proxy server which accepts WebSocket connections and forwards any incoming frames to backend HTTP server(s)

Fermyon 5 Dec 21, 2022
A secure, real-time, low-latency binary WebSocket RPC subprotocol.

HardLight A secure, real-time, low-latency binary WebSocket RPC subprotocol. HardLight has two data models: RPC: a client connects to a server, and ca

valera 5 Apr 2, 2023
Rust API connector for Bybit's WebSockets APIs.

rust-bybit English | 简体中文 Unofficial Rust API connector for Bybit's WebSockets APIs. Disclaimer This is an unofficial Rust API connector for Bybit's A

yufuquant 12 Nov 12, 2022
A command-line tool for exposing a wrapped program's standard IO using WebSockets/SSE

cmdpiped cmdpiped is a command-line tool for exposing a wrapped cli program's standard IO to WebSockets/SSE Installation Ready to use Binaries are ava

Geoffrey Mureithi 10 Nov 11, 2022
Easy c̵̰͠r̵̛̠ö̴̪s̶̩̒s̵̭̀-t̶̲͝h̶̯̚r̵̺͐e̷̖̽ḁ̴̍d̶̖̔ ȓ̵͙ė̶͎ḟ̴͙e̸̖͛r̶̖͗ë̶̱́ṉ̵̒ĉ̷̥e̷͚̍ s̷̹͌h̷̲̉a̵̭͋r̷̫̊ḭ̵̊n̷̬͂g̵̦̃ f̶̻̊ơ̵̜ṟ̸̈́ R̵̞̋ù̵̺s̷̖̅ţ̸͗!̸̼͋

Rust S̵̓i̸̓n̵̉ I̴n̴f̶e̸r̵n̷a̴l mutability! Howdy, friendly Rust developer! Ever had a value get m̵̯̅ð̶͊v̴̮̾ê̴̼͘d away right under your nose just when

null 294 Dec 23, 2022
Utilities and tools based around Amazon S3 to provide convenience APIs in a CLI

s3-utils Utilities and tools based around Amazon S3 to provide convenience APIs in a CLI. This tool contains a small set of command line utilities for

Isaac Whitfield 47 Dec 15, 2022
Prototype for a CLI/Libary designed for interacting with NASA Open APIs with Rust.

Overview Voyager is a swiss army knife library for the NASA Open APIs. It is designed to bundle all the NASA APIs into a single package. Voyager can b

Ethan Gallucci 4 Aug 14, 2022
REC2 (Rusty External Command and Control) is client and server tool allowing auditor to execute command from VirusTotal and Mastodon APIs written in Rust. 🦀

Information: REC2 is an old personal project (early 2023) that I didn't continue development on. It's part of a list of projects that helped me to lea

Quentin Texier (g0h4n) 104 Oct 7, 2023