pw_rpc Web Module#
Pigweed AI summary: The pw_rpc module allows Pigweed RPCs to be called from TypeScript or JavaScript, and includes a client library to handle RPCs. The RPC client is instantiated from a list of channels and a set of protos, and the target RPC method is found by searching based on the full name. All RPC methods can be invoked with a set of callbacks that are triggered when a response is received, the RPC is completed, or an error occurs. The open function allows starting and registering an RPC without crashing
The pw_rpc
module makes it possible to call Pigweed RPCs from
TypeScript or JavaScript. The module includes client library to facilitate handling RPCs.
This module is currently a work in progress.
Creating an RPC Client#
Pigweed AI summary: This section explains how to create an RPC client using a list of channels and a set of protos. The code example shows how to import the necessary modules and instantiate the client. To generate a ProtoSet/ProtoCollection from your own .proto files, you can use pw_proto_compiler in your package.json file. This will generate a collection.js file that can be used similarly to the example provided.
The RPC client is instantiated from a list of channels and a set of protos.
import { ProtoCollection } from 'pigweedjs/protos/collection';
const channels = [new Channel(1, savePacket), new Channel(5)];
const client = Client.fromProtoSet(channels, new ProtoCollection());
function savePacket(packetBytes: Uint8Array): void {
const packet = RpcPacket.deserializeBinary(packetBytes);
...
}
To generate a ProtoSet/ProtoCollection from your own .proto
files, use
pw_proto_compiler
in your package.json
like this:
...
"scripts": {
"build-protos": "pw_proto_compiler -p protos/rpc1.proto -p protos/rpc2.proto --out dist/protos",
This will generate a collection.js file which can be used similar to above example.
Finding an RPC Method#
Pigweed AI summary: To find the target RPC method, the client must be instantiated with the correct proto library and searched based on the full name. The four possible RPC stubs are UnaryMethodStub, ServerStreamingMethodStub, ClientStreamingMethodStub, and BidirectionalStreamingMethodStub. The general stub returned by channel.methodStub() should be typecast before using, as each stub type has different invoke parameters.
Once the client is instantiated with the correct proto library, the target RPC
method is found by searching based on the full name:
{packageName}.{serviceName}.{methodName}
const channel = client.channel()!;
unaryStub = channel.methodStub('pw.rpc.test1.TheTestService.SomeUnary')!
as UnaryMethodStub;
The four possible RPC stubs are UnaryMethodStub
,
ServerStreamingMethodStub
, ClientStreamingMethodStub
, and
BidirectionalStreamingMethodStub
. Note that channel.methodStub()
returns a general stub. Since each stub type has different invoke
parameters, the general stub should be typecast before using.
Invoke an RPC with callbacks#
Pigweed AI summary: This section explains how to invoke an RPC method with callbacks that are triggered when a response is received, the RPC is completed, or an error occurs. The example provided demonstrates how to register these callbacks on a Bidirectional RPC, and similar methods can be invoked in a similar fashion. The code snippet shows how to configure callback functions and invoke the Bidirectional RPC with the callbacks.
invoke(request?: Message,
onNext: Callback = () => {},
onCompleted: Callback = () => {},
onError: Callback = () => {}): Call
All RPC methods can be invoked with a set of callbacks that are triggered when either a response is received, the RPC is completed, or an error occurs. The example below demonstrates registering these callbacks on a Bidirectional RPC. Other RPC types can be invoked in a similar fashion. The request parameter may differ slightly between RPC types.
bidiRpc = client.channel()?.methodStub(
'pw.rpc.test1.TheTestService.SomeBidi')!
as BidirectionalStreamingMethodStub;
// Configure callback functions
const onNext = (response: Message) => {
console.log(response);
}
const onComplete = (status: Status) => {
console.log('completed!');
}
const onError = (error: Error) => {
console.log();
}
bidiRpc.invoke(request, onNext, onComplete, onError);
Open an RPC: ignore initial errors#
Pigweed AI summary: The "Open" function allows for the starting and registering of an RPC without crashing on errors, which is useful for starting an RPC before the server is ready, such as a logging RPC during device booting. The function takes in a message request and callbacks for onNext, onCompleted, and onError.
Open allows you to start and register an RPC without crashing on errors. This is useful for starting an RPC before the server is ready. For instance, starting a logging RPC while the device is booting.
open(request?: Message,
onNext: Callback = () => {},
onCompleted: Callback = () => {},
onError: Callback = () => {}): Call
Blocking RPCs: promise API#
Pigweed AI summary: The article discusses different types of RPCs (Remote Procedure Calls) and their implementation using the promise API. Each MethodStub type provides a call() function for sending requests and awaiting responses, with an optional timeout field. The article covers four types of RPCs: Unary, Server Streaming, Client Streaming, and Bidirectional Streaming, with code examples for each type.
Each MethodStub type provides an call() function that allows sending requests and awaiting responses through the promise API. The timeout field is optional. If no timeout is specified, the RPC will wait indefinitely.
Unary RPC#
Pigweed AI summary: This paragraph describes a code snippet in TypeScript that implements a unary RPC (Remote Procedure Call) using a client channel and a method stub. The code sets a request property, specifies a timeout, and calls the unary RPC with the request and timeout parameters. The response and status are then returned.
unaryRpc = client.channel()?.methodStub(
'pw.rpc.test1.TheTestService.SomeUnary')!
as UnaryMethodStub;
const request = new unaryRpc.requestType();
request.setFooProperty(4);
const timeout = 2000 // 2 seconds
const [status, response] = await unaryRpc.call(request, timeout);
Server Streaming RPC#
Pigweed AI summary: This paragraph describes a code snippet for implementing server streaming RPC in TypeScript. It includes defining a serverStreamRpc method, invoking it, setting a timeout, and logging responses.
serverStreamRpc = client.channel()?.methodStub(
'pw.rpc.test1.TheTestService.SomeServerStreaming')!
as ServerStreamingMethodStub;
const call = serverStreamRpc.invoke();
const timeout = 2000
for await (const response of call.getResponses(2, timeout)) {
console.log(response);
}
const responses = call.getResponse() // All responses until stream end.
while (!responses.done) {
console.log(await responses.value());
}
Client Streaming RPC#
Pigweed AI summary: This paragraph describes a code snippet for implementing client streaming RPC in TypeScript. The code creates a client stream and sends multiple requests, ending the stream and waiting for a response. If successful, the console will log that the client stream finished successfully, otherwise it will log an error message.
clientStreamRpc = client.channel()!.methodStub(
'pw.rpc.test1.TheTestService.SomeClientStreaming')!
as ClientStreamingMethodStub;
clientStreamRpc.invoke();
const request = new clientStreamRpc.method.requestType();
request.setFooProperty('foo_test');
clientStreamRpc.send(request);
// Send three more requests, end the stream, and wait for a response.
const timeout = 2000 // 2 seconds
request.finishAndWait([request, request, request], timeout)
.then(() => {
console.log('Client stream finished successfully');
})
.catch((reason) => {
console.log(`Client stream error: ${reason}`);
});
Bidirectional Stream RPC#
Pigweed AI summary: This paragraph describes how to use Bidirectional Stream RPC in TypeScript, including how to set up the method stub, send requests, receive responses, and end the stream. It also includes a timeout and error handling.
bidiStreamingRpc = client.channel()!.methodStub(
'pw.rpc.test1.TheTestService.SomeBidiStreaming')!
as BidirectionalStreamingMethodStub;
bidiStreamingRpc.invoke();
const request = new bidiStreamingRpc.method.requestType();
request.setFooProperty('foo_test');
// Send requests
bidiStreamingRpc.send(request);
// Receive responses
const timeout = 2000 // 2 seconds
for await (const response of call.getResponses(1, timeout)) {
console.log(response);
}
// Send three more requests, end the stream, and wait for a response.
request.finishAndWait([request, request, request], timeout)
.then(() => {
console.log('Bidirectional stream finished successfully');
})
.catch((reason) => {
console.log(`Bidirectional stream error: ${reason}`);
});