#rpc #browser #client-server #wasm #async-client #web-apps

workflow-rpc

Workflow RPC (wRPC) framework based on the workflow-websocket crate offering native & in-browser (WASM32) clients and a native server (based on tokio & tungstenite). wRPC supports custom Borsh and JSON protocols with use of generics for RPC method declarations.

27 releases (9 breaking)

0.11.0 Feb 25, 2024
0.10.2 Dec 24, 2023
0.8.1 Nov 1, 2023
0.3.17 May 28, 2023
0.1.2 Sep 21, 2022

#39 in WebSocket

Download history 105/week @ 2023-12-04 203/week @ 2023-12-11 273/week @ 2023-12-18 455/week @ 2023-12-25 366/week @ 2024-01-01 202/week @ 2024-01-08 277/week @ 2024-01-15 466/week @ 2024-01-22 80/week @ 2024-01-29 88/week @ 2024-02-05 158/week @ 2024-02-12 198/week @ 2024-02-19 227/week @ 2024-02-26 68/week @ 2024-03-04 153/week @ 2024-03-11 87/week @ 2024-03-18

644 downloads per month
Used in 16 crates (6 directly)

MIT/Apache

360KB
7.5K SLoC

workflow-rpc (wRPC)

Part of the workflow-rs application framework.


github crates.io docs.rs license

RPC functionality built on top of the workflow-websocket crate offering asynchronous data relay over WebSocket connections supporting a custom high-performance Borsh and an extended JSON-RPC protocols.

Features

  • High-performance Borsh message encoding protocol
  • RPC method and notification handler declarations based on serializable generics
  • Client to Server RPC method invocation
  • Client to Server notification messages
  • Server to Client notification messages
  • Server-side handshake scaffolding for custom connection negotiation
  • Easy to retain connection data structure for posting async client notifications

This crate provides a high performance, Rust-focused, communication layer. The remote function invocation is done via a single function with two generics rpc.call<Request,Response>().await? where the request and response data types must implement serlialization using both Borsh and Serde JSON serialization and deserialization traits.

The data is transmitted via WebSocket binary message frames for Borsh encoding and via text frames for JSON encoding.

Borsh Protocol

Due to use of generics for id and op (method) types, Borsh header messages can vary in size and it is the responsibility of the developer to ensure consistency between client and server. Protocol versioning can be negotiated using a handshake during the connection opening phase.

The following format is used by the Borsh Protocol: Request: [Option,Option,Payload]

  • id: Id: a generic user-defined type, typically u32 or u64-based type (Option:None if the message is a notification).
  • op: Ops: a generic user-defined type, typically an enum representing the operation.
  • payload: Payload: Any data type that implements BorshSerialize, BorshDeserialize, Serialize and Deserialize traits. Response: [Option,Kind,Option,Payload]
  • id: Id: a generic user-defined type (Option:None if the message is a notification)
  • kind: Kind: a byte representing message type: 0x01: Success, 0x02: Error, 0xff: Notification
  • ops: Ops: a generic user-defined type, typically an enum representing the operation.
  • payload: Payload: serialized data containing Result<UserType,ServerError>

NOTE: Borsh provides high-performance serialization and deserialization, however, the change in the data structure formats transported across RPC can result in the protocol mismatch between server and client. When using Borsh it is your responsibility to build both server and client from the same codebase.

To provide version resolution, data structures can be encapsulated into enums as follows:

enum MyEnum {
    V1(DataStructureV1),
    V2(DataStructureV2),
    ...
}

wRPC JSON Protocol

JSON protocol uses Serde (serde-json) serialization.

JSON message format extends on top of JSON-RPC protocol as follows: Client-side message:

  • id: optional, absent if the message is a notification
  • method: RPC method or notification name
  • params: message data Server-side message:
  • id: optional, absent if message is a notification
  • method: RPC method or notification name
  • params: message (response or notification) data
  • error: error data if the RPC method produced an error error data field contains:
  • code: error code (as of v0.3.0 always 0x00)
  • message: error message string
  • data: additional error data (as of v0.3.0 always absent`) Differences between JSON-RPC and JSON-wRPC:
  • JSON-RPC response returns result property in the response. wRPC returns params property in case of both response and notification.
  • JSON-RPC 2.0 specification does not support server-side (server-to-client) notification.
  • JSON-RPC 2.0 contains a json-rpc="2.0" property in every message. This is redundant for wRPC - wRPC handshake can be used to describe protocol version.

Node.js compatibility

NOTE: workflow-rpc is built on top of the workflow-websocket crate. To use workflow-rpc in the Node.js environment, you need to introduce a W3C WebSocket object before loading the WASM32 library to simulate the global WebSocket object available in Web Browsers. The WebSocket NPM module provides W3C WebSocket compatible implementation and can be used as follows:

// WebSocket
globalThis.WebSocket = require('websocket').w3cwebsocket;
// Load WASM32 library ...

Dependencies

~19–36MB
~563K SLoC