wscall 0.1.1

Facade crate for the WSCALL protocol, server, and client
Documentation

wscall

WSCALL is a lightweight WebSocket API framework with a custom binary frame protocol, a reusable Rust server crate, a reusable Rust client crate, and a facade crate for consumers that prefer a single dependency.

Workspace Layout

The repository is now organized as a Cargo workspace:

crates/
	wscall-protocol/
	wscall-server/
	wscall-client/
	wscall/

Each crate has a clear responsibility:

  1. wscall-protocol: shared frame codec, envelope types, file attachment model, and protocol errors.
  2. wscall-server: reusable WebSocket server framework with routes, filters, validation, exception mapping, and server push events.
  3. wscall-client: reusable client SDK with request correlation, event ACK correlation, and server event subscriptions.
  4. wscall: facade crate that re-exports protocol plus optional server and client APIs behind features.

Protocol Summary

Each WebSocket binary message is encoded as:

| frame_len:u32 | message_type:u8 | encryption:u8 | payload |

Transport behavior:

  1. Plaintext mode stores JSON directly in payload.
  2. ChaCha20 and AES256 modes store 12-byte nonce + ciphertext in payload.
  3. The payload limit is 10 * 1024 * 1024 - 6, which keeps the full WSCALL frame within 10 MiB.
  4. File parameters use JSON references plus inline Base64 attachments.

Use As Crates

Depend on only what you need:

[dependencies]
wscall-server = "0.1.1"
wscall-client = "0.1.1"

Or use the facade crate:

[dependencies]
wscall = { version = "0.1.1", features = ["full"] }

Quick Start

Minimal server:

use serde_json::json;
use wscall::WscallServer;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
	let mut server = WscallServer::new();

	server.route("system.echo", |ctx| async move {
		Ok(json!({
			"route": ctx.route(),
			"params": ctx.params(),
		}))
	});

	server.listen("127.0.0.1:9001").await?;
	Ok(())
}

Minimal client:

use serde_json::json;
use wscall::WscallClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
	let client = WscallClient::connect("ws://127.0.0.1:9001/socket").await?;
	client
		.on_connected(|event| async move {
			println!("connected: {}", event.url);
		})
		.await;
	client
		.on_disconnected(|event| async move {
			println!("disconnected: {}", event.reason);
		})
		.await;
	let response = client
		.call("system.echo", json!({ "message": "hello" }), Vec::new())
		.await?;

	println!("response: {response}");
	client.close().await?;
	Ok(())
}

Client reconnect behavior:

  1. Unexpected disconnects trigger automatic reconnect attempts.
  2. The first retry waits 3 seconds.
  3. Each later retry increases the delay by 1 second.
  4. The retry delay is capped at 30 seconds.
  5. Calling close() stops reconnect attempts.

Runnable end-to-end quick start:

cargo run -p wscall --example quick_start --features full

Run The Demos

Start the demo server:

cargo run -p wscall --example demo_server --features server

In another terminal, run the demo client:

cargo run -p wscall --example demo_client --features client

The demos exercise:

  1. system.echo API.
  2. files.inspect API with inline attachment.
  3. chat.message event emit and broadcast.
  4. chat.history API query.
  5. End-to-end ChaCha20 frame encryption using the demo key wired in both examples.

Quality Gates

Recommended checks before publishing or merging:

cargo fmt --all --check
cargo clippy --workspace --all-features --all-targets -- -D warnings
cargo test --workspace --all-features

Publishing Checklist

Before publishing the crates to crates.io:

  1. Confirm the configured repository and homepage metadata still match the canonical repository.
  2. Run the quality gates locally.
  3. Update all workspace crate versions and internal dependency pins to the target release version.
  4. Run cargo package for wscall-protocol to validate the root dependency crate.
  5. Publish in dependency order: wscall-protocol, wscall-server, wscall-client, then wscall.
  6. After each publish, wait for the crates.io index to catch up before packaging or publishing the next dependent crate.

For any release that introduces a new unpublished dependency version, downstream crates such as wscall-server, wscall-client, and wscall must still be published in dependency order so crates.io can resolve the freshly published versions.

See RELEASE.md for a release sequence that matches this dependency chain.

Version history is tracked in CHANGELOG.md.

Current Constraints

  1. ChaCha20 and AES256-GCM are implemented in FrameCodec; the demos still default to ChaCha20.
  2. Attachments are inline Base64 and suited to small files.
  3. Large-file chunking is not part of the current core protocol.
  4. The published crate and code identifiers have been renamed to wscall.