• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1.. _module-pw_rpc-ts:
2
3-----------------
4pw_rpc web module
5-----------------
6.. pigweed-module-subpage::
7   :name: pw_rpc
8
9The ``pw_rpc`` module makes it possible to call Pigweed RPCs from
10TypeScript or JavaScript. The module includes client library to facilitate handling RPCs.
11
12This module is currently a work in progress.
13
14Creating an RPC Client
15======================
16The RPC client is instantiated from a list of channels and a set of protos.
17
18.. code-block:: typescript
19
20   import { ProtoCollection } from 'pigweedjs/protos/collection';
21
22   const channels = [new Channel(1, savePacket), new Channel(5)];
23   const client = Client.fromProtoSet(channels, new ProtoCollection());
24
25   function savePacket(packetBytes: Uint8Array): void {
26     const packet = RpcPacket.deserializeBinary(packetBytes);
27     ...
28   }
29
30To generate a ProtoSet/ProtoCollection from your own ``.proto`` files, use
31``pw_proto_compiler`` in your ``package.json`` like this:
32
33.. code-block:: javascript
34
35   ...
36   "scripts": {
37     "build-protos": "pw_proto_compiler -p protos/rpc1.proto -p protos/rpc2.proto --out dist/protos",
38
39This will generate a `collection.js` file which can be used similar to above
40example.
41
42Finding an RPC Method
43=====================
44Once the client is instantiated with the correct proto library, the target RPC
45method is found by searching based on the full name:
46``{packageName}.{serviceName}.{methodName}``
47
48.. code-block:: typescript
49
50   const channel = client.channel()!;
51   unaryStub = channel.methodStub('pw.rpc.test1.TheTestService.SomeUnary')!
52       as UnaryMethodStub;
53
54The four possible RPC stubs are ``UnaryMethodStub``,
55``ServerStreamingMethodStub``, ``ClientStreamingMethodStub``, and
56``BidirectionalStreamingMethodStub``.  Note that ``channel.methodStub()``
57returns a general stub. Since each stub type has different invoke
58parameters, the general stub should be typecast before using.
59
60Invoke an RPC with callbacks
61============================
62
63.. code-block:: typescript
64
65   invoke(request?: Message,
66       onNext: Callback = () => {},
67       onCompleted: Callback = () => {},
68       onError: Callback = () => {}): Call
69
70All RPC methods can be invoked with a set of callbacks that are triggered when
71either a response is received, the RPC is completed, or an error occurs. The
72example below demonstrates registering these callbacks on a Bidirectional RPC.
73Other RPC types can be invoked in a similar fashion. The request parameter may
74differ slightly between RPC types.
75
76.. code-block:: typescript
77
78   bidiRpc = client.channel()?.methodStub(
79       'pw.rpc.test1.TheTestService.SomeBidi')!
80       as BidirectionalStreamingMethodStub;
81
82   // Configure callback functions
83   const onNext = (response: Message) => {
84     console.log(response);
85   }
86   const onComplete = (status: Status) => {
87     console.log('completed!');
88   }
89   const onError = (error: Error) => {
90     console.log();
91   }
92
93   bidiRpc.invoke(request, onNext, onComplete, onError);
94
95Open an RPC: ignore initial errors
96=====================================
97
98Open allows you to start and register an RPC without crashing on errors. This
99is useful for starting an RPC before the server is ready. For instance, starting
100a logging RPC while the device is booting.
101
102.. code-block:: typescript
103
104   open(request?: Message,
105       onNext: Callback = () => {},
106       onCompleted: Callback = () => {},
107       onError: Callback = () => {}): Call
108
109Blocking RPCs: promise API
110==========================
111
112Each MethodStub type provides an call() function that allows sending requests
113and awaiting responses through the promise API. The timeout field is optional.
114If no timeout is specified, the RPC will wait indefinitely.
115
116Unary RPC
117---------
118.. code-block:: typescript
119
120   unaryRpc = client.channel()?.methodStub(
121       'pw.rpc.test1.TheTestService.SomeUnary')!
122       as UnaryMethodStub;
123   const request = new unaryRpc.requestType();
124   request.setFooProperty(4);
125   const timeout = 2000 // 2 seconds
126   const [status, response] = await unaryRpc.call(request, timeout);
127
128Server Streaming RPC
129--------------------
130.. code-block:: typescript
131
132   serverStreamRpc = client.channel()?.methodStub(
133       'pw.rpc.test1.TheTestService.SomeServerStreaming')!
134       as ServerStreamingMethodStub;
135
136   const call = serverStreamRpc.invoke();
137   const timeout = 2000
138   for await (const response of call.getResponses(2, timeout)) {
139    console.log(response);
140   }
141   const responses = call.getResponse() // All responses until stream end.
142   while (!responses.done) {
143     console.log(await responses.value());
144   }
145
146
147Client Streaming RPC
148--------------------
149.. code-block:: typescript
150
151   clientStreamRpc = client.channel()!.methodStub(
152     'pw.rpc.test1.TheTestService.SomeClientStreaming')!
153     as ClientStreamingMethodStub;
154   clientStreamRpc.invoke();
155   const request = new clientStreamRpc.method.requestType();
156   request.setFooProperty('foo_test');
157   clientStreamRpc.send(request);
158
159   // Send three more requests, end the stream, and wait for a response.
160   const timeout = 2000 // 2 seconds
161   request.finishAndWait([request, request, request], timeout)
162       .then(() => {
163         console.log('Client stream finished successfully');
164       })
165       .catch((reason) => {
166         console.log(`Client stream error: ${reason}`);
167       });
168
169Bidirectional Stream RPC
170------------------------
171.. code-block:: typescript
172
173   bidiStreamingRpc = client.channel()!.methodStub(
174     'pw.rpc.test1.TheTestService.SomeBidiStreaming')!
175     as BidirectionalStreamingMethodStub;
176   bidiStreamingRpc.invoke();
177   const request = new bidiStreamingRpc.method.requestType();
178   request.setFooProperty('foo_test');
179
180   // Send requests
181   bidiStreamingRpc.send(request);
182
183   // Receive responses
184   const timeout = 2000 // 2 seconds
185   for await (const response of call.getResponses(1, timeout)) {
186    console.log(response);
187   }
188
189   // Send three more requests, end the stream, and wait for a response.
190   request.finishAndWait([request, request, request], timeout)
191       .then(() => {
192         console.log('Bidirectional stream finished successfully');
193       })
194       .catch((reason) => {
195         console.log(`Bidirectional stream error: ${reason}`);
196       });
197