194 lines
6.0 KiB
ReStructuredText
194 lines
6.0 KiB
ReStructuredText
.. _module-pw_rpc-ts:
|
|
|
|
-------------------------
|
|
pw_rpc Web Module
|
|
-------------------------
|
|
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
|
|
======================
|
|
The RPC client is instantiated from a list of channels and a set of protos.
|
|
|
|
.. code-block:: typescript
|
|
|
|
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:
|
|
|
|
.. code-block:: javascript
|
|
|
|
...
|
|
"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
|
|
=====================
|
|
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}``
|
|
|
|
.. code-block:: typescript
|
|
|
|
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
|
|
============================
|
|
|
|
.. code-block:: typescript
|
|
|
|
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.
|
|
|
|
.. code-block:: typescript
|
|
|
|
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
|
|
=====================================
|
|
|
|
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.
|
|
|
|
.. code-block:: typescript
|
|
|
|
open(request?: Message,
|
|
onNext: Callback = () => {},
|
|
onCompleted: Callback = () => {},
|
|
onError: Callback = () => {}): Call
|
|
|
|
Blocking RPCs: promise API
|
|
==========================
|
|
|
|
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
|
|
---------
|
|
.. code-block:: typescript
|
|
|
|
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
|
|
--------------------
|
|
.. code-block:: typescript
|
|
|
|
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
|
|
--------------------
|
|
.. code-block:: typescript
|
|
|
|
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
|
|
------------------------
|
|
.. code-block:: typescript
|
|
|
|
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}`);
|
|
});
|