Alexei Frolov | 26e3ae6 | 2020-05-04 17:06:17 -0700 | [diff] [blame] | 1 | .. default-domain:: cpp |
| 2 | |
| 3 | .. highlight:: sh |
| 4 | |
| 5 | .. _chapter-pw-rpc: |
| 6 | |
| 7 | ------ |
| 8 | pw_rpc |
| 9 | ------ |
| 10 | The ``pw_rpc`` module provides a system for defining and invoking remote |
| 11 | procedure calls (RPCs) on a device. |
| 12 | |
| 13 | .. note:: |
| 14 | |
| 15 | Under construction. |
Wyatt Hepler | 948f547 | 2020-06-02 16:52:28 -0700 | [diff] [blame] | 16 | |
| 17 | RPC server |
| 18 | ========== |
| 19 | Declare an instance of ``rpc::Server`` and register services with it. |
| 20 | |
| 21 | .. admonition:: TODO |
| 22 | |
| 23 | Document the public interface |
| 24 | |
| 25 | RPC server implementation |
| 26 | ------------------------- |
| 27 | |
| 28 | The Method class |
| 29 | ^^^^^^^^^^^^^^^^ |
| 30 | The RPC Server depends on the ``pw::rpc::internal::Method`` class. ``Method`` |
| 31 | serves as the bridge between the ``pw_rpc`` server library and the user-defined |
| 32 | RPC functions. ``Method`` takes an RPC packet, decodes it using a protobuf |
| 33 | library (if applicable), and calls the RPC function. Since ``Method`` interacts |
| 34 | directly with the protobuf library, it must be implemented separately for each |
| 35 | protobuf library. |
| 36 | |
| 37 | ``pw::rpc::internal::Method`` is not implemented as a facade with different |
| 38 | backends. Instead, there is a separate instance of the ``pw_rpc`` server library |
| 39 | for each ``Method`` implementation. There are a few reasons for this. |
| 40 | |
| 41 | * ``Method`` is entirely internal to ``pw_rpc``. Users will never implement a |
| 42 | custom backend. Exposing a facade would unnecessarily expose implementation |
| 43 | details and make ``pw_rpc`` more difficult to use. |
| 44 | * There is no common interface between ``pw_rpc`` / ``Method`` implementations. |
| 45 | It's not possible to swap between e.g. a Nanopb and a ``pw_protobuf`` RPC |
| 46 | server because the interface for the user-implemented RPCs changes completely. |
| 47 | This nullifies the primary benefit of facades. |
| 48 | * The different ``Method`` implementations can be built easily alongside one |
| 49 | another in a cross-platform way. This makes testing simpler, since the tests |
| 50 | build with any backend configuration. Users can select which ``Method`` |
| 51 | implementation to use simply by depending on the corresponding server library. |
| 52 | |
| 53 | Packet flow |
| 54 | ^^^^^^^^^^^ |
| 55 | |
| 56 | Requests |
| 57 | ~~~~~~~~ |
| 58 | |
| 59 | .. blockdiag:: |
| 60 | |
| 61 | blockdiag { |
| 62 | packets [shape = beginpoint]; |
| 63 | |
| 64 | group { |
| 65 | label = "pw_rpc library" |
| 66 | |
| 67 | server [label = "Server"]; |
| 68 | service [label = "internal::Service"]; |
| 69 | method [label = "internal::Method"]; |
| 70 | } |
| 71 | |
| 72 | stubs [label = "generated services", shape = ellipse]; |
| 73 | user [label = "user-defined RPCs", shape = roundedbox]; |
| 74 | |
| 75 | packets -> server -> service -> method -> stubs -> user; |
| 76 | packets -> server [folded]; |
| 77 | method -> stubs [folded]; |
| 78 | } |
| 79 | |
| 80 | Responses |
| 81 | ~~~~~~~~~ |
| 82 | |
| 83 | .. blockdiag:: |
| 84 | |
| 85 | blockdiag { |
| 86 | user -> stubs [folded]; |
| 87 | |
| 88 | group { |
| 89 | label = "pw_rpc library" |
| 90 | |
| 91 | server [label = "Server"]; |
| 92 | method [label = "internal::Method"]; |
| 93 | channel [label = "Channel"]; |
| 94 | } |
| 95 | |
| 96 | stubs [label = "generated services", shape = ellipse]; |
| 97 | user [label = "user-defined RPCs", shape = roundedbox]; |
| 98 | packets [shape = beginpoint]; |
| 99 | |
| 100 | user -> stubs -> method [folded]; |
| 101 | method -> server -> channel; |
| 102 | channel -> packets [folded]; |
| 103 | } |