blob: 3d2459637fa8b32864dd5b66af0b6b40db653dfc [file] [log] [blame]
.. _module-pw_rpc-ts:
-------------------------
pw_rpc Typescript package
-------------------------
The ``pw_rpc`` Typescript package makes it possible to call Pigweed RPCs from
Typescript. The package includes client library to facilitate handling RPCs.
This package 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
const testProtoPath = 'pw_rpc/ts/test_protos-descriptor-set.proto.bin';
const lib = await Library.fromFileDescriptorSet(
testProtoPath, 'test_protos_tspb');
const channels = [new Channel(1, savePacket), new Channel(5)];
const client = Client.fromProtoSet(channels, lib);
function savePacket(packetBytes: Uint8Array): void {
const packet = RpcPacket.deserializeBinary(packetBytes);
...
}
The proto library must match the proto build rules. The first argument
corresponds with the location of the ``proto_library`` build rule that generates
a descriptor set for all src protos. The second argument corresponds with the
name of the ``js_proto_library`` build rule that generates javascript based on
the descriptor set. For instance, the previous example corresponds with the
following build file: ``pw_rpc/ts/BUILD.bazel``.
.. code-block::
proto_library(
name = "test_protos",
srcs = [
"test.proto",
"test2.proto",
],
)
js_proto_library(
name = "test_protos_tspb",
protos = [":test_protos"],
)
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
==========================
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 [status, response] = await unaryRpc.call(request);
Server Streaming RPC
--------------------
.. code-block:: typescript
serverStreamRpc = client.channel()?.methodStub(
'pw.rpc.test1.TheTestService.SomeServerStreaming')!
as ServerStreamingMethodStub;
const call = serverStreamRpc.invoke();
for await (const response of call.getResponses(2)) {
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.
request.finishAndWait([request, request, request])
.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
for await (const response of call.getResponses(1)) {
console.log(response);
}
// Send three more requests, end the stream, and wait for a response.
request.finishAndWait([request, request, request])
.then(() => {
console.log('Bidirectional stream finished successfully');
})
.catch((reason) => {
console.log(`Bidirectional stream error: ${reason}`);
});
.. attention::
RPC timeout is currently unsupported on all RPC types.