40 releases (15 breaking)
0.18.0 | Sep 7, 2024 |
---|---|
0.15.0 | Jul 26, 2024 |
0.11.0 | Feb 25, 2024 |
0.10.2 | Dec 24, 2023 |
0.1.2 | Sep 21, 2022 |
#40 in WebSocket
2,006 downloads per month
Used in 16 crates
(7 directly)
455KB
10K
SLoC
workflow-rpc
(wRPC)
Part of the workflow-rs
application framework.
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 anenum
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
: Notificationops: Ops
: a generic user-defined type, typically anenum
representing the operation.payload: Payload
: serialized data containingResult<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 notificationmethod
: RPC method or notification nameparams
: message data Server-side message:id
: optional, absent if message is a notificationmethod
: RPC method or notification nameparams
: message (response or notification) dataerror
: error data if the RPC method produced an errorerror
data field contains:code
: error code (as of v0.3.0 always0x00
)message
: error message stringdata
: 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 returnsparams
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–35MB
~570K SLoC