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