aboutsummaryrefslogtreecommitdiff
path: root/pw_rpc/ts/docs.rst
blob: 7d7a2c7c0687f67f0cf835a6cee3fc26ce7a19b5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
.. _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}`);
      });